UEFIPatch 0.2.0 / UEFITool 0.18.0

- updated EFI11/Tiano compression and decompression code to UDK2014
versions
- UEFIPatch rewritten to support offset-based patches and patterns with
placeholder symbols
This commit is contained in:
Nikolaj Schlej 2014-07-05 14:56:56 +02:00
parent a3854ad059
commit c23aef47be
11 changed files with 2227 additions and 2429 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,14 @@
/* EFI/Tiano Compress Header /* EfiTianoCompress.h
Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved. Copyright (c) 2014, Nikolaj Schlej. All rights reserved.<BR>
Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: Module Name:
@ -54,12 +55,12 @@ Returns:
EFI_INVALID_PARAMETER - Parameter supplied is wrong. EFI_INVALID_PARAMETER - Parameter supplied is wrong.
--*/ --*/
INT32 UINT8
TianoCompress ( TianoCompress (
UINT8 *SrcBuffer, CONST VOID *SrcBuffer,
UINT32 SrcSize, CONST UINT64 SrcSize,
UINT8 *DstBuffer, VOID *DstBuffer,
UINT32 *DstSize UINT64 *DstSize
) )
; ;
@ -86,12 +87,12 @@ Returns:
EFI_INVALID_PARAMETER - Parameter supplied is wrong. EFI_INVALID_PARAMETER - Parameter supplied is wrong.
--*/ --*/
INT32 UINT8
EfiCompress ( EfiCompress (
UINT8 *SrcBuffer, CONST VOID *SrcBuffer,
UINT32 SrcSize, CONST UINT64 SrcSize,
UINT8 *DstBuffer, VOID *DstBuffer,
UINT32 *DstSize UINT64 *DstSize
) )
; ;

View File

