mirror of
https://github.com/LongSoft/UEFITool.git
synced 2025-05-13 06:34:42 -04:00
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:
parent
a3854ad059
commit
c23aef47be
11 changed files with 2227 additions and 2429 deletions
162
ffsengine.cpp
162
ffsengine.cpp
|
@ -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* compressed;
|
||||
UINT32 compressedSize = 0;
|
||||
|
||||
|
||||
switch (algorithm) {
|
||||
case COMPRESSION_ALGORITHM_NONE:
|
||||
{
|
||||
|
@ -1808,10 +1807,11 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
|||
break;
|
||||
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;
|
||||
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;
|
||||
return ERR_STANDARD_COMPRESSION_FAILED;
|
||||
}
|
||||
|
@ -1822,10 +1822,11 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
|||
break;
|
||||
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;
|
||||
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;
|
||||
return ERR_STANDARD_COMPRESSION_FAILED;
|
||||
}
|
||||
|
@ -1836,6 +1837,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
|||
break;
|
||||
case COMPRESSION_ALGORITHM_LZMA:
|
||||
{
|
||||
UINT32 compressedSize = 0;
|
||||
if (LzmaCompress((const UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL)
|
||||
return ERR_CUSTOMIZED_COMPRESSION_FAILED;
|
||||
compressed = new UINT8[compressedSize];
|
||||
|
@ -1850,6 +1852,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
|||
break;
|
||||
case COMPRESSION_ALGORITHM_IMLZMA:
|
||||
{
|
||||
UINT32 compressedSize = 0;
|
||||
QByteArray header = data.left(sizeof(EFI_COMMON_SECTION_HEADER));
|
||||
EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*)header.constData();
|
||||
UINT32 headerSize = sizeOfSectionHeader(sectionHeader);
|
||||
|
@ -2645,6 +2648,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base,
|
|||
|
||||
// Reconstruction successful
|
||||
reconstructed = header.append(reconstructed);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -3198,48 +3202,126 @@ UINT8 FfsEngine::dump(const QModelIndex & index, const QString path)
|
|||
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;
|
||||
|
||||
// Skip removed files
|
||||
// Skip removed items
|
||||
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)) {
|
||||
UINT8 result;
|
||||
|
||||
// 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);
|
||||
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);
|
||||
patched.append(body);
|
||||
return replace(index, patched, REPLACE_MODE_AS_IS);
|
||||
}
|
||||
// Patch body
|
||||
else if (mode == PATCH_MODE_BODY) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue