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

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* 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;
}