@ -1,6 +1,7 @@
/*++ /*++ EfiTianoDecompress.c
Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR> Copyright (c) 2014, Nikolaj Schlej. All rights reserved.<BR>
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -28,7 +29,9 @@ Decompressor. Algorithm Ported from OPSD code (Decomp.asm)
#define MAXMATCH 256 #define MAXMATCH 256
#define THRESHOLD 3 #define THRESHOLD 3
#define CODE_BIT 16 #define CODE_BIT 16
//#define UINT8_MAX 0xff #ifndef UINT8_MAX
#define UINT8_MAX 0xff
#endif
#define BAD_TABLE - 1 #define BAD_TABLE - 1
// //
@ -69,7 +72,7 @@ UINT16 mCTable[4096];
UINT16 mPTTable[256]; UINT16 mPTTable[256];
// //
// The length of the field 'Position Set Code Length Array Size'Block Header. // The length of the field 'Position Set Code Length Array Size' in Block Header.
// For EFI 1.1 de/compression algorithm, mPBit = 4 // For EFI 1.1 de/compression algorithm, mPBit = 4
// For Tiano de/compression algorithm, mPBit = 5 // For Tiano de/compression algorithm, mPBit = 5
// //
@ -79,14 +82,14 @@ UINT8 mPBit;
STATIC STATIC
VOID VOID
FillBuf( FillBuf(
SCRATCH_DATA *Sd, IN SCRATCH_DATA *Sd,
UINT16 NumOfBits IN UINT16 NumOfBits
) )
/*++ /*++
Routine Description: Routine Description:
Shift mBitBuf NumOfBits left. ReadNumOfBits of bits from source. Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source.
Arguments: Arguments:
@ -112,7 +115,8 @@ while (NumOfBits > Sd->mBitCount) {
Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++]; Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++];
Sd->mBitCount = 8; Sd->mBitCount = 8;
} else { }
else {
// //
// No more bits from the source, just pad zero bit. // No more bits from the source, just pad zero bit.
// //
@ -129,16 +133,16 @@ Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount;
STATIC STATIC
UINT32 UINT32
GetBits( GetBits(
SCRATCH_DATA *Sd, IN SCRATCH_DATA *Sd,
UINT16 NumOfBits IN UINT16 NumOfBits
) )
/*++ /*++
Routine Description: Routine Description:
Get NumOfBits of bits from mBitBuf. Fill mBitBuf with subsequent Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent
NumOfBits of bits from source. Returns NumOfBits of bits that are NumOfBits of bits from source. Returns NumOfBits of bits that are
popped. popped out.
Arguments: Arguments:
@ -147,27 +151,27 @@ NumOfBits - The number of bits to pop and read.
Returns: Returns:
The bits that are popped. The bits that are popped out.
--*/ --*/
{ {
UINT32 Bits; UINT32 OutBits;
Bits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); OutBits = (UINT32)(Sd->mBitBuf >> (BITBUFSIZ - NumOfBits));
FillBuf(Sd, NumOfBits); FillBuf(Sd, NumOfBits);
return Bits; return OutBits;
} }
STATIC STATIC
UINT16 UINT16
MakeTable( MakeTable(
SCRATCH_DATA *Sd, IN SCRATCH_DATA *Sd,
UINT16 NumOfChar, IN UINT16 NumOfChar,
UINT8 *BitLen, IN UINT8 *BitLen,
UINT16 TableBits, IN UINT16 TableBits,
UINT16 *Table OUT UINT16 *Table
) )
/*++ /*++
@ -203,14 +207,33 @@ UINT16 Avail;
UINT16 NextCode; UINT16 NextCode;
UINT16 Mask; UINT16 Mask;
for (Index = 1; Index <= 16; Index++) { //
// TableBits should not be greater than 16.
//
if (TableBits >= (sizeof(Count) / sizeof(UINT16))) {
return (UINT16)BAD_TABLE;
}
//
// Initialize Count array starting from Index 0, as there is a possibility of Count array being uninitialized.
//
for (Index = 0; Index <= 16; Index++) {
Count[Index] = 0; Count[Index] = 0;
} }
for (Index = 0; Index < NumOfChar; Index++) { for (Index = 0; Index < NumOfChar; Index++) {
//
// Count array index should not be greater than or equal to its size.
//
if (BitLen[Index] < (sizeof(Count) / sizeof(UINT16))) {
Count[BitLen[Index]]++; Count[BitLen[Index]]++;
} }
else {
return (UINT16)BAD_TABLE;
}
}
Start[0] = 0;
Start[1] = 0; Start[1] = 0;
for (Index = 1; Index <= 16; Index++) { for (Index = 1; Index <= 16; Index++) {
@ -249,7 +272,7 @@ Mask = (UINT16) (1U << (15 - TableBits));
for (Char = 0; Char < NumOfChar; Char++) { for (Char = 0; Char < NumOfChar; Char++) {
Len = BitLen[Char]; Len = BitLen[Char];
if (Len == 0) { if (Len == 0 || Len >= 17) {
continue; continue;
} }
@ -261,25 +284,32 @@ for (Char = 0; Char < NumOfChar; Char++) {
// Check to prevent possible heap corruption // Check to prevent possible heap corruption
if (Index >= (UINT16)(1U << TableBits)) if (Index >= (UINT16)(1U << TableBits))
return (UINT16)BAD_TABLE; return (UINT16)BAD_TABLE;
Table[Index] = Char; Table[Index] = Char;
} }
} else { }
else {
Index3 = Start[Len]; Index3 = Start[Len];
Pointer = &Table[Index3 >> JuBits]; Pointer = &Table[Index3 >> JuBits];
Index = (UINT16)(Len - TableBits); Index = (UINT16)(Len - TableBits);
while (Index != 0) { while (Index != 0) {
if (*Pointer == 0) { //
// Avail should be lesser than size of mRight and mLeft to prevent buffer overflow.
//
if ((*Pointer == 0) && (Avail < sizeof(Sd->mRight) / sizeof(UINT16)) && (Avail < sizeof(Sd->mLeft) / sizeof(UINT16))) {
Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; Sd->mRight[Avail] = Sd->mLeft[Avail] = 0;
*Pointer = Avail++; *Pointer = Avail++;
} }
if (Index3 & Mask) { //
// *Pointer should be lesser than size of mRight and mLeft to prevent buffer overflow.
//
if ((Index3 & Mask) && (*Pointer < (sizeof(Sd->mRight) / sizeof(UINT16)))) {
Pointer = &Sd->mRight[*Pointer]; Pointer = &Sd->mRight[*Pointer];
} else { }
else if (*Pointer < (sizeof(Sd->mLeft) / sizeof(UINT16))) {
Pointer = &Sd->mLeft[*Pointer]; Pointer = &Sd->mLeft[*Pointer];
} }
@ -302,7 +332,7 @@ return 0;
STATIC STATIC
UINT32 UINT32
DecodeP( DecodeP(
SCRATCH_DATA *Sd IN SCRATCH_DATA *Sd
) )
/*++ /*++
@ -333,7 +363,8 @@ if (Val >= MAXNP) {
if (Sd->mBitBuf & Mask) { if (Sd->mBitBuf & Mask) {
Val = Sd->mRight[Val]; Val = Sd->mRight[Val];
} else { }
else {
Val = Sd->mLeft[Val]; Val = Sd->mLeft[Val];
} }
@ -356,10 +387,10 @@ return Pos;
STATIC STATIC
UINT16 UINT16
ReadPTLen( ReadPTLen(
SCRATCH_DATA *Sd, IN SCRATCH_DATA *Sd,
UINT16 nn, IN UINT16 nn,
UINT16 nbit, IN UINT16 nbit,
UINT16 Special IN UINT16 Special
) )
/*++ /*++
@ -388,6 +419,13 @@ UINT32 Mask;
Number = (UINT16)GetBits(Sd, nbit); Number = (UINT16)GetBits(Sd, nbit);
if ((Number > sizeof(Sd->mPTLen)) || (nn > sizeof(Sd->mPTLen))) {
//
// Fail if Number or nn is greater than size of mPTLen
//
return (UINT16)BAD_TABLE;
}
if (Number == 0) { if (Number == 0) {
CharC = (UINT16)GetBits(Sd, nbit); CharC = (UINT16)GetBits(Sd, nbit);
@ -423,6 +461,12 @@ while (Index < Number) {
if (Index == Special) { if (Index == Special) {
CharC = (UINT16)GetBits(Sd, 2); CharC = (UINT16)GetBits(Sd, 2);
while ((INT16)(--CharC) >= 0) { while ((INT16)(--CharC) >= 0) {
if (Index >= sizeof(Sd->mPTLen)) {
//
// Fail if Index is greater than or equal to mPTLen
//
return (UINT16)BAD_TABLE;
}
Sd->mPTLen[Index++] = 0; Sd->mPTLen[Index++] = 0;
} }
} }
@ -486,7 +530,8 @@ while (Index < Number) {
if (Mask & Sd->mBitBuf) { if (Mask & Sd->mBitBuf) {
CharC = Sd->mRight[CharC]; CharC = Sd->mRight[CharC];
} else { }
else {
CharC = Sd->mLeft[CharC]; CharC = Sd->mLeft[CharC];
} }
@ -503,9 +548,11 @@ while (Index < Number) {
if (CharC == 0) { if (CharC == 0) {
CharC = 1; CharC = 1;
} else if (CharC == 1) { }
else if (CharC == 1) {
CharC = (UINT16)(GetBits(Sd, 4) + 3); CharC = (UINT16)(GetBits(Sd, 4) + 3);
} else if (CharC == 2) { }
else if (CharC == 2) {
CharC = (UINT16)(GetBits(Sd, CBIT) + 20); CharC = (UINT16)(GetBits(Sd, CBIT) + 20);
} }
@ -513,7 +560,8 @@ while (Index < Number) {
Sd->mCLen[Index++] = 0; Sd->mCLen[Index++] = 0;
} }
} else { }
else {
Sd->mCLen[Index++] = (UINT8)(CharC - 2); Sd->mCLen[Index++] = (UINT8)(CharC - 2);
@ -580,7 +628,8 @@ if (Index2 >= NC) {
do { do {
if (Sd->mBitBuf & Mask) { if (Sd->mBitBuf & Mask) {
Index2 = Sd->mRight[Index2]; Index2 = Sd->mRight[Index2];
} else { }
else {
Index2 = Sd->mLeft[Index2]; Index2 = Sd->mLeft[Index2];
} }
@ -634,11 +683,13 @@ for (;;) {
// //
if (Sd->mOutBuf >= Sd->mOrigSize) { if (Sd->mOutBuf >= Sd->mOrigSize) {
return; return;
} else { }
else {
Sd->mDstBase[Sd->mOutBuf++] = (UINT8)CharC; Sd->mDstBase[Sd->mOutBuf++] = (UINT8)CharC;
} }
} else { }
else {
// //
// Process a Pointer // Process a Pointer
// //
@ -647,10 +698,6 @@ for (;;) {
BytesRemain = CharC; BytesRemain = CharC;
DataIdx = Sd->mOutBuf - DecodeP(Sd) - 1; DataIdx = Sd->mOutBuf - DecodeP(Sd) - 1;
if (DataIdx >= Sd->mOrigSize) {
Sd->mBadTableFlag = 1;
return;
}
BytesRemain--; BytesRemain--;
while ((INT16)(BytesRemain) >= 0) { while ((INT16)(BytesRemain) >= 0) {
@ -663,16 +710,14 @@ for (;;) {
} }
} }
} }
return ;
} }
UINT32 EFI_STATUS
EfiTianoGetInfo ( GetInfo(
VOID *Source, IN VOID *Source,
UINT32 SrcSize, IN UINT32 SrcSize,
UINT32 *DstSize, OUT UINT32 *DstSize,
UINT32 *ScratchSize OUT UINT32 *ScratchSize
) )
/*++ /*++
@ -689,7 +734,7 @@ ScratchSize - The size of scratch buffer.
Returns: Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved. EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted EFI_INVALID_PARAMETER - The source data is corrupted
--*/ --*/
@ -700,22 +745,22 @@ UINT8 *Src;
Src = Source; Src = Source;
if (SrcSize < 8) { if (SrcSize < 8) {
return ERR_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
*DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); *DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
return ERR_SUCCESS; return EFI_SUCCESS;
} }
UINT32 EFI_STATUS
Decompress( Decompress(
VOID *Source, IN VOID *Source,
UINT32 SrcSize, IN UINT32 SrcSize,
VOID *Destination, IN OUT VOID *Destination,
UINT32 DstSize, IN UINT32 DstSize,
VOID *Scratch, IN OUT VOID *Scratch,
UINT32 ScratchSize, IN UINT32 ScratchSize,
UINT8 Version IN UINT8 Version
) )
/*++ /*++
@ -745,23 +790,23 @@ EFI_INVALID_PARAMETER - The source data is corrupted
UINT32 Index; UINT32 Index;
UINT32 CompSize; UINT32 CompSize;
UINT32 OrigSize; UINT32 OrigSize;
UINT32 Status; EFI_STATUS Status;
SCRATCH_DATA *Sd; SCRATCH_DATA *Sd;
UINT8 *Src; UINT8 *Src;
UINT8 *Dst; UINT8 *Dst;
Status = ERR_SUCCESS; Status = EFI_SUCCESS;
Src = Source; Src = Source;
Dst = Destination; Dst = Destination;
if (ScratchSize < sizeof(SCRATCH_DATA)) { if (ScratchSize < sizeof(SCRATCH_DATA)) {
return ERR_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Sd = (SCRATCH_DATA *)Scratch; Sd = (SCRATCH_DATA *)Scratch;
if (SrcSize < 8) { if (SrcSize < 8) {
return ERR_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
@ -775,11 +820,11 @@ if (OrigSize == 0) {
} }
if (SrcSize < CompSize + 8) { if (SrcSize < CompSize + 8) {
return ERR_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
if (DstSize != OrigSize) { if (DstSize != OrigSize) {
return ERR_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Src = Src + 8; Src = Src + 8;
@ -788,7 +833,7 @@ for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) {
((UINT8 *)Sd)[Index] = 0; ((UINT8 *)Sd)[Index] = 0;
} }
// //
// The length of the field 'Position Set Code Length Array Size'Block Header. // The length of the field 'Position Set Code Length Array Size' in Block Header.
// For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4 // For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4
// For Tiano de/compression algorithm(Version 2), mPBit = 5 // For Tiano de/compression algorithm(Version 2), mPBit = 5
// //
@ -805,7 +850,7 @@ default:
// //
// Currently, only have 2 versions // Currently, only have 2 versions
// //
return ERR_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Sd->mSrcBase = Src; Sd->mSrcBase = Src;
@ -827,27 +872,64 @@ if (Sd->mBadTableFlag != 0) {
// //
// Something wrong with the source // Something wrong with the source
// //
Status = ERR_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
} }
return Status; return Status;
} }
UINT32 EFI_STATUS
EFIAPI EFIAPI
EfiDecompress ( EfiTianoGetInfo(
VOID *Source, IN VOID *Source,
UINT32 SrcSize, IN UINT32 SrcSize,
VOID *Destination, OUT UINT32 *DstSize,
UINT32 DstSize, OUT UINT32 *ScratchSize
VOID *Scratch,
UINT32 ScratchSize
) )
/*++ /*++
Routine Description: Routine Description:
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.Decompress(). The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo().
Arguments:
This - The protocol instance pointer
Source - The source buffer containing the compressed data.
SrcSize - The size of source buffer
DstSize - The size of destination buffer.
ScratchSize - The size of scratch buffer.
Returns:
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successful retrieved.
EFI_INVALID_PARAMETER - The source data is corrupted
--*/
{
return GetInfo(
Source,
SrcSize,
DstSize,
ScratchSize
);
}
EFI_STATUS
EFIAPI
EfiDecompress(
IN VOID *Source,
IN UINT32 SrcSize,
IN OUT VOID *Destination,
IN UINT32 DstSize,
IN OUT VOID *Scratch,
IN UINT32 ScratchSize
)
/*++
Routine Description:
The implementation of EFI_DECOMPRESS_PROTOCOL.Decompress().
Arguments: Arguments:
@ -880,21 +962,21 @@ return Decompress (
); );
} }
UINT32 EFI_STATUS
EFIAPI EFIAPI
TianoDecompress( TianoDecompress(
VOID *Source, IN VOID *Source,
UINT32 SrcSize, IN UINT32 SrcSize,
VOID *Destination, IN OUT VOID *Destination,
UINT32 DstSize, IN UINT32 DstSize,
VOID *Scratch, IN OUT VOID *Scratch,
UINT32 ScratchSize IN UINT32 ScratchSize
) )
/*++ /*++
Routine Description: Routine Description:
The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress(). The implementation of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress().
Arguments: Arguments:
@ -926,4 +1008,3 @@ return Decompress (
2 2
); );
} }

View File

@ -1,6 +1,7 @@
/*++ /* EfiTianoDecompress.h
Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR> Copyright (c) 2014, Nikolaj Schlej. All rights reserved.<BR>
Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -30,12 +31,13 @@ Providing both EFI and Tiano decompress algorithms.
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct { typedef struct {
UINT32 CompSize; UINT32 CompSize;
UINT32 OrigSize; UINT32 OrigSize;
} EFI_TIANO_HEADER; } EFI_TIANO_HEADER;
UINT32 EFI_STATUS
EFIAPI EFIAPI
EfiTianoGetInfo ( EfiTianoGetInfo (
VOID *Source, VOID *Source,
@ -65,7 +67,7 @@ EFI_INVALID_PARAMETER - The source data is corrupted
--*/ --*/
; ;
UINT32 EFI_STATUS
EFIAPI EFIAPI
EfiDecompress ( EfiDecompress (
VOID *Source, VOID *Source,
@ -99,7 +101,7 @@ EFI_INVALID_PARAMETER - The source data is corrupted
--*/ --*/
; ;
UINT32 EFI_STATUS
EFIAPI EFIAPI
TianoDecompress ( TianoDecompress (
VOID *Source, VOID *Source,

View File

@ -56,6 +56,7 @@ UINT8 UEFIPatch::patchFromFile(QString path)
if (result) if (result)
return result; return result;
UINT8 counter = 0;
while (!file.atEnd()) { while (!file.atEnd()) {
QByteArray line = file.readLine(); QByteArray line = file.readLine();
// Use sharp sign as commentary // Use sharp sign as commentary
@ -68,98 +69,81 @@ UINT8 UEFIPatch::patchFromFile(QString path)
QUuid uuid = QUuid(list.at(0)); QUuid uuid = QUuid(list.at(0));
QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID)); QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID));
result = patchFile(model->index(0, 0), guid, QByteArray::fromHex(list.at(1)), QByteArray::fromHex(list.at(2))); bool converted;
if (result) UINT8 sectionType = (UINT8)list.at(1).toUShort(&converted, 16);
return result; if (!converted)
}
QByteArray reconstructed;
result = ffsEngine->reconstructImageFile(reconstructed);
if (result)
return result;
if (reconstructed == buffer) {
return ERR_ITEM_NOT_FOUND;
}
QFile outputFile;
outputFile.setFileName(path.append(".patched"));
if (!outputFile.open(QFile::WriteOnly))
return ERR_FILE_WRITE;
outputFile.resize(0);
outputFile.write(reconstructed);
outputFile.close();
return ERR_SUCCESS;
}
UINT8 UEFIPatch::patch(QString path, QString fileGuid, QString findPattern, QString replacePattern)
{
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly))
return ERR_FILE_READ;
QByteArray buffer = inputFile.readAll();
inputFile.close();
UINT8 result = ffsEngine->parseImageFile(buffer);
if (result)
return result;
QUuid uuid = QUuid(fileGuid);
QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID));
result = patchFile(model->index(0, 0), guid, QByteArray::fromHex(findPattern.toLatin1()), QByteArray::fromHex(replacePattern.toLatin1()));
if (result)
return result;
QByteArray reconstructed;
result = ffsEngine->reconstructImageFile(reconstructed);
if (result)
return result;
if (reconstructed == buffer) {
return ERR_ITEM_NOT_FOUND;
}
QFile outputFile;
outputFile.setFileName(path.append(".patched"));
if (!outputFile.open(QFile::WriteOnly))
return ERR_FILE_WRITE;
outputFile.resize(0);
outputFile.write(reconstructed);
outputFile.close();
return ERR_SUCCESS;
}
UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const QByteArray & findPattern, const QByteArray & replacePattern)
{
if (!model || !index.isValid())
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
if (model->type(index) == Types::File && model->header(index).left(sizeof(EFI_GUID)) == fileGuid) { QVector<PatchData> patches;
return ffsEngine->patch(index, findPattern, replacePattern, PATCH_MODE_BODY);
for (int i = 2; i < list.count(); i++) {
QList<QByteArray> patchList = list.at(i).split(':');
PatchData patch;
patch.type = *(UINT8*)patchList.at(0).constData();
if (patch.type == PATCH_TYPE_PATTERN) {
patch.offset = 0xFFFFFFFF;
patch.hexFindPattern = patchList.at(1);
patch.hexReplacePattern = patchList.at(2);
patches.append(patch);
}
else if (patch.type == PATCH_TYPE_OFFSET) {
patch.offset = patchList.at(1).toUInt(NULL, 16);
patch.hexReplacePattern = patchList.at(2);
patches.append(patch);
}
else {
// Ignore unknown patch type
continue;
}
}
result = patchFile(model->index(0, 0), guid, sectionType, patches);
if (result && result != ERR_NOTHING_TO_PATCH)
return result;
counter++;
} }
int childCount = model->rowCount(index); QByteArray reconstructed;
if (childCount > 0) { result = ffsEngine->reconstructImageFile(reconstructed);
UINT8 result;
for (int i = 0; i < childCount; i++) {
result = patchFile(index.child(i, 0), fileGuid, findPattern, replacePattern);
if (result) if (result)
return result; return result;
if (reconstructed == buffer)
return ERR_NOTHING_TO_PATCH;
QFile outputFile;
outputFile.setFileName(path.append(".patched"));
if (!outputFile.open(QFile::WriteOnly))
return ERR_FILE_WRITE;
outputFile.resize(0);
outputFile.write(reconstructed);
outputFile.close();
return ERR_SUCCESS;
}
UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches)
{
if (!model || !index.isValid())
return ERR_INVALID_PARAMETER;
if (model->type(index) == Types::Section && model->subtype(index) == sectionType) {
QModelIndex fileIndex = model->findParentOfType(index, Types::File);
if (model->type(fileIndex) == Types::File &&
model->header(fileIndex).left(sizeof(EFI_GUID)) == fileGuid)
{
return ffsEngine->patch(index, patches);
}
}
if (model->rowCount(index) > 0) {
for (int i = 0; i < model->rowCount(index); i++) {
UINT8 result = patchFile(index.child(i, 0), fileGuid, sectionType, patches);
if (!result)
break;
else if (result != ERR_NOTHING_TO_PATCH)
return result;
} }
} }
return ERR_SUCCESS; return ERR_NOTHING_TO_PATCH;
} }

