diff --git a/UEFIExtract/uefiextract_main.cpp b/UEFIExtract/uefiextract_main.cpp index 83b8c293e..5c98cc801 100644 --- a/UEFIExtract/uefiextract_main.cpp +++ b/UEFIExtract/uefiextract_main.cpp @@ -1,6 +1,6 @@ /* uefiextract_main.cpp -Copyright (c) 2015, Nikolaj Schlej. All rights reserved. +Copyright (c) 2018, LongSoft. All rights reserved. This program and the accompanying materials 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 @@ -19,8 +19,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); - a.setOrganizationName("CodeRush"); - a.setOrganizationDomain("coderush.me"); + a.setOrganizationName("LongSoft"); + a.setOrganizationDomain("longsoft.me"); a.setApplicationName("UEFIExtract"); UEFIExtract w; @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) } else { - std::cout << "UEFIExtract 0.4.4" << std::endl << std::endl << + std::cout << "UEFIExtract 0.4.5" << std::endl << std::endl << "Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl << "Returned value is a bit mask where 0 on position N meant File with GUID_N was found and unpacked, 1 otherwise" << std::endl; return 1; diff --git a/UEFIPatch/patches.txt b/UEFIPatch/patches.txt index 29d156d5f..4a78a8c80 100644 --- a/UEFIPatch/patches.txt +++ b/UEFIPatch/patches.txt @@ -34,6 +34,7 @@ F7731B4C-58A2-4DF4-8980-5645D39ECE58 10 P:0FBA6C24380F:0FBA7424380F # PowerManagement | Sandy Bridge with ME 8.xx, Ivy Bridge 8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:75080FBAE80F89442430:EB080FBAE80F89442430 + # PowerManagement | New SB-E/IB-E 8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:0FBA6C24380F:0FBA7424380F @@ -48,5 +49,12 @@ F7731B4C-58A2-4DF4-8980-5645D39ECE58 10 P:0FBA6C24380F:0FBA7424380F 299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:75080D00800000:EB080D00800000 # SiInit | Kaby Lake -299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:81E10080000033C1:9090909090909090 +299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:81E10080000033C1:9090909090909090 299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:81E10080000033C1:9090909090909090 + +# SiInit | Skylake-X +D71C8BA4-4AF2-4D0D-B1BA-F2409F0C20D3 10 P:81E10080000033C1:9090909090909090 +D71C8BA4-4AF2-4D0D-B1BA-F2409F0C20D3 12 P:81E10080000033C1:9090909090909090 + +# PpmInitialize | Skylake-X, Kaby Lake-X +3FFCAE95-23CF-4967-94F5-16352F68E43B 10 P:0FBAE80F:0FBAE00F \ No newline at end of file diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index 36d4f9943..9c2af76fd 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -1,6 +1,6 @@ /* uefipatch_main.cpp -Copyright (c) 2017, LongSoft. All rights reserved. +Copyright (c) 2018, LongSoft. All rights reserved. This program and the accompanying materials 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 @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.11 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.12 - 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; diff --git a/UEFIReplace/uefireplace_main.cpp b/UEFIReplace/uefireplace_main.cpp index 562db2250..8ec15a175 100644 --- a/UEFIReplace/uefireplace_main.cpp +++ b/UEFIReplace/uefireplace_main.cpp @@ -19,8 +19,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); - a.setOrganizationName("CodeRush"); - a.setOrganizationDomain("coderush.me"); + a.setOrganizationName("LongSoft"); + a.setOrganizationDomain("longsoft.me"); a.setApplicationName("UEFIReplace"); UEFIReplace r; @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) QStringList args = a.arguments(); if (args.length() < 5) { - std::cout << "UEFIReplace 0.3.9 - UEFI image file replacement utility" << std::endl << std::endl << + std::cout << "UEFIReplace 0.1.1 - UEFI image file replacement utility" << std::endl << std::endl << "Usage: UEFIReplace image_file guid section_type contents_file" << std::endl; return ERR_SUCCESS; } diff --git a/ffsengine.cpp b/ffsengine.cpp index 71b786c17..f9c319de4 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -871,7 +871,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent) if (msgUnknownRevision) msg(tr("parseBios: unknown volume revision %1").arg(volumeHeader->Revision), index); if (msgSizeMismach) - msg(tr("parseBios: volume size stored in header %1h differs from calculated using block map %3h") + msg(tr("parseBios: volume size stored in header %1h differs from calculated using block map %2h") .hexarg(volumeSize).arg(bmVolumeSize), index); @@ -1825,7 +1825,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c // Get TE info bool msgInvalidSignature = false; const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData(); - UINT32 teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); + + // Most EFI images today include teFixup in ImageBase value, + // which doesn't follow the UEFI spec, but is so popular that + // only a few images out of thousands are different + UINT32 teFixup = 0; //teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) { info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4); msgInvalidSignature = true; @@ -3543,18 +3547,21 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon volumeSize = newSize; } } - - // Check new volume size - if ((UINT32)(header.size() + reconstructed.size()) > volumeSize) - { - msg(tr("reconstructVolume: volume grow failed"), index); - return ERR_INVALID_VOLUME; - } } // Use current volume body - else + else { reconstructed = model->body(index); + // BUGBUG: volume size may change during this operation for volumes withour files in them + // but such volumes are fairly rare + } + + // Check new volume size + if ((UINT32)(header.size() + reconstructed.size()) != volumeSize) { + msg(tr("reconstructVolume: volume size can't be changed"), index); + return ERR_INVALID_VOLUME; + } + // Reconstruction successful reconstructed = header.append(reconstructed); @@ -3574,6 +3581,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength); } } + // Store new free space offset, if needed if (model->text(index).contains("AppleFSO ")) { // Get current CRC32 value from volume header @@ -3716,30 +3724,31 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision, offset += section.size(); } } - - // Correct file size - UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0; - if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) { - uint32ToUint24(EFI_SECTION2_IS_USED, fileHeader->Size); - EFI_FFS_FILE_HEADER2* fileHeader2 = (EFI_FFS_FILE_HEADER2*) fileHeader; - fileHeader2->ExtendedSize = sizeof(EFI_FFS_FILE_HEADER2) + reconstructed.size() + tailSize; - } else { - if (sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize > 0xFFFFFF) { - msg(tr("reconstructFile: resulting file size is too big"), index); - return ERR_INVALID_FILE; - } - uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize, fileHeader->Size); - } - - // Recalculate header checksum - fileHeader->IntegrityCheck.Checksum.Header = 0; - fileHeader->IntegrityCheck.Checksum.File = 0; - fileHeader->IntegrityCheck.Checksum.Header = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->State); } // Use current file body else reconstructed = model->body(index); + // Correct file size + UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0; + if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) { + uint32ToUint24(EFI_SECTION2_IS_USED, fileHeader->Size); + EFI_FFS_FILE_HEADER2* fileHeader2 = (EFI_FFS_FILE_HEADER2*)fileHeader; + fileHeader2->ExtendedSize = sizeof(EFI_FFS_FILE_HEADER2) + reconstructed.size() + tailSize; + } + else { + if (sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize > 0xFFFFFF) { + msg(tr("reconstructFile: resulting file size is too big"), index); + return ERR_INVALID_FILE; + } + uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize, fileHeader->Size); + } + + // Recalculate header checksum + fileHeader->IntegrityCheck.Checksum.Header = 0; + fileHeader->IntegrityCheck.Checksum.File = 0; + fileHeader->IntegrityCheck.Checksum.Header = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->State); + // Recalculate data checksum, if needed if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((const UINT8*)reconstructed.constData(), reconstructed.size()); @@ -3755,6 +3764,7 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision, UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File; reconstructed.append(ht).append(ft); } + // Set file state state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION; if (erasePolarity == ERASE_POLARITY_TRUE) @@ -3792,8 +3802,8 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, model->action(index) == Actions::Rebase) { QByteArray header = model->header(index); EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*)header.data(); - bool extended = false; - if(uint24ToUint32(commonHeader->Size) == 0xFFFFFF) { + bool extended = false; + if (uint24ToUint32(commonHeader->Size) == 0xFFFFFF) { extended = true; } @@ -3894,34 +3904,44 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, .arg(model->subtype(index)), index); return ERR_INVALID_SECTION; } - - // Correct section size - if (extended) { - EFI_COMMON_SECTION_HEADER2 * extHeader = (EFI_COMMON_SECTION_HEADER2*) commonHeader; - extHeader->ExtendedSize = header.size() + reconstructed.size(); - uint32ToUint24(0xFFFFFF, commonHeader->Size); - } else { - uint32ToUint24(header.size() + reconstructed.size(), commonHeader->Size); - } } // Leaf section - else + else { reconstructed = model->body(index); + } + + // Correct section size + if (extended) { + EFI_COMMON_SECTION_HEADER2 * extHeader = (EFI_COMMON_SECTION_HEADER2*)commonHeader; + extHeader->ExtendedSize = header.size() + reconstructed.size(); + uint32ToUint24(0xFFFFFF, commonHeader->Size); + } + else { + uint32ToUint24(header.size() + reconstructed.size(), commonHeader->Size); + } // Rebase PE32 or TE image, if needed if ((model->subtype(index) == EFI_SECTION_PE32 || model->subtype(index) == EFI_SECTION_TE) && (model->subtype(index.parent()) == EFI_FV_FILETYPE_PEI_CORE || - model->subtype(index.parent()) == EFI_FV_FILETYPE_PEIM || - model->subtype(index.parent()) == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { + model->subtype(index.parent()) == EFI_FV_FILETYPE_PEIM || + model->subtype(index.parent()) == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { UINT16 teFixup = 0; - //TODO: add proper handling - /*if (model->subtype(index) == EFI_SECTION_TE) { - const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)model->body(index).constData(); - teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); - }*/ + + // Most EFI images today include teFixup in ImageBase value, + // which doesn't follow the UEFI spec, but is so popular that + // only a few images out of thousands are different + + // There are some heuristics possible here to detect if an entry point is calculated correctly + // or needs a proper fixup, but new_engine already have them and it's better to work on proper + // builder for it than trying to fix this mess + + //if (model->subtype(index) == EFI_SECTION_TE) { + // const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)model->body(index).constData(); + // teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); + // if (base) { - result = rebase(reconstructed, base - teFixup + header.size()); + result = rebase(reconstructed, base - teFixup + header.size(), index); if (result) { msg(tr("reconstructSection: executable section rebase failed"), index); return result; @@ -4217,7 +4237,7 @@ UINT8 FfsEngine::findTextPattern(const QModelIndex & index, const QString & patt return ERR_SUCCESS; } -UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) +UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base, const QModelIndex & index) { UINT32 delta; // Difference between old and new base addresses UINT32 relocOffset; // Offset of relocation region @@ -4290,6 +4310,9 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) relocSize = teHeader->DataDirectory[EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC].Size; // Set new base teHeader->ImageBase = base; + + // Warn the user about possible outcome of incorrect rebase of TE image + msg(tr("rebase: can't determine if TE image base is adjusted or not, rebased TE image may stop working"), index); } else return ERR_UNKNOWN_IMAGE_TYPE; @@ -4319,6 +4342,12 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) // Run this relocation record while (Reloc < RelocEnd) { + if (*Reloc == 0x0000) { + // Skip last emtpy reloc entry + Reloc += 1; + continue; + } + UINT32 RelocLocation = RelocBase->VirtualAddress - teFixup + (*Reloc & 0x0FFF); if ((UINT32)file.size() < RelocLocation) return ERR_BAD_RELOCATION_ENTRY; diff --git a/ffsengine.h b/ffsengine.h index 32a88ff87..129f44b86 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -84,7 +84,6 @@ class FfsEngine : public QObject UINT8 reconstructIntelImage(const QModelIndex& index, QByteArray & reconstructed); UINT8 reconstructRegion(const QModelIndex& index, QByteArray & reconstructed, bool includeHeader = true); UINT8 reconstructPadding(const QModelIndex& index, QByteArray & reconstructed); - UINT8 reconstructBios(const QModelIndex& index, QByteArray & reconstructed); UINT8 reconstructVolume(const QModelIndex& index, QByteArray & reconstructed); UINT8 reconstructFile(const QModelIndex& index, const UINT8 revision, const UINT8 erasePolarity, const UINT32 base, QByteArray& reconstructed); UINT8 reconstructSection(const QModelIndex& index, const UINT32 base, QByteArray & reconstructed); @@ -126,7 +125,7 @@ class FfsEngine : public QObject // Rebase routines UINT8 getBase(const QByteArray& file, UINT32& base); UINT8 getEntryPoint(const QByteArray& file, UINT32 &entryPoint); - UINT8 rebase(QByteArray & executable, const UINT32 base); + UINT8 rebase(QByteArray & executable, const UINT32 base, const QModelIndex & index); void rebasePeiFiles(const QModelIndex & index); // Patch routines diff --git a/types.cpp b/types.cpp index a9a93006b..d8dd01d9e 100644 --- a/types.cpp +++ b/types.cpp @@ -69,7 +69,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype) case Types::Image: if (subtype == Subtypes::IntelImage) return QObject::tr("Intel"); - else if (Subtypes::UefiImage) + else if (subtype == Subtypes::UefiImage) return QObject::tr("UEFI"); else return QObject::tr("Unknown subtype"); @@ -153,4 +153,4 @@ QString actionTypeToQString(const UINT8 action) default: return QObject::tr("Unknown"); } -} \ No newline at end of file +} diff --git a/uefitool.cpp b/uefitool.cpp index f3c6ce310..3e9166c33 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.22.2")) +version(tr("0.22.3")) { clipboard = QApplication::clipboard();