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
) )
; ;

File diff suppressed because it is too large Load Diff

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
@ -11,12 +12,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: Module Name:
Decompress.h Decompress.h
Abstract: Abstract:
Header file for decompression routine. Header file for decompression routine.
Providing both EFI and Tiano decompress algorithms. Providing both EFI and Tiano decompress algorithms.
--*/ --*/
@ -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,20 +69,46 @@ 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);
if (!converted)
return ERR_INVALID_PARAMETER;
QVector<PatchData> patches;
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; return result;
counter++;
} }
QByteArray reconstructed; QByteArray reconstructed;
result = ffsEngine->reconstructImageFile(reconstructed); result = ffsEngine->reconstructImageFile(reconstructed);
if (result) if (result)
return result; return result;
if (reconstructed == buffer)
if (reconstructed == buffer) { return ERR_NOTHING_TO_PATCH;
return ERR_ITEM_NOT_FOUND;
}
QFile outputFile; QFile outputFile;
outputFile.setFileName(path.append(".patched")); outputFile.setFileName(path.append(".patched"));
if (!outputFile.open(QFile::WriteOnly)) if (!outputFile.open(QFile::WriteOnly))
@ -94,72 +121,29 @@ UINT8 UEFIPatch::patchFromFile(QString path)
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 UEFIPatch::patch(QString path, QString fileGuid, QString findPattern, QString replacePattern) UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches)
{
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()) if (!model || !index.isValid())
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
if (model->type(index) == Types::Section && model->subtype(index) == sectionType) {
if (model->type(index) == Types::File && model->header(index).left(sizeof(EFI_GUID)) == fileGuid) { QModelIndex fileIndex = model->findParentOfType(index, Types::File);
return ffsEngine->patch(index, findPattern, replacePattern, PATCH_MODE_BODY); if (model->type(fileIndex) == Types::File &&
model->header(fileIndex).left(sizeof(EFI_GUID)) == fileGuid)
{
return ffsEngine->patch(index, patches);
}
} }
int childCount = model->rowCount(index); if (model->rowCount(index) > 0) {
if (childCount > 0) { for (int i = 0; i < model->rowCount(index); i++) {
UINT8 result; UINT8 result = patchFile(index.child(i, 0), fileGuid, sectionType, patches);
for (int i = 0; i < childCount; i++) { if (!result)
result = patchFile(index.child(i, 0), fileGuid, findPattern, replacePattern); break;
if (result) else if (result != ERR_NOTHING_TO_PATCH)
return result; 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,8 +1797,7 @@ 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 UINT8 result;
if (mode == PATCH_MODE_HEADER && model->header(index).contains(findPattern)) {
// 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)
return result;
}
else if (current.type == PATCH_TYPE_PATTERN) {
result = patchViaPattern(body, current.hexFindPattern, current.hexReplacePattern);
if (result)
return result;
}
else
return ERR_UNKNOWN_PATCH_TYPE;
}
if (body != model->body(index)) {
QByteArray patched = model->header(index); QByteArray patched = model->header(index);
patched.replace(findPattern, replacePattern).append(model->body(index)); patched.append(body);
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); return replace(index, patched, REPLACE_MODE_AS_IS);
} }
// Patch body
else if (mode == PATCH_MODE_BODY) { return ERR_NOTHING_TO_PATCH;
if (model->rowCount(index)) { }
UINT8 result;
for (int i = 0; i < model->rowCount(index); i++) {
result = patch(index.child(i, 0), findPattern, replacePattern, PATCH_MODE_BODY);
if (result)
return result;
}
}
else if (model->body(index).contains(findPattern)){
QByteArray patched = model->body(index);
patched.replace(findPattern, replacePattern);
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
return ERR_UNKNOWN_PATCH_MODE;
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,12 +127,16 @@ 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
// Message helper // Message helper
void msg(const QString & message, const QModelIndex &index = QModelIndex()); void msg(const QString & message, const QModelIndex &index = QModelIndex());
// Internal operations // Internal operations
bool hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2); bool hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length); UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);

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">