View File

@ -37,7 +37,7 @@ public:
UINT8 patch(QString path, QString fileGuid, QString findPattern, QString replacePattern); UINT8 patch(QString path, QString fileGuid, QString findPattern, QString replacePattern);
private: private:
UINT8 patchFile(const QModelIndex & index, const QByteArray & fileGuid, const QByteArray & findPattern, const QByteArray & replacePattern); UINT8 patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches);
FfsEngine* ffsEngine; FfsEngine* ffsEngine;
TreeModel* model; TreeModel* model;
}; };

View File

@ -27,31 +27,34 @@ int main(int argc, char *argv[])
UINT8 result = ERR_SUCCESS; UINT8 result = ERR_SUCCESS;
UINT32 argumentsCount = a.arguments().length(); UINT32 argumentsCount = a.arguments().length();
if (argumentsCount == 2) { if (argumentsCount == 2) {
result = w.patchFromFile(a.arguments().at(1)); result = w.patchFromFile(a.arguments().at(1));
} }
else if (argumentsCount == 5) { else {
result = w.patch(a.arguments().at(1), a.arguments().at(2), a.arguments().at(3), a.arguments().at(4)); std::cout << "UEFIPatch 0.2.0 - UEFI image file patching utility" << std::endl << std::endl <<
"Usage: UEFIPatch image_file" << std::endl << std::endl <<
"Patches will be read from patches.txt file\n";
return ERR_SUCCESS;
} }
else
result = ERR_INVALID_PARAMETER;
switch (result) { switch (result) {
case ERR_INVALID_PARAMETER:
std::cout << "UEFIPatch 0.1.0 - UEFI image file patching utility" << std::endl << std::endl <<
"Usage: UEFIPatch image_file [ffs_file_guid search_pattern replace_pattern]" << std::endl << std::endl <<
"image_file - full or relative path to UEFI image file" << std::endl <<
"ffs_file_guid - GUID of FFS file to be patched" << std::endl <<
"search_pattern - pattern to search" << std::endl <<
"replace_pattern - pattern to replace" << std::endl << std::endl <<
"If only image_file parameter is specified, patches will be read from patches.txt file";
break;
case ERR_SUCCESS: case ERR_SUCCESS:
std::cout << "Image patched" << std::endl; std::cout << "Image patched" << std::endl;
break; break;
case ERR_ITEM_NOT_FOUND: case ERR_INVALID_PARAMETER:
std::cout << "FFS file or search pattern not found in input file" << std::endl; std::cout << "Function called with invalid parameter" << std::endl;
break;
case ERR_NOTHING_TO_PATCH:
std::cout << "No patches can be applied to input file" << std::endl;
break;
case ERR_UNKNOWN_PATCH_TYPE:
std::cout << "Unknown patch type" << std::endl;
break;
case ERR_PATCH_OFFSET_OUT_OF_BOUNDS:
std::cout << "Patch offset out of bounds" << std::endl;
break;
case ERR_INVALID_SYMBOL:
std::cout << "Pattern format mismatch" << std::endl;
break; break;
case ERR_INVALID_FILE: case ERR_INVALID_FILE:
std::cout << "patches.txt file not found or can't be read" << std::endl; std::cout << "patches.txt file not found or can't be read" << std::endl;

View File

@ -45,8 +45,6 @@ typedef uint16_t CHAR16;
#define NULL ((VOID *) 0) #define NULL ((VOID *) 0)
#endif #endif
#define EFIAPI
#define ERR_SUCCESS 0 #define ERR_SUCCESS 0
#define ERR_INVALID_PARAMETER 1 #define ERR_INVALID_PARAMETER 1
#define ERR_BUFFER_TOO_SMALL 2 #define ERR_BUFFER_TOO_SMALL 2
@ -85,9 +83,23 @@ typedef uint16_t CHAR16;
#define ERR_COMPLEX_BLOCK_MAP 35 #define ERR_COMPLEX_BLOCK_MAP 35
#define ERR_DIR_ALREADY_EXIST 36 #define ERR_DIR_ALREADY_EXIST 36
#define ERR_DIR_CREATE 37 #define ERR_DIR_CREATE 37
#define ERR_UNKNOWN_PATCH_MODE 38 #define ERR_UNKNOWN_PATCH_TYPE 38
#define ERR_PATCH_OFFSET_OUT_OF_BOUNDS 39
#define ERR_INVALID_SYMBOL 40
#define ERR_NOTHING_TO_PATCH 41
#define ERR_NOT_IMPLEMENTED 0xFF #define ERR_NOT_IMPLEMENTED 0xFF
// UDK porting definitions
#define IN
#define OUT
#define EFIAPI
#define EFI_STATUS UINT8
#define EFI_SUCCESS ERR_SUCCESS
#define EFI_INVALID_PARAMETER ERR_INVALID_PARAMETER
#define EFI_OUT_OF_RESOURCES ERR_OUT_OF_RESOURCES
#define EFI_BUFFER_TOO_SMALL ERR_BUFFER_TOO_SMALL
#define EFI_ERROR(X) X
// Compression algorithms // Compression algorithms
#define COMPRESSION_ALGORITHM_UNKNOWN 0 #define COMPRESSION_ALGORITHM_UNKNOWN 0
#define COMPRESSION_ALGORITHM_NONE 1 #define COMPRESSION_ALGORITHM_NONE 1
@ -114,6 +126,10 @@ typedef uint16_t CHAR16;
#define PATCH_MODE_HEADER 0 #define PATCH_MODE_HEADER 0
#define PATCH_MODE_BODY 1 #define PATCH_MODE_BODY 1
// Patch types
#define PATCH_TYPE_OFFSET 'O'
#define PATCH_TYPE_PATTERN 'P'
// Erase polarity types // Erase polarity types
#define ERASE_POLARITY_FALSE 0 #define ERASE_POLARITY_FALSE 0
#define ERASE_POLARITY_TRUE 1 #define ERASE_POLARITY_TRUE 1
@ -124,8 +140,6 @@ typedef uint16_t CHAR16;
#define SEARCH_MODE_BODY 2 #define SEARCH_MODE_BODY 2
#define SEARCH_MODE_ALL 3 #define SEARCH_MODE_ALL 3
// EFI GUID // EFI GUID
typedef struct { typedef struct {
UINT8 Data[16]; UINT8 Data[16];

View File

@ -1797,7 +1797,6 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteArray & compressedData) UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteArray & compressedData)
{ {
UINT8* compressed; UINT8* compressed;
UINT32 compressedSize = 0;
switch (algorithm) { switch (algorithm) {
case COMPRESSION_ALGORITHM_NONE: case COMPRESSION_ALGORITHM_NONE:
@ -1808,10 +1807,11 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
break; break;
case COMPRESSION_ALGORITHM_EFI11: case COMPRESSION_ALGORITHM_EFI11:
{ {
if (EfiCompress((UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) UINT64 compressedSize = 0;
if (EfiCompress(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL)
return ERR_STANDARD_COMPRESSION_FAILED; return ERR_STANDARD_COMPRESSION_FAILED;
compressed = new UINT8[compressedSize]; compressed = new UINT8[compressedSize];
if (EfiCompress((UINT8*)data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { if (EfiCompress(data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) {
delete[] compressed; delete[] compressed;
return ERR_STANDARD_COMPRESSION_FAILED; return ERR_STANDARD_COMPRESSION_FAILED;
} }
@ -1822,10 +1822,11 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
break; break;
case COMPRESSION_ALGORITHM_TIANO: case COMPRESSION_ALGORITHM_TIANO:
{ {
if (TianoCompress((UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) UINT64 compressedSize = 0;
if (TianoCompress(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL)
return ERR_STANDARD_COMPRESSION_FAILED; return ERR_STANDARD_COMPRESSION_FAILED;
compressed = new UINT8[compressedSize]; compressed = new UINT8[compressedSize];
if (TianoCompress((UINT8*)data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { if (TianoCompress(data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) {
delete[] compressed; delete[] compressed;
return ERR_STANDARD_COMPRESSION_FAILED; return ERR_STANDARD_COMPRESSION_FAILED;
} }
@ -1836,6 +1837,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
break; break;
case COMPRESSION_ALGORITHM_LZMA: case COMPRESSION_ALGORITHM_LZMA:
{ {
UINT32 compressedSize = 0;
if (LzmaCompress((const UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) if (LzmaCompress((const UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL)
return ERR_CUSTOMIZED_COMPRESSION_FAILED; return ERR_CUSTOMIZED_COMPRESSION_FAILED;
compressed = new UINT8[compressedSize]; compressed = new UINT8[compressedSize];
@ -1850,6 +1852,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
break; break;
case COMPRESSION_ALGORITHM_IMLZMA: case COMPRESSION_ALGORITHM_IMLZMA:
{ {
UINT32 compressedSize = 0;
QByteArray header = data.left(sizeof(EFI_COMMON_SECTION_HEADER)); QByteArray header = data.left(sizeof(EFI_COMMON_SECTION_HEADER));
EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*)header.constData(); EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*)header.constData();
UINT32 headerSize = sizeOfSectionHeader(sectionHeader); UINT32 headerSize = sizeOfSectionHeader(sectionHeader);
@ -2645,6 +2648,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base,
// Reconstruction successful // Reconstruction successful
reconstructed = header.append(reconstructed); reconstructed = header.append(reconstructed);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -3198,48 +3202,126 @@ UINT8 FfsEngine::dump(const QModelIndex & index, const QString path)
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::patch(const QModelIndex & index, const QByteArray & findPattern, const QByteArray & replacePattern, const UINT8 mode) UINT8 FfsEngine::patch(const QModelIndex & index, const QVector<PatchData> & patches)
{ {
if (!index.isValid() || findPattern.isEmpty()) if (!index.isValid() || patches.isEmpty() || model->rowCount(index))
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
// Skip removed files // Skip removed items
if (model->action(index) == Actions::Remove) if (model->action(index) == Actions::Remove)
return ERR_SUCCESS; return ERR_NOTHING_TO_PATCH;
// Patch header
if (mode == PATCH_MODE_HEADER && model->header(index).contains(findPattern)) {
QByteArray patched = model->header(index);
patched.replace(findPattern, replacePattern).append(model->body(index));
msg(tr("Header of %1 patched, %2 -> %3")
.arg(model->nameString(index))
.arg(QString(findPattern.toHex()))
.arg(QString(replacePattern.toHex())), index);
return replace(index, patched, REPLACE_MODE_AS_IS);
}
// Patch body
else if (mode == PATCH_MODE_BODY) {
if (model->rowCount(index)) {
UINT8 result; UINT8 result;
for (int i = 0; i < model->rowCount(index); i++) {
result = patch(index.child(i, 0), findPattern, replacePattern, PATCH_MODE_BODY); // Apply patches to item's body
QByteArray body = model->body(index);
PatchData current;
Q_FOREACH(current, patches)
{
if (current.type == PATCH_TYPE_OFFSET) {
result = patchViaOffset(body, current.offset, current.hexReplacePattern);
if (result) if (result)
return result; return result;
} }
} else if (current.type == PATCH_TYPE_PATTERN) {
else if (model->body(index).contains(findPattern)){ result = patchViaPattern(body, current.hexFindPattern, current.hexReplacePattern);
QByteArray patched = model->body(index); if (result)
patched.replace(findPattern, replacePattern); return result;
patched.prepend(model->header(index));
msg(tr("Body of %1 patched, %2 -> %3")
.arg(model->nameString(index))
.arg(QString(findPattern.toHex()))
.arg(QString(replacePattern.toHex())), index);
return replace(index, patched, REPLACE_MODE_AS_IS);
}
} }
else else
return ERR_UNKNOWN_PATCH_MODE; return ERR_UNKNOWN_PATCH_TYPE;
}
if (body != model->body(index)) {
QByteArray patched = model->header(index);
patched.append(body);
return replace(index, patched, REPLACE_MODE_AS_IS);
}
return ERR_NOTHING_TO_PATCH;
}
UINT8 FfsEngine::patchViaOffset(QByteArray & data, const UINT32 offset, const QByteArray & hexReplacePattern)
{
QByteArray body = data;
// Skip patterns with odd length
if (hexReplacePattern.length() % 2 > 0)
return ERR_INVALID_PARAMETER;
// Check offset bounds
if (offset > body.length() - hexReplacePattern.length() / 2)
return ERR_PATCH_OFFSET_OUT_OF_BOUNDS;
// Parse replace pattern
QByteArray replacePattern;
bool converted;
for (int i = 0; i < hexReplacePattern.length() / 2; i++) {
QByteArray hex = hexReplacePattern.mid(2 * i, 2);
UINT8 value = 0;
if (!hex.contains('.')) { // Normal byte pattern
value = (UINT8)hex.toUShort(&converted, 16);
if (!converted)
return ERR_INVALID_SYMBOL;
}
else { // Placeholder byte pattern
if (hex[0] == '.' && hex[1] == '.') { // Full byte placeholder
value = body.at(offset + i);
}
else if (hex[0] == '.') {// Upper byte part placeholder
hex[0] = '0';
value = (UINT8)(body.at(offset + i) & 0xF0);
value += (UINT8)hex.toUShort(&converted, 16);
if (!converted)
return ERR_INVALID_SYMBOL;
}
else if (hex[1] == '.') { // Lower byte part placeholder
hex[1] = '0';
value = (UINT8)(body.at(offset + i) & 0x0F);
value += (UINT8)hex.toUShort(&converted, 16);
if (!converted)
return ERR_INVALID_SYMBOL;
}
else
return ERR_INVALID_SYMBOL;
}
// Append calculated value to real pattern
replacePattern.append(value);
}
body.replace(offset, replacePattern.length(), replacePattern);
msg(tr("patch: replaced %1 bytes at offset 0x%2 %3 -> %4")
.arg(replacePattern.length())
.arg(offset, 8, 16, QChar('0'))
.arg(QString(data.mid(offset, replacePattern.length()).toHex()))
.arg(QString(replacePattern.toHex())));
data = body;
return ERR_SUCCESS;
}
UINT8 FfsEngine::patchViaPattern(QByteArray & data, const QByteArray hexFindPattern, const QByteArray & hexReplacePattern)
{
QByteArray body = data;
// Skip patterns with odd length
if (hexFindPattern.length() % 2 > 0 || hexReplacePattern.length() % 2 > 0)
return ERR_INVALID_PARAMETER;
// Convert file body to hex;
QString hexBody = QString(body.toHex());
QRegExp regexp = QRegExp(QString(hexFindPattern), Qt::CaseInsensitive);
INT64 offset = regexp.indexIn(hexBody);
while (offset >= 0) {
if (offset % 2 == 0) {
UINT8 result = patchViaOffset(body, offset/2, hexReplacePattern);
if (result)
return result;
}
offset = regexp.indexIn(hexBody, offset + 1);
}
data = body;
return ERR_SUCCESS; return ERR_SUCCESS;
} }

View File

@ -32,6 +32,13 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
class TreeModel; class TreeModel;
struct PatchData {
UINT8 type;
UINT32 offset;
QByteArray hexFindPattern;
QByteArray hexReplacePattern;
};
class FfsEngine : public QObject class FfsEngine : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -86,7 +93,7 @@ public:
UINT8 remove(const QModelIndex & index); UINT8 remove(const QModelIndex & index);
UINT8 rebuild(const QModelIndex & index); UINT8 rebuild(const QModelIndex & index);
UINT8 dump(const QModelIndex & index, const QString path); UINT8 dump(const QModelIndex & index, const QString path);
UINT8 patch(const QModelIndex & index, const QByteArray & findPattern, const QByteArray & replacePattern, const UINT8 mode); UINT8 patch(const QModelIndex & index, const QVector<PatchData> & patches);
// Search routines // Search routines
UINT8 findHexPattern(const QByteArray & pattern, const UINT8 mode); UINT8 findHexPattern(const QByteArray & pattern, const UINT8 mode);
@ -120,6 +127,10 @@ private:
// Patch routines // Patch routines
UINT8 patchVtf(QByteArray &vtf); UINT8 patchVtf(QByteArray &vtf);
// Patch helpers
UINT8 patchViaOffset(QByteArray & data, const UINT32 offset, const QByteArray & hexReplacePattern);
UINT8 patchViaPattern(QByteArray & data, const QByteArray hexFindPattern, const QByteArray & hexReplacePattern);
#ifndef _CONSOLE #ifndef _CONSOLE
QQueue<MessageListItem> messageItems; QQueue<MessageListItem> messageItems;
#endif #endif

View File

@ -20,7 +20,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>UEFITool 0.17.10</string> <string>UEFITool 0.18.0</string>
</property> </property>
<widget class="QWidget" name="centralWidget"> <widget class="QWidget" name="centralWidget">
<property name="sizePolicy"> <property name="sizePolicy">