From 92c9754c02f67932d05be451f7fea125f03000f0 Mon Sep 17 00:00:00 2001 From: cyrozap Date: Sat, 28 Mar 2015 22:15:06 -0400 Subject: [PATCH 01/22] Add Travis CI configuration --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a10dcd5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: cpp + +compiler: + - clang + - gcc + +before_install: + - sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa + - sudo apt-get update -qq + - sudo apt-get install -qq qt5-qmake qtbase5-dev qtdeclarative5-dev libqt5webkit5-dev libsqlite3-dev + +script: + - qmake uefitool.pro + - make From 351285dfbfb1d3c40d1424f2f8cdba2f463fddbe Mon Sep 17 00:00:00 2001 From: cyrozap Date: Sat, 28 Mar 2015 22:20:38 -0400 Subject: [PATCH 02/22] Fixing Travis build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a10dcd5..bd25b50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,5 @@ before_install: - sudo apt-get install -qq qt5-qmake qtbase5-dev qtdeclarative5-dev libqt5webkit5-dev libsqlite3-dev script: - - qmake uefitool.pro + - qmake -qt=qt5 uefitool.pro - make From 3013398a9d66eeecfb89d7772df5825a103950bb Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 17 May 2015 10:38:04 +0200 Subject: [PATCH 03/22] Engine 0.20.5 - raw file header was included twice during reconstruction as region --- ffsengine.cpp | 9 +++++---- ffsengine.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 2e0a8fe..0029f04 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -2740,7 +2740,7 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec return ERR_NOT_IMPLEMENTED; } -UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconstructed) +UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconstructed, bool includeHeader) { if (!index.isValid()) return ERR_SUCCESS; @@ -2790,7 +2790,8 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst } // Reconstruction successful - reconstructed = model->header(index).append(reconstructed); + if (includeHeader) + reconstructed = model->header(index).append(reconstructed); return ERR_SUCCESS; } @@ -3207,9 +3208,9 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision, if (model->rowCount(index)) { reconstructed.clear(); // Construct new file body - // File contains raw data, must be parsed as region + // File contains raw data, must be parsed as region without header if (model->subtype(index) == EFI_FV_FILETYPE_ALL || model->subtype(index) == EFI_FV_FILETYPE_RAW) { - result = reconstructRegion(index, reconstructed); + result = reconstructRegion(index, reconstructed, false); if (result) return result; } diff --git a/ffsengine.h b/ffsengine.h index 41d9e0a..281aa6e 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -81,7 +81,7 @@ public: UINT8 reconstructImageFile(QByteArray &reconstructed); UINT8 reconstruct(const QModelIndex &index, QByteArray & reconstructed); UINT8 reconstructIntelImage(const QModelIndex& index, QByteArray & reconstructed); - UINT8 reconstructRegion(const QModelIndex& index, QByteArray & reconstructed); + UINT8 reconstructRegion(const QModelIndex& index, QByteArray & reconstructed, bool includeHeader = true); 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); From d78df75de6afec0de8d7f30773ce948f43edf2b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 17 May 2015 10:39:31 +0200 Subject: [PATCH 04/22] Update version numbers --- UEFIPatch/uefipatch_main.cpp | 2 +- uefitool.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index 2ff15c9..6f37b1f 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.4 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.5 - 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/uefitool.cpp b/uefitool.cpp index 0f344f2..44eaeff 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.20.4")) +version(tr("0.20.5")) { clipboard = QApplication::clipboard(); From c5fec376f765dc2b33ab8856f96ace966a6df8a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 5 Jul 2015 13:28:53 +0200 Subject: [PATCH 05/22] Engine 0.20.6 - added support for recalculation of Apple-specific free space offset value stored in volume's ZeroVector. Thanks to osxreverser for reporting the issue #29. - ZeroVectorCRC renamed to AppleCRC32, because it's Apple-specific after all. - ParsingData handling removed from old codebase, because it's only needed for the new engine. --- ffsengine.cpp | 134 +++++++++++++++++++++++++++----------------------- treeitem.cpp | 18 +------ treeitem.h | 7 +-- treemodel.cpp | 31 +----------- treemodel.h | 2 +- types.h | 21 -------- uefitool.cpp | 2 +- 7 files changed, 78 insertions(+), 137 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 0029f04..16aea9b 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -221,7 +221,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer) .hexarg(flashImage.size()).arg(flashImage.size()); // Add tree item - index = model->addItem(Types::Image, Subtypes::UefiImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), index); + index = model->addItem(Types::Image, Subtypes::UefiImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, index); return parseBios(flashImage, index); } @@ -359,7 +359,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in .arg(descriptorMap->NumberOfIccTableEntries); // Add Intel image tree item - index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, QByteArray(), parent); + index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, parent); // Descriptor // Get descriptor info @@ -426,7 +426,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in } // Add descriptor tree item - model->addItem(Types::Region, Subtypes::DescriptorRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, QByteArray(), index); + model->addItem(Types::Region, Subtypes::DescriptorRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, index); // Sort regions in ascending order qSort(offsets); @@ -483,7 +483,7 @@ UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, con .arg(version->minor); // Add tree item - index = model->addItem(Types::Region, Subtypes::GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, QByteArray(), parent, mode); + index = model->addItem(Types::Region, Subtypes::GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, parent, mode); return ERR_SUCCESS; } @@ -532,7 +532,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const } // Add tree item - index = model->addItem(Types::Region, Subtypes::MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, QByteArray(), parent, mode); + index = model->addItem(Types::Region, Subtypes::MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, parent, mode); // Show messages if (emptyRegion) { @@ -557,7 +557,7 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con hexarg(pdr.size()).arg(pdr.size()); // Add tree item - index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent, mode); + index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, parent, mode); // Parse PDR region as BIOS space UINT8 result = parseBios(pdr, index); @@ -578,7 +578,7 @@ UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, c hexarg(bios.size()).arg(bios.size()); // Add tree item - index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent, mode); + index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, parent, mode); return parseBios(bios, index); } @@ -613,7 +613,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent) .hexarg(padding.size()).arg(padding.size()); // Add tree item - model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); + model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent); } // Search for and parse all volumes @@ -638,7 +638,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent) info = tr("Full size: %1h (%2)") .hexarg(padding.size()).arg(padding.size()); // Add tree item - model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); + model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent); } // Get volume size @@ -712,7 +712,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent) info = tr("Full size: %1h (%2)") .hexarg(padding.size()).arg(padding.size()); // Add tree item - model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); + model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent); } break; } @@ -784,12 +784,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co /*volumeFfsVersion = 2;*/ } - // Check for FFS v3 volume - /*if (FFSv3Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) { - volumeIsUnknown = false; - volumeFfsVersion = 3; - }*/ - // Check attributes // Determine value of empty byte char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; @@ -804,13 +798,20 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Check for Apple CRC32 in ZeroVector bool volumeHasZVCRC = false; + bool volumeHasZVFSO = false; UINT32 crc32FromZeroVector = *(UINT32*)(volume.constData() + 8); + UINT32 freeSpaceOffsetFromZeroVector = *(UINT32*)(volume.constData() + 12); if (crc32FromZeroVector != 0) { // Calculate CRC32 of the volume body UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength); if (crc == crc32FromZeroVector) { volumeHasZVCRC = true; } + + // Check for free space size in zero vector + if (freeSpaceOffsetFromZeroVector != 0) { + volumeHasZVFSO = true; + } } // Check header checksum by recalculating it @@ -833,11 +834,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co .arg(volumeHeader->Revision) .hexarg2(volumeHeader->Attributes, 8) .arg(empty ? "1" : "0"); - - // Apple CRC32 volume - if (volumeHasZVCRC) { - info += tr("\nCRC32 in ZeroVector: valid"); - } // Extended header present if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { @@ -847,21 +843,17 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co .arg(guidToQString(extendedHeader->FvName)); } - // Construct parsing data structure - QByteArray parsingData(sizeof(PARSING_DATA), 0); - PARSING_DATA* pdata = (PARSING_DATA*)parsingData.data(); - pdata->Type = VolumeParsingData; - pdata->Data.Volume.HasZeroVectorCRC = volumeHasZVCRC; - // Add text QString text; if (volumeHasZVCRC) - text += tr("ZeroVectorCRC "); + text += tr("AppleCRC32 "); + if (volumeHasZVFSO) + text += tr("AppleFSO "); // Add tree item QByteArray header = volume.left(headerSize); QByteArray body = volume.mid(headerSize, volumeSize - headerSize); - index = model->addItem(Types::Volume, volumeIsUnknown ? Subtypes::UnknownVolume : Subtypes::Ffs2Volume, COMPRESSION_ALGORITHM_NONE, name, text, info, header, body, parsingData, parent, mode); + index = model->addItem(Types::Volume, volumeIsUnknown ? Subtypes::UnknownVolume : Subtypes::Ffs2Volume, COMPRESSION_ALGORITHM_NONE, name, text, info, header, body, parent, mode); // Show messages if (volumeIsUnknown) { @@ -917,16 +909,16 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Add all bytes before as free space... if (i > 0) { QByteArray free = freeSpace.left(i); - model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, QByteArray(), index, mode); + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode); } // ... and all bytes after as a padding QByteArray padding = freeSpace.mid(i); - QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, QByteArray(), index, mode); + QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode); msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); } else { // Add free space element - model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, QByteArray(), index, mode); + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, index, mode); } break; // Exit from loop } @@ -951,14 +943,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) msg(tr("parseVolume: FFS file parsing failed with error \"%1\"").arg(errorMessage(result)), index); - - // Construct parsing data structure - QByteArray parsingData(sizeof(PARSING_DATA), 0); - PARSING_DATA* pdata = (PARSING_DATA*)parsingData.data(); - pdata->Type = FileParsingData; - pdata->Data.File.Offset = fileOffset; - model->setParsingData(fileIndex, parsingData); - // Show messages if (msgUnalignedFile) msg(tr("parseVolume: unaligned file %1").arg(guidToQString(fileHeader->Name)), fileIndex); @@ -1108,7 +1092,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U .hexarg2(fileHeader->State, 2); // Add tree item - index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Show messages if (msgInvalidHeaderChecksum) @@ -1137,11 +1121,11 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U // Add all bytes before as free space... if (i > 0) { QByteArray free = body.left(i); - model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, QByteArray(), index, mode); + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode); } // ... and all bytes after as a padding QByteArray padding = body.mid(i); - QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, QByteArray(), index, mode); + QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode); // Show message msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex); @@ -1348,7 +1332,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(compressedSectionHeader->UncompressedLength).arg(compressedSectionHeader->UncompressedLength); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, parent, mode); // Show message if (!parseCurrentSection) @@ -1488,7 +1472,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c } // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, parent, mode); // Show messages if (msgUnknownGuid) @@ -1527,7 +1511,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(body.size()).arg(body.size()); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Parse section body result = parseSections(body, index); @@ -1560,7 +1544,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c info += tr("\nParsed expression:%1").arg(str); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Show messages if (msgDepexParseFailed) @@ -1600,7 +1584,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(teHeader->ImageBase + teHeader->AddressOfEntryPoint - teFixup); } // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Show messages if (msgInvalidSignature) { @@ -1683,7 +1667,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c } // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Show messages if (msgInvalidDosSignature) { @@ -1719,7 +1703,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(body.size()).arg(body.size()); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); } break; case EFI_SECTION_FREEFORM_SUBTYPE_GUID: { @@ -1736,7 +1720,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .arg(guidToQString(fsgHeader->SubTypeGuid)); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Rename section model->setName(index, guidToQString(fsgHeader->SubTypeGuid)); @@ -1758,7 +1742,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .arg(QString::fromUtf16((const ushort*)body.constData())); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); } break; case EFI_SECTION_USER_INTERFACE: { @@ -1775,7 +1759,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .arg(text); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Rename parent file model->setText(model->findParentOfType(parent, Types::File), text); @@ -1793,7 +1777,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(body.size()).arg(body.size()); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Parse section body as BIOS space result = parseBios(body, index); @@ -1846,7 +1830,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c } // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Parse section body as BIOS space if (!parsed) { @@ -1874,7 +1858,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(postcodeHeader->Postcode); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); } break; default: @@ -1888,7 +1872,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c .hexarg(body.size()).arg(body.size()); // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); msg(tr("parseSection: section with unknown type %1h").hexarg2(sectionHeader->Type, 2), index); } return ERR_SUCCESS; @@ -2829,6 +2813,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon UINT32 volumeSize = header.size() + body.size(); // Reconstruct volume body + UINT32 freeSpaceOffset = 0; if (model->rowCount(index)) { reconstructed.clear(); UINT8 polarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE; @@ -3007,6 +2992,17 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon return ERR_INVALID_VOLUME; } + // Check for free space offset in ZeroVector + if (model->text(index).contains("AppleFSO ")) { + // Align current offset to 8 byte boundary + UINT32 alignment = offset % 8; + freeSpaceOffset = model->header(index).size() + offset; + if (alignment) { + alignment = 8 - alignment; + freeSpaceOffset += alignment; + } + } + // Insert VTF or non-UEFI data to it's correct place if (!vtf.isEmpty()) { // VTF found // Determine correct VTF offset @@ -3108,22 +3104,36 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon reconstructed = header.append(reconstructed); // Recalculate CRC32 in ZeroVector, if needed - const PARSING_DATA* pdata = (const PARSING_DATA*)model->parsingData(index).constData(); - if (pdata->Type == VolumeParsingData && pdata->Data.Volume.HasZeroVectorCRC) { + if (model->text(index).contains("AppleCRC32 ")) { // Get current CRC32 value from volume header - const UINT32 current = *(const UINT32*)(reconstructed.constData() + 8); + const UINT32 currentCrc = *(const UINT32*)(reconstructed.constData() + 8); // Calculate new value UINT32 crc = crc32(0, (const UINT8*)reconstructed.constData() + volumeHeader->HeaderLength, reconstructed.size() - volumeHeader->HeaderLength); // Update the value - if (current != crc) { + if (currentCrc != crc) { *(UINT32*)(reconstructed.data() + 8) = crc; - // Recalculate header checksum again + // Recalculate header checksum volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)reconstructed.data(); volumeHeader->Checksum = 0; 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 + const UINT32 currentFso = *(const UINT32*)(reconstructed.constData() + 12); + // Update the value + if (freeSpaceOffset != 0 && currentFso != freeSpaceOffset) { + *(UINT32*)(reconstructed.data() + 12) = freeSpaceOffset; + + // Recalculate header checksum + volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)reconstructed.data(); + volumeHeader->Checksum = 0; + volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength); + } + } + return ERR_SUCCESS; } diff --git a/treeitem.cpp b/treeitem.cpp index 94514dd..925d95b 100644 --- a/treeitem.cpp +++ b/treeitem.cpp @@ -17,7 +17,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compression, const QString & name, const QString & text, const QString & info, - const QByteArray & header, const QByteArray & body, const QByteArray & parsingData, + const QByteArray & header, const QByteArray & body, TreeItem *parent) : itemAction(Actions::NoAction), itemType(type), @@ -28,7 +28,6 @@ TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compressio itemInfo(info), itemHeader(header), itemBody(body), - itemParsingData(parsingData), parentItem(parent) { } @@ -184,11 +183,6 @@ QByteArray TreeItem::body() const return itemBody; } -QByteArray TreeItem::parsingData() const -{ - return itemParsingData; -} - bool TreeItem::hasEmptyHeader() const { return itemHeader.isEmpty(); @@ -199,16 +193,6 @@ bool TreeItem::hasEmptyBody() const return itemBody.isEmpty(); } -bool TreeItem::hasEmptyParsingData() const -{ - return itemParsingData.isEmpty(); -} - -void TreeItem::setParsingData(const QByteArray & data) -{ - itemParsingData = data; -} - UINT8 TreeItem::action() const { return itemAction; diff --git a/treeitem.h b/treeitem.h index 8697a75..58015f4 100644 --- a/treeitem.h +++ b/treeitem.h @@ -26,7 +26,7 @@ class TreeItem public: TreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE, const QString &name = QString(), const QString &text = QString(), const QString &info = QString(), - const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & parsingData = QByteArray(), + const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), TreeItem *parent = 0); ~TreeItem(); @@ -63,10 +63,6 @@ public: QByteArray body() const; bool hasEmptyBody() const; - QByteArray parsingData() const; - bool hasEmptyParsingData() const; - void setParsingData(const QByteArray & data); - QString info() const; void addInfo(const QString &info); void setInfo(const QString &info); @@ -87,7 +83,6 @@ private: QString itemInfo; QByteArray itemHeader; QByteArray itemBody; - QByteArray itemParsingData; TreeItem *parentItem; }; diff --git a/treemodel.cpp b/treemodel.cpp index ef83561..a82724b 100644 --- a/treemodel.cpp +++ b/treemodel.cpp @@ -178,22 +178,6 @@ bool TreeModel::hasEmptyBody(const QModelIndex &index) const return item->hasEmptyBody(); } -QByteArray TreeModel::parsingData(const QModelIndex &index) const -{ - if (!index.isValid()) - return QByteArray(); - TreeItem *item = static_cast(index.internalPointer()); - return item->parsingData(); -} - -bool TreeModel::hasEmptyParsingData(const QModelIndex &index) const -{ - if (!index.isValid()) - return true; - TreeItem *item = static_cast(index.internalPointer()); - return item->hasEmptyParsingData(); -} - QString TreeModel::name(const QModelIndex &index) const { if (!index.isValid()) @@ -284,20 +268,9 @@ void TreeModel::setAction(const QModelIndex &index, const UINT8 action) emit dataChanged(this->index(0, 0), index); } -void TreeModel::setParsingData(const QModelIndex &index, const QByteArray &data) -{ - if (!index.isValid()) - return; - - TreeItem *item = static_cast(index.internalPointer()); - item->setParsingData(data); - emit dataChanged(this->index(0, 0), index); -} - QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT8 compression, const QString & name, const QString & text, const QString & info, - const QByteArray & header, const QByteArray & body, const QByteArray & parsingData, - const QModelIndex & parent, const UINT8 mode) + const QByteArray & header, const QByteArray & body, const QModelIndex & parent, const UINT8 mode) { TreeItem *item = 0; TreeItem *parentItem = 0; @@ -318,7 +291,7 @@ QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT } } - TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, parsingData, parentItem); + TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, parentItem); if (mode == CREATE_MODE_APPEND) { emit layoutAboutToBeChanged(); parentItem->appendChild(newItem); diff --git a/treemodel.h b/treemodel.h index 3c8c210..ae9c717 100644 --- a/treemodel.h +++ b/treemodel.h @@ -65,7 +65,7 @@ public: QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE, const QString & name = QString(), const QString & text = QString(), const QString & info = QString(), - const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & parsingData = QByteArray(), + const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); QModelIndex findParentOfType(const QModelIndex & index, UINT8 type) const; diff --git a/types.h b/types.h index a65b73e..ec605b4 100644 --- a/types.h +++ b/types.h @@ -85,25 +85,4 @@ extern QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype); extern QString compressionTypeToQString(const UINT8 algorithm); extern QString regionTypeToQString(const UINT8 type); -enum ParsingDataTypes { - UnknownParsingData, - VolumeParsingData, - FileParsingData -}; - -typedef union _PARSING_DATA_UNION { - struct _PARSING_DATA_UNION_VOLUME { - bool HasZeroVectorCRC; - } Volume; - - struct _PARSING_DATA_UNION_FILE { - UINT32 Offset; - } File; -} PARSING_DATA_UNION; - -typedef struct _PARSING_DATA { - UINT8 Type; - PARSING_DATA_UNION Data; -} PARSING_DATA; - #endif \ No newline at end of file diff --git a/uefitool.cpp b/uefitool.cpp index 44eaeff..4ff8781 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.20.5")) +version(tr("0.20.6")) { clipboard = QApplication::clipboard(); From 1109e4437909a91032e7278222140b51e14b0304 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Tue, 11 Aug 2015 18:12:12 +0200 Subject: [PATCH 06/22] Create LICENSE.md --- LICENSE.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3f16459 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,23 @@ +Copyright (c) 2015, Nikolaj Schlej +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 63e5a4dd1cf187fe6b62bd0da60529746f2ff7a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Thu, 13 Aug 2015 20:28:10 +0200 Subject: [PATCH 07/22] UT 0.20.7 - added "Open in new window..." action --- uefitool.cpp | 20 +++++++++++++++++--- uefitool.h | 4 ++++ uefitool.ui | 12 ++++++++++++ uefitool_main.cpp | 1 + 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/uefitool.cpp b/uefitool.cpp index 4ff8781..14b2e56 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.20.6")) +version(tr("0.20.7")) { clipboard = QApplication::clipboard(); @@ -31,6 +31,7 @@ version(tr("0.20.6")) // Connect signals to slots connect(ui->actionOpenImageFile, SIGNAL(triggered()), this, SLOT(openImageFile())); + connect(ui->actionOpenImageFileInNewWindow, SIGNAL(triggered()), this, SLOT(openImageFileInNewWindow())); connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile())); connect(ui->actionSearch, SIGNAL(triggered()), this, SLOT(search())); connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extractAsIs())); @@ -83,6 +84,11 @@ UEFITool::~UEFITool() delete searchDialog; } +void UEFITool::setProgramPath(QString path) +{ + currentProgramPath = path; +}; + void UEFITool::init() { // Clear components @@ -358,6 +364,8 @@ void UEFITool::replace(const UINT8 mode) path = QFileDialog::getOpenFileName(this, tr("Select volume file to replace body"), currentDir, "Volume files (*.vol *.bin);;All files (*)"); else if (model->subtype(index) == EFI_SECTION_RAW) path = QFileDialog::getOpenFileName(this, tr("Select raw file to replace body"), currentDir, "Raw files (*.raw *.bin);;All files (*)"); + else if (model->subtype(index) == EFI_SECTION_PE32 || model->subtype(index) == EFI_SECTION_TE || model->subtype(index) == EFI_SECTION_PIC) + path = QFileDialog::getOpenFileName(this, tr("Select EFI executable file to replace body"), currentDir, "EFI executable files (*.efi *.dxe *.pei *.bin);;All files (*)"); else path = QFileDialog::getOpenFileName(this, tr("Select file to replace body"), currentDir, "Binary files (*.bin);;All files (*)"); } @@ -521,7 +529,7 @@ void UEFITool::exit() void UEFITool::saveImageFile() { - QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi *.dec);;All files (*)"); + QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)"); if (path.isEmpty()) return; @@ -552,10 +560,16 @@ void UEFITool::saveImageFile() void UEFITool::openImageFile() { - QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi *.dec);;All files (*)"); + QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)"); openImageFile(path); } +void UEFITool::openImageFileInNewWindow() +{ + QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)"); + QProcess::startDetached(currentProgramPath, QStringList(path)); +} + void UEFITool::openImageFile(QString path) { if (path.trimmed().isEmpty()) diff --git a/uefitool.h b/uefitool.h index dda7fdc..edac83b 100644 --- a/uefitool.h +++ b/uefitool.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ public: ~UEFITool(); void openImageFile(QString path); + void setProgramPath(QString path); private slots: void init(); @@ -58,6 +60,7 @@ public: void scrollTreeView(QListWidgetItem* item); void openImageFile(); + void openImageFileInNewWindow(); void saveImageFile(); void search(); @@ -95,6 +98,7 @@ private: SearchDialog* searchDialog; QClipboard* clipboard; QString currentDir; + QString currentProgramPath; QQueue messageItems; const QString version; diff --git a/uefitool.ui b/uefitool.ui index 82868da..5b5953a 100644 --- a/uefitool.ui +++ b/uefitool.ui @@ -188,6 +188,7 @@ &File + @@ -522,6 +523,17 @@ Ctrl+Alt+C + + + &Open image file in new window... + + + Open image file in new window + + + Ctrl+Shift+O + + diff --git a/uefitool_main.cpp b/uefitool_main.cpp index e5764c0..a9ac03a 100644 --- a/uefitool_main.cpp +++ b/uefitool_main.cpp @@ -23,6 +23,7 @@ int main(int argc, char *argv[]) a.setApplicationName("UEFITool"); UEFITool w; + w.setProgramPath(a.arguments().at(0)); if (a.arguments().length() > 1) w.openImageFile(a.arguments().at(1)); w.show(); From 9c4ddbec6218302e86955cfc53e7dfcc8f858eca Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 30 Aug 2015 10:52:19 +0200 Subject: [PATCH 08/22] UT 0.20.8 - data after the latest region of Intel image is in tree now - added Intel, Lenovo and Toshiba-specific capsule GUIDs to the list of known GUIDs - fixed bogus "File with invalid size" message while working on almost full volumes - pressing Cancel on "Open in new window" dialog now works as expected Big thanks to Lordkag for spotting most of the issues (#31). --- basetypes.h | 1 + ffs.h | 32 ++++++++-- ffsengine.cpp | 160 ++++++++++++++++++++++++++++++++++++-------------- types.cpp | 12 ++-- types.h | 3 +- uefitool.cpp | 12 ++-- 6 files changed, 159 insertions(+), 61 deletions(-) diff --git a/basetypes.h b/basetypes.h index 083267b..e8589ad 100644 --- a/basetypes.h +++ b/basetypes.h @@ -85,6 +85,7 @@ typedef unsigned int UINTN; #define ERR_INVALID_SYMBOL 40 #define ERR_NOTHING_TO_PATCH 41 #define ERR_DEPEX_PARSE_FAILED 42 +#define ERR_TRUNCATED_IMAGE 43 #define ERR_NOT_IMPLEMENTED 0xFF // UDK porting definitions diff --git a/ffs.h b/ffs.h index 8b7da95..0bb8221 100644 --- a/ffs.h +++ b/ffs.h @@ -32,7 +32,7 @@ extern QString sectionTypeToQString(const UINT8 type); //***************************************************************************** // EFI Capsule //***************************************************************************** -// Capsule header +// Standard EFI Capsule header typedef struct _EFI_CAPSULE_HEADER { EFI_GUID CapsuleGuid; UINT32 HeaderSize; @@ -49,16 +49,36 @@ typedef struct _EFI_CAPSULE_HEADER { const QByteArray EFI_CAPSULE_GUID ("\xBD\x86\x66\x3B\x76\x0D\x30\x40\xB7\x0E\xB5\x51\x9E\x2F\xC5\xA0", 16); +// Intel capsule GUID +const QByteArray INTEL_CAPSULE_GUID +("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16); + +// Lenovo capsule GUID +const QByteArray LENOVO_CAPSULE_GUID +("\x8B\xA6\x3C\x4A\x23\x77\xFB\x48\x80\x3D\x57\x8C\xC1\xFE\xC4\x4D", 16); + +// Toshiba EFI Capsule header +typedef struct _TOSHIBA_CAPSULE_HEADER { + EFI_GUID CapsuleGuid; + UINT32 HeaderSize; + UINT32 FullSize; + UINT32 Flags; +} TOSHIBA_CAPSULE_HEADER; + +// Toshiba capsule GUID +const QByteArray TOSHIBA_CAPSULE_GUID +("\x62\x70\xE0\x3B\x51\x1D\xD2\x45\x83\x2B\xF0\x93\x25\x7E\xD4\x61", 16); + // AMI Aptio extended capsule header typedef struct _APTIO_CAPSULE_HEADER { EFI_CAPSULE_HEADER CapsuleHeader; - UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of + UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of // the capsule volume //!TODO: Enable certificate and ROM layout reading - //UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume + //UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume // that are included in the signature calculation //FW_CERTIFICATE FWCert; - //ROM_AREA RomAreaMap[1]; + //ROM_AREA RomAreaMap[1]; } APTIO_CAPSULE_HEADER; // AMI Aptio signed extended capsule GUID @@ -252,8 +272,8 @@ extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize); // Integrity check typedef union { struct { - UINT8 Header; - UINT8 File; + UINT8 Header; + UINT8 File; } Checksum; UINT16 TailReference; // Revision 1 UINT16 Checksum16; // Revision 2 diff --git a/ffsengine.cpp b/ffsengine.cpp index 16aea9b..d516019 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -75,6 +75,7 @@ QString errorMessage(UINT8 errorCode) case ERR_INVALID_SYMBOL: return QObject::tr("Invalid symbol"); case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch"); case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed"); + case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated"); default: return QObject::tr("Unknown error %1").arg(errorCode); } } @@ -146,14 +147,16 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer) // Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) { - msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER))); + msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER))); return ERR_INVALID_PARAMETER; } // Check buffer for being normal EFI capsule header UINT32 capsuleHeaderSize = 0; QModelIndex index; - if (buffer.startsWith(EFI_CAPSULE_GUID)) { + if (buffer.startsWith(EFI_CAPSULE_GUID) + || buffer.startsWith(INTEL_CAPSULE_GUID) + || buffer.startsWith(LENOVO_CAPSULE_GUID)) { // Get info const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData(); capsuleHeaderSize = capsuleHeader->HeaderSize; @@ -170,7 +173,24 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer) // Add tree item index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body); } + // Check buffer for being Toshiba capsule header + else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) { + // Get info + const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)buffer.constData(); + capsuleHeaderSize = capsuleHeader->HeaderSize; + QByteArray header = buffer.left(capsuleHeaderSize); + QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize); + QString name = tr("UEFI capsule"); + QString info = tr("Capsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h") + .arg(guidToQString(capsuleHeader->CapsuleGuid)) + .hexarg(buffer.size()).arg(buffer.size()) + .hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize) + .hexarg(capsuleHeader->FullSize - capsuleHeader->HeaderSize).arg(capsuleHeader->FullSize - capsuleHeader->HeaderSize) + .hexarg2(capsuleHeader->Flags, 8); + // Add tree item + index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body); + } // Check buffer for being extended Aptio signed capsule header else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) { // Get info @@ -192,7 +212,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer) // Add tree item index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body); - + // Show message about possible Aptio signature break if (signedCapsule) { msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index); @@ -458,6 +478,34 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in return result; } + // Add the data after the last region as padding + UINT32 IntelDataEnd = 0; + UINT32 LastRegionOffset = offsets.last(); + if (LastRegionOffset == gbeBegin) + IntelDataEnd = gbeEnd; + else if (LastRegionOffset == meBegin) + IntelDataEnd = meEnd; + else if (LastRegionOffset == biosBegin) + IntelDataEnd = biosEnd; + else if (LastRegionOffset == pdrBegin) + IntelDataEnd = pdrEnd; + + if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated + msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged") + .hexarg(intelImage.size()).arg(intelImage.size()) + .hexarg(IntelDataEnd).arg(IntelDataEnd), index); + return ERR_TRUNCATED_IMAGE; + } + else if (IntelDataEnd < (UINT32)intelImage.size()) { // Insert padding + QByteArray padding = bios.right(intelImage.size() - IntelDataEnd); + // Get info + name = tr("Padding"); + info = tr("Full size: %1h (%2)") + .hexarg(padding.size()).arg(padding.size()); + // Add tree item + model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, index); + } + return ERR_SUCCESS; } @@ -495,7 +543,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const return ERR_EMPTY_REGION; // Get info - QString name = tr("ME/TXE region"); + QString name = tr("ME region"); QString info = tr("Full size: %1h (%2)"). hexarg(me.size()).arg(me.size()); @@ -536,10 +584,10 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const // Show messages if (emptyRegion) { - msg(tr("parseRegion: ME/TXE region is empty"), index); + msg(tr("parseRegion: ME region is empty"), index); } else if (!versionFound) { - msg(tr("parseRegion: ME/TXE region version is unknown, it can be damaged"), index); + msg(tr("parseRegion: ME region version is unknown, it can be damaged"), index); } return ERR_SUCCESS; @@ -611,7 +659,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent) name = tr("Padding"); info = tr("Full size: %1h (%2)") .hexarg(padding.size()).arg(padding.size()); - + // Add tree item model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent); } @@ -777,7 +825,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Check for volume structure to be known bool volumeIsUnknown = true; /*UINT8 volumeFfsVersion = 0;*/ - + // Check for FFS v2 volume if (FFSv2Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) { volumeIsUnknown = false; @@ -864,7 +912,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co if (msgInvalidChecksum) { msg(tr("parseVolume: volume header checksum is invalid"), index); } - + // Search for and parse all files UINT32 fileOffset = headerSize; UINT32 fileSize; @@ -874,6 +922,22 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co bool msgUnalignedFile = false; bool msgDuplicateGuid = false; + // Check if it's possibly the latest file in the volume + if (volumeSize - fileOffset < sizeof(EFI_FFS_FILE_HEADER)) { + // No files are possible after this point + // All the rest is either free space or non-UEFI data + QByteArray rest = volume.right(volumeSize - fileOffset); + if (rest.count(empty) == rest.size()) { // It's a free space + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode); + } + else { //It's non-UEFI data + QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode); + msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); + } + // Exit from loop + break; + } + result = getFileSize(volume, fileOffset, fileSize); if (result) return result; @@ -907,7 +971,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co i = ALIGN8(i) - 8; // Add all bytes before as free space... - if (i > 0) { + if (i > 0) { QByteArray free = freeSpace.left(i); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode); } @@ -1079,7 +1143,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U QString info; if (fileHeader->Type != EFI_FV_FILETYPE_PAD) name = guidToQString(fileHeader->Name); - else + else name = parseAsNonEmptyPadFile ? tr("Non-empty pad-file") : tr("Pad-file"); info = tr("File GUID: %1\nType: %2h\nAttributes: %3h\nFull size: %4h (%5)\nHeader size: %6h (%7)\nBody size: %8h (%9)\nState: %10h") @@ -1103,7 +1167,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U msg(tr("parseFile: invalid tail value"), index); if (msgInvalidType) msg(tr("parseFile: unknown file type %1h").arg(fileHeader->Type, 2), index); - + // No parsing needed if (!parseCurrentFile) return ERR_SUCCESS; @@ -1126,10 +1190,10 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U // ... and all bytes after as a padding QByteArray padding = body.mid(i); QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode); - + // Show message msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex); - + return ERR_SUCCESS; } @@ -1211,7 +1275,7 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed) const EFI_GUID * guid; const UINT8* current = (const UINT8*)body.constData(); - + // Special cases of first opcode switch (*current) { case EFI_DEP_BEFORE: @@ -1241,7 +1305,7 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed) break; } - // Parse the rest of depex + // Parse the rest of depex while (current - (const UINT8*)body.constData() < body.size()) { switch (*current) { case EFI_DEP_BEFORE: @@ -1287,9 +1351,9 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed) return ERR_DEPEX_PARSE_FAILED; } break; - default: - return ERR_DEPEX_PARSE_FAILED; - break; + default: + return ERR_DEPEX_PARSE_FAILED; + break; } } @@ -1379,11 +1443,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c // Tiano compressed section if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) { algorithm = COMPRESSION_ALGORITHM_UNKNOWN; - + result = decompress(body, EFI_STANDARD_COMPRESSION, processed, &algorithm); if (result) parseCurrentSection = false; - + if (algorithm == COMPRESSION_ALGORITHM_TIANO) { info += tr("\nCompression type: Tiano"); info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length()); @@ -1392,17 +1456,17 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c info += tr("\nCompression type: EFI 1.1"); info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length()); } - else + else info += tr("\nCompression type: unknown"); } // LZMA compressed section else if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) { algorithm = COMPRESSION_ALGORITHM_UNKNOWN; - + result = decompress(body, EFI_CUSTOMIZED_COMPRESSION, processed, &algorithm); if (result) parseCurrentSection = false; - + if (algorithm == COMPRESSION_ALGORITHM_LZMA) { info += tr("\nCompression type: LZMA"); info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length()); @@ -1570,7 +1634,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) { info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4); msgInvalidSignature = true; - } + } else { info += tr("\nSignature: %1h\nMachine type: %2\nNumber of sections: %3\nSubsystem: %4h\nStrippedSize: %5h (%6)\nBaseOfCode: %7h\nRelativeEntryPoint: %8h\nImageBase: %9h\nEntryPoint: %10h") .hexarg2(teHeader->Signature, 4) @@ -1833,7 +1897,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); // Parse section body as BIOS space - if (!parsed) { + if (!parsed) { result = parseBios(body, index); if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) { msg(tr("parseSection: parsing raw section as BIOS failed with error \"%1\"").arg(errorMessage(result)), index); @@ -1922,7 +1986,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte } else if (type == Types::Volume) { QByteArray volume; - if (header.isEmpty()) // Whole volume + if (header.isEmpty()) // Whole volume volume.append(body); else { // Body only volume.append(model->header(index)).append(body); @@ -1936,7 +2000,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte result = parseVolume(volume, fileIndex, index, mode); if (result) return result; - + // Set action model->setAction(fileIndex, action); } @@ -1954,7 +2018,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte QByteArray newHeader = header; EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)newHeader.data(); - + // Correct file size UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof(UINT16) : 0; uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + body.size() + tailSize, fileHeader->Size); @@ -2478,7 +2542,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA return ERR_STANDARD_COMPRESSION_FAILED; } compressedData = QByteArray((const char*)compressed, compressedSize); - + // Check that compressed data can be decompressed normally QByteArray decompressed; if (decompress(compressedData, EFI_STANDARD_COMPRESSION, decompressed, NULL) == ERR_SUCCESS @@ -2498,7 +2562,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA return ERR_STANDARD_COMPRESSION_FAILED; } compressedData = QByteArray((const char*)compressed, compressedSize); - + // New functions will be trusted here, because another check will reduce performance delete[] compressed; return ERR_SUCCESS; @@ -2657,12 +2721,20 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec char empty = '\xFF'; for (int i = 1; i < model->rowCount(index); i++) { QByteArray region; + + // Padding after the end of all Intel regions + if (model->type(index.child(i, 0)) == Types::Padding) { + region = model->body(index.child(i, 0)); + reconstructed.append(region); + offset += region.size(); + continue; + } + result = reconstructRegion(index.child(i, 0), region); if (result) return result; - UINT8 type = model->subtype(index.child(i, 0)); - switch (type) + switch (model->subtype(index.child(i, 0))) { case Subtypes::GbeRegion: gbe = region; @@ -2761,7 +2833,7 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst if (reconstructed.size() > model->body(index).size()) { msg(tr("reconstructRegion: reconstructed region size %1h (%2) is bigger then original %3h (%4)") .hexarg(reconstructed.size()).arg(reconstructed.size()) - .hexarg(model->body(index).size()).arg(reconstructed.size()), + .hexarg(model->body(index).size()).arg(reconstructed.size()), index); return ERR_INVALID_PARAMETER; } @@ -2799,7 +2871,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon reconstructed.clear(); return ERR_SUCCESS; } - else if (model->action(index) == Actions::Replace || + else if (model->action(index) == Actions::Replace || model->action(index) == Actions::Rebuild) { QByteArray header = model->header(index); QByteArray body = model->body(index); @@ -2811,7 +2883,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon // Get volume size UINT32 volumeSize = header.size() + body.size(); - + // Reconstruct volume body UINT32 freeSpaceOffset = 0; if (model->rowCount(index)) { @@ -2926,7 +2998,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon // Pad file if (fileHeader->Type == EFI_FV_FILETYPE_PAD) { padFileGuid = file.left(sizeof(EFI_GUID)); - + // Parse non-empty pad file if (model->rowCount(index.child(i, 0))) { //TODO: handle it @@ -2981,7 +3053,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon // Get non-UEFI data and it's offset nonUefiData = model->body(index.child(i + 1, 0)); nonUefiDataOffset = body.size() - nonUefiData.size(); - break; + break; } } } @@ -3133,7 +3205,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength); } } - + return ERR_SUCCESS; } @@ -3435,7 +3507,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, 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()); if (result) { @@ -3966,7 +4038,7 @@ UINT8 FfsEngine::getBase(const QByteArray& file, UINT32& base) // Populate TE header const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)file.constData(); //!TODO: add handling - base = teHeader->ImageBase; + base = teHeader->ImageBase; } return ERR_SUCCESS; @@ -4041,10 +4113,10 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path, return ERR_INVALID_PARAMETER; QDir dir; - if (guid.isEmpty() || + if (guid.isEmpty() || guidToQString(*(const EFI_GUID*)model->header(index).constData()) == guid || guidToQString(*(const EFI_GUID*)model->header(model->findParentOfType(index, Types::File)).constData()) == guid) { - + if (dir.cd(path)) return ERR_DIR_ALREADY_EXIST; @@ -4079,7 +4151,7 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path, file.write(info.toLatin1()); file.close(); dumped = true; - } + } UINT8 result; for (int i = 0; i < model->rowCount(index); i++) { diff --git a/types.cpp b/types.cpp index 5904e9e..17ca51f 100644 --- a/types.cpp +++ b/types.cpp @@ -24,7 +24,7 @@ QString regionTypeToQString(const UINT8 type) case Subtypes::GbeRegion: return QObject::tr("GbE"); case Subtypes::MeRegion: - return QObject::tr("ME/TXE"); + return QObject::tr("ME"); case Subtypes::BiosRegion: return QObject::tr("BIOS"); case Subtypes::PdrRegion: @@ -80,7 +80,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype) return QObject::tr("Non-empty"); else return QObject::tr("Unknown subtype"); - case Types::Volume: + case Types::Volume: if (subtype == Subtypes::UnknownVolume) return QObject::tr("Unknown"); else if (subtype == Subtypes::Ffs2Volume) @@ -89,14 +89,16 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype) return QObject::tr("FFSv3"); else return QObject::tr("Unknown subtype"); - case Types::Capsule: + case Types::Capsule: if (subtype == Subtypes::AptioSignedCapsule) return QObject::tr("Aptio signed"); else if (subtype == Subtypes::AptioUnsignedCapsule) return QObject::tr("Aptio unsigned"); else if (subtype == Subtypes::UefiCapsule) - return QObject::tr("UEFI 2.0 "); - else + return QObject::tr("UEFI 2.0"); + else if (subtype == Subtypes::ToshibaCapsule) + return QObject::tr("Toshiba"); + else return QObject::tr("Unknown subtype"); case Types::Region: return regionTypeToQString(subtype); diff --git a/types.h b/types.h index ec605b4..64df300 100644 --- a/types.h +++ b/types.h @@ -54,7 +54,8 @@ namespace Subtypes { enum CapsuleSubtypes { AptioSignedCapsule = 80, AptioUnsignedCapsule, - UefiCapsule + UefiCapsule, + ToshibaCapsule }; enum VolumeSubtypes { diff --git a/uefitool.cpp b/uefitool.cpp index 14b2e56..5a4ef55 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -16,8 +16,8 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), -ui(new Ui::UEFITool), -version(tr("0.20.7")) +ui(new Ui::UEFITool), +version(tr("0.20.8")) { clipboard = QApplication::clipboard(); @@ -85,8 +85,8 @@ UEFITool::~UEFITool() } void UEFITool::setProgramPath(QString path) -{ - currentProgramPath = path; +{ + currentProgramPath = path; }; void UEFITool::init() @@ -455,7 +455,7 @@ void UEFITool::extract(const UINT8 mode) case Types::Capsule: path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), currentDir, "Image files (*.rom *.bin);;All files (*)"); break; - case Types::Volume: + case Types::Volume: path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), currentDir, "Volume body files (*.vbd *.bin);;All files (*)"); break; case Types::File: { @@ -567,6 +567,8 @@ void UEFITool::openImageFile() void UEFITool::openImageFileInNewWindow() { QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)"); + if (path.trimmed().isEmpty()) + return; QProcess::startDetached(currentProgramPath, QStringList(path)); } From aa80837bf5ce68af01f1f432011b546cd8762bef Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 6 Sep 2015 23:46:26 +0200 Subject: [PATCH 09/22] UT 0.21.0 - added support for new Intel descriptor type, based on [this](http://review.coreboot.org/gitweb?p=coreboot.git;a=commit;h=1f7fd720c81755144423f2d4062c39cc651adc0a) coreboot commit, thanks to lordkag for issue #32 - solved a bug with incorrect volume free space item placement during volume replace, now works as expected - solved an issue with incorrect Aptio capsule parsing introduced in 0.20.8 --- descriptor.h | 131 ++++++++++++++-------- ffs.h | 4 - ffsengine.cpp | 292 +++++++++++++++++++++++++++++++++++++------------- ffsengine.h | 1 + types.cpp | 2 + types.h | 3 +- uefitool.cpp | 2 +- 7 files changed, 309 insertions(+), 126 deletions(-) diff --git a/descriptor.h b/descriptor.h index 82ff6da..989761b 100644 --- a/descriptor.h +++ b/descriptor.h @@ -17,7 +17,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "basetypes.h" // Make sure we use right packing rules -#pragma pack(push,1) +#pragma pack(push, 1) // Flash descriptor header typedef struct _FLASH_DESCRIPTOR_HEADER { @@ -34,37 +34,38 @@ typedef struct _FLASH_DESCRIPTOR_HEADER { // Descriptor map // Base fields are storing bits [11:4] of actual base addresses, all other bits are 0 typedef struct _FLASH_DESCRIPTOR_MAP { - UINT8 ComponentBase; // 0x03 on most machines - UINT8 NumberOfFlashChips; // Zero-based number of flash chips installed on board - UINT8 RegionBase; // 0x04 on most machines - UINT8 NumberOfRegions; // Zero-based number of flash regions (descriptor is always included) - UINT8 MasterBase; // 0x06 on most machines - UINT8 NumberOfMasters; // Zero-based number of flash masters - UINT8 PchStrapsBase; // 0x10 on most machines - UINT8 NumberOfPchStraps; // One-based number of UINT32s to read as PCH Straps, min=0, max=255 (1 Kb) - UINT8 ProcStrapsBase; // 0x20 on most machines - UINT8 NumberOfProcStraps; // Number of PROC straps to be read, can be 0 or 1 - UINT8 IccTableBase; // 0x21 on most machines - UINT8 NumberOfIccTableEntries; // 0x00 on most machines - UINT8 DmiTableBase; // 0x25 on most machines - UINT8 NumberOfDmiTableEntries; // 0x00 on most machines - UINT16 ReservedZero; // Still unknown, zeros in all descriptors I have seen + // FLMAP0 + UINT32 ComponentBase : 8; + UINT32 NumberOfFlashChips : 2; // Zero-based number of flash chips installed on board + UINT32 : 6; + UINT32 RegionBase : 8; + UINT32 : 8; + // FLMAP 1 + UINT32 MasterBase : 8; + UINT32 NumberOfMasters : 2; + UINT32 : 6; + UINT32 PchStrapsBase : 8; + UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb) + // FLMAP 2 + UINT32 ProcStrapsBase : 8; + UINT32 NumberOfProcStraps : 8; // One-based number of UINT32s to read as processor straps, min=0, max=255 (1 Kb) + UINT32: 16; } FLASH_DESCRIPTOR_MAP; // Component section // Flash parameters DWORD structure typedef struct _FLASH_PARAMETERS { - UINT8 FirstChipDensity : 3; - UINT8 SecondChipDensity : 3; - UINT8 ReservedZero0 : 2; // Still unknown, zeros in all descriptors I have seen - UINT8 ReservedZero1 : 8; // Still unknown, zeros in all descriptors I have seen - UINT8 ReservedZero2 : 4; // Still unknown, zeros in all descriptors I have seen + UINT8 FirstChipDensity : 4; + UINT8 SecondChipDensity : 4; + UINT8 : 8; + UINT8 : 1; + UINT8 ReadClockFreqency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors and 17 Mhz (110b) in v2 ones UINT8 FastReadEnabled : 1; UINT8 FastReadFreqency : 3; UINT8 FlashReadStatusFrequency : 3; UINT8 FlashWriteFrequency : 3; UINT8 DualOutputFastReadSupported : 1; - UINT8 ReservedZero3 : 1; // Still unknown, zero in all descriptors I have seen + UINT8 : 1; } FLASH_PARAMETERS; // Flash densities @@ -74,11 +75,16 @@ typedef struct _FLASH_PARAMETERS { #define FLASH_DENSITY_4MB 0x03 #define FLASH_DENSITY_8MB 0x04 #define FLASH_DENSITY_16MB 0x05 +#define FLASH_DENSITY_32MB 0x06 +#define FLASH_DENSITY_64MB 0x07 +#define FLASH_DENSITY_UNUSED 0x0F // Flash frequencies -#define FLASH_FREQUENCY_20MHZ 0x00 -#define FLASH_FREQUENCY_33MHZ 0x01 -#define FLASH_FREQUENCY_50MHZ 0x04 +#define FLASH_FREQUENCY_20MHZ 0x00 +#define FLASH_FREQUENCY_33MHZ 0x01 +#define FLASH_FREQUENCY_48MHZ 0x02 +#define FLASH_FREQUENCY_50MHZ_30MHZ 0x04 +#define FLASH_FREQUENCY_17MHZ 0x06 // Component section structure typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION { @@ -87,24 +93,45 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION { UINT8 InvalidInstruction1; // UINT8 InvalidInstruction2; // UINT8 InvalidInstruction3; // - UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000 - UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen } FLASH_DESCRIPTOR_COMPONENT_SECTION; +// Component section structure +typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION_V2 { + FLASH_PARAMETERS FlashParameters; + UINT8 InvalidInstruction0; // Instructions for SPI chip, that must not be executed, like FLASH ERASE + UINT8 InvalidInstruction1; // + UINT8 InvalidInstruction2; // + UINT8 InvalidInstruction3; // + UINT8 InvalidInstruction4; // + UINT8 InvalidInstruction5; // + UINT8 InvalidInstruction6; // + UINT8 InvalidInstruction7; // +} FLASH_DESCRIPTOR_COMPONENT_SECTION_V2; + // Region section // All base and limit register are storing upper part of actual UINT32 base and limit // If limit is zero - region is not present typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { - UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen + UINT16 :16; UINT16 FlashBlockEraseSize; // Size of block erased by single BLOCK ERASE command - UINT16 BiosBase; - UINT16 BiosLimit; - UINT16 MeBase; - UINT16 MeLimit; - UINT16 GbeBase; - UINT16 GbeLimit; - UINT16 PdrBase; - UINT16 PdrLimit; + UINT16 Region0Base; // BIOS + UINT16 Region0Limit; // + UINT16 Region1Base; // ME + UINT16 Region1Limit; // + UINT16 Region2Base; // GbE + UINT16 Region2Limit; // + UINT16 Region3Base; // PDR + UINT16 Region3Limit; // + UINT16 Region4Base; // Reserved region + UINT16 Region4Limit; // + UINT16 Region5Base; // Reserved region + UINT16 Region5Limit; // + UINT16 Region6Base; // Reserved region + UINT16 Region6Limit; // + UINT16 Region7Base; // Reserved region + UINT16 Region7Limit; // + UINT16 Region8Base; // EC + UINT16 Region8Limit; // } FLASH_DESCRIPTOR_REGION_SECTION; // Flash block erase sizes @@ -115,24 +142,40 @@ typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { // Master section typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION { UINT16 BiosId; - UINT8 BiosRead; - UINT8 BiosWrite; + UINT8 BiosRead; + UINT8 BiosWrite; UINT16 MeId; - UINT8 MeRead; - UINT8 MeWrite; + UINT8 MeRead; + UINT8 MeWrite; UINT16 GbeId; - UINT8 GbeRead; - UINT8 GbeWrite; + UINT8 GbeRead; + UINT8 GbeWrite; } FLASH_DESCRIPTOR_MASTER_SECTION; +// Master section v2 (Skylake+) +typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION_V2 { + UINT32 : 8; + UINT32 BiosRead : 12; + UINT32 BiosWrite : 12; + UINT32 : 8; + UINT32 MeRead : 12; + UINT32 MeWrite : 12; + UINT32 : 8; + UINT32 GbeRead : 12; + UINT32 GbeWrite : 12; + UINT32 :32; + UINT32 : 8; + UINT32 EcRead : 12; + UINT32 EcWrite : 12; +} FLASH_DESCRIPTOR_MASTER_SECTION_V2; + // Region access bits in master section #define FLASH_DESCRIPTOR_REGION_ACCESS_DESC 0x01 #define FLASH_DESCRIPTOR_REGION_ACCESS_BIOS 0x02 #define FLASH_DESCRIPTOR_REGION_ACCESS_ME 0x04 #define FLASH_DESCRIPTOR_REGION_ACCESS_GBE 0x08 #define FLASH_DESCRIPTOR_REGION_ACCESS_PDR 0x10 - -//!TODO: Describe PCH and PROC straps sections, as well as ICC and DMI tables +#define FLASH_DESCRIPTOR_REGION_ACCESS_EC 0x20 // Base address of descriptor upper map #define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC diff --git a/ffs.h b/ffs.h index 0bb8221..0adc031 100644 --- a/ffs.h +++ b/ffs.h @@ -53,10 +53,6 @@ const QByteArray EFI_CAPSULE_GUID const QByteArray INTEL_CAPSULE_GUID ("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16); -// Lenovo capsule GUID -const QByteArray LENOVO_CAPSULE_GUID -("\x8B\xA6\x3C\x4A\x23\x77\xFB\x48\x80\x3D\x57\x8C\xC1\xFE\xC4\x4D", 16); - // Toshiba EFI Capsule header typedef struct _TOSHIBA_CAPSULE_HEADER { EFI_GUID CapsuleGuid; diff --git a/ffsengine.cpp b/ffsengine.cpp index d516019..985ea38 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -155,8 +155,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer) UINT32 capsuleHeaderSize = 0; QModelIndex index; if (buffer.startsWith(EFI_CAPSULE_GUID) - || buffer.startsWith(INTEL_CAPSULE_GUID) - || buffer.startsWith(LENOVO_CAPSULE_GUID)) { + || buffer.startsWith(INTEL_CAPSULE_GUID)) { // Get info const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData(); capsuleHeaderSize = capsuleHeader->HeaderSize; @@ -266,45 +265,36 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE); const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8(descriptor, descriptorMap->RegionBase); - const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8(descriptor, descriptorMap->MasterBase); + const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase); - // GbE region - QByteArray gbe; - UINT32 gbeBegin = 0; - UINT32 gbeEnd = 0; - if (regionSection->GbeLimit) { - gbeBegin = calculateRegionOffset(regionSection->GbeBase); - gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); - gbe = intelImage.mid(gbeBegin, gbeEnd); - gbeEnd += gbeBegin; + // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency + UINT8 descriptorVersion = 0; + if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) // Old descriptor + descriptorVersion = 1; + else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor + descriptorVersion = 2; + else { + msg(tr("parseIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency)); + return ERR_INVALID_FLASH_DESCRIPTOR; } + // ME region QByteArray me; UINT32 meBegin = 0; UINT32 meEnd = 0; - if (regionSection->MeLimit) { - meBegin = calculateRegionOffset(regionSection->MeBase); - meEnd = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); + if (regionSection->Region1Limit) { + meBegin = calculateRegionOffset(regionSection->Region1Base); + meEnd = calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit); me = intelImage.mid(meBegin, meEnd); meEnd += meBegin; } - // PDR region - QByteArray pdr; - UINT32 pdrBegin = 0; - UINT32 pdrEnd = 0; - if (regionSection->PdrLimit) { - pdrBegin = calculateRegionOffset(regionSection->PdrBase); - pdrEnd = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); - pdr = intelImage.mid(pdrBegin, pdrEnd); - pdrEnd += pdrBegin; - } // BIOS region QByteArray bios; UINT32 biosBegin = 0; UINT32 biosEnd = 0; - if (regionSection->BiosLimit) { - biosBegin = calculateRegionOffset(regionSection->BiosBase); - biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + if (regionSection->Region0Limit) { + biosBegin = calculateRegionOffset(regionSection->Region0Base); + biosEnd = calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit); // Check for Gigabyte specific descriptor map if (biosEnd - biosBegin == (UINT32)intelImage.size()) { @@ -322,8 +312,41 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); return ERR_INVALID_FLASH_DESCRIPTOR; } + // GbE region + QByteArray gbe; + UINT32 gbeBegin = 0; + UINT32 gbeEnd = 0; + if (regionSection->Region2Limit) { + gbeBegin = calculateRegionOffset(regionSection->Region2Base); + gbeEnd = calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit); + gbe = intelImage.mid(gbeBegin, gbeEnd); + gbeEnd += gbeBegin; + } + // PDR region + QByteArray pdr; + UINT32 pdrBegin = 0; + UINT32 pdrEnd = 0; + if (regionSection->Region3Limit) { + pdrBegin = calculateRegionOffset(regionSection->Region3Base); + pdrEnd = calculateRegionSize(regionSection->Region3Base, regionSection->Region3Limit); + pdr = intelImage.mid(pdrBegin, pdrEnd); + pdrEnd += pdrBegin; + } + // EC region + QByteArray ec; + UINT32 ecBegin = 0; + UINT32 ecEnd = 0; + if (descriptorVersion == 2) { + if (regionSection->Region8Limit) { + pdrBegin = calculateRegionOffset(regionSection->Region8Base); + pdrEnd = calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit); + pdr = intelImage.mid(ecBegin, ecEnd); + ecEnd += ecBegin; + } + } // Check for intersections between regions + // Descriptor if (hasIntersection(descriptorBegin, descriptorEnd, gbeBegin, gbeEnd)) { msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region")); return ERR_INVALID_FLASH_DESCRIPTOR; @@ -340,6 +363,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region")); return ERR_INVALID_FLASH_DESCRIPTOR; } + if (descriptorVersion == 2 && hasIntersection(descriptorBegin, descriptorEnd, ecBegin, ecEnd)) { + msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with EC region")); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + // GbE if (hasIntersection(gbeBegin, gbeEnd, meBegin, meEnd)) { msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region")); return ERR_INVALID_FLASH_DESCRIPTOR; @@ -352,6 +380,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region")); return ERR_INVALID_FLASH_DESCRIPTOR; } + if (descriptorVersion == 2 && hasIntersection(gbeBegin, gbeEnd, ecBegin, ecEnd)) { + msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with EC region")); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + // ME if (hasIntersection(meBegin, meEnd, biosBegin, biosEnd)) { msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region")); return ERR_INVALID_FLASH_DESCRIPTOR; @@ -360,23 +393,35 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region")); return ERR_INVALID_FLASH_DESCRIPTOR; } + if (descriptorVersion == 2 && hasIntersection(meBegin, meEnd, ecBegin, ecEnd)) { + msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with EC region")); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + // BIOS if (hasIntersection(biosBegin, biosEnd, pdrBegin, pdrEnd)) { msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region")); return ERR_INVALID_FLASH_DESCRIPTOR; } + if (descriptorVersion == 2 && hasIntersection(biosBegin, biosEnd, ecBegin, ecEnd)) { + msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with EC region")); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + // PDR + if (descriptorVersion == 2 && hasIntersection(pdrBegin, pdrEnd, ecBegin, ecEnd)) { + msg(tr("parseIntelImage: descriptor parsing failed, PDR region has intersection with EC region")); + return ERR_INVALID_FLASH_DESCRIPTOR; + } // Region map is consistent // Intel image QString name = tr("Intel image"); - QString info = tr("Full size: %1h (%2)\nFlash chips: %3\nRegions: %4\nMasters: %5\nPCH straps: %6\nPROC straps: %7\nICC table entries: %8") + QString info = tr("Full size: %1h (%2)\nFlash chips: %3\nMasters: %4\nPCH straps: %5\nCPU straps: %6\n") .hexarg(intelImage.size()).arg(intelImage.size()) - .arg(descriptorMap->NumberOfFlashChips + 1) // - .arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage - .arg(descriptorMap->NumberOfMasters + 1) // + .arg(descriptorMap->NumberOfFlashChips + 1) + .arg(descriptorMap->NumberOfMasters + 1) .arg(descriptorMap->NumberOfPchStraps) - .arg(descriptorMap->NumberOfProcStraps) - .arg(descriptorMap->NumberOfIccTableEntries); + .arg(descriptorMap->NumberOfProcStraps); // Add Intel image tree item index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, parent); @@ -389,49 +434,89 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in // Check regions presence once again QVector offsets; - if (regionSection->GbeLimit) { + if (regionSection->Region2Limit) { offsets.append(gbeBegin); info += tr("\nGbE region offset: %1h").hexarg(gbeBegin); } - if (regionSection->MeLimit) { + if (regionSection->Region1Limit) { offsets.append(meBegin); info += tr("\nME region offset: %1h").hexarg(meBegin); } - if (regionSection->BiosLimit) { + if (regionSection->Region0Limit) { offsets.append(biosBegin); info += tr("\nBIOS region offset: %1h").hexarg(biosBegin); } - if (regionSection->PdrLimit) { + if (regionSection->Region3Limit) { offsets.append(pdrBegin); info += tr("\nPDR region offset: %1h").hexarg(pdrBegin); } + if (descriptorVersion == 2 && regionSection->Region8Limit) { + offsets.append(ecBegin); + info += tr("\nEC region offset: %1h").hexarg(ecBegin); + } // Region access settings - info += tr("\nRegion access settings:"); - info += tr("\nBIOS:%1%2h ME:%3%4h GbE:%5%6h") - .hexarg2(masterSection->BiosRead, 2) - .hexarg2(masterSection->BiosWrite, 2) - .hexarg2(masterSection->MeRead, 2) - .hexarg2(masterSection->MeWrite, 2) - .hexarg2(masterSection->GbeRead, 2) - .hexarg2(masterSection->GbeWrite, 2); + if (descriptorVersion == 1) { + const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8(descriptor, descriptorMap->MasterBase); + info += tr("\nRegion access settings:"); + info += tr("\nBIOS:%1%2h ME:%3%4h GbE:%5%6h") + .hexarg2(masterSection->BiosRead, 2) + .hexarg2(masterSection->BiosWrite, 2) + .hexarg2(masterSection->MeRead, 2) + .hexarg2(masterSection->MeWrite, 2) + .hexarg2(masterSection->GbeRead, 2) + .hexarg2(masterSection->GbeWrite, 2); - // BIOS access table - info += tr("\nBIOS access table:"); - info += tr("\n Read Write"); - info += tr("\nDesc %1 %2") - .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ") - .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); - info += tr("\nBIOS Yes Yes"); - info += tr("\nME %1 %2") - .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ") - .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); - info += tr("\nGbE %1 %2") - .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ") - .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); - info += tr("\nPDR %1 %2") - .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ") - .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); + // BIOS access table + info += tr("\nBIOS access table:"); + info += tr("\n Read Write"); + info += tr("\nDesc %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); + info += tr("\nBIOS Yes Yes"); + info += tr("\nME %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); + info += tr("\nGbE %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); + info += tr("\nPDR %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); + } + else if (descriptorVersion == 2) { + const FLASH_DESCRIPTOR_MASTER_SECTION_V2* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION_V2*)calculateAddress8(descriptor, descriptorMap->MasterBase); + info += tr("\nRegion access settings:"); + info += tr("\nBIOS: %1h %2h ME: %3h %4h\nGbE: %5h %6h EC: %7h %8h") + .hexarg2(masterSection->BiosRead, 3) + .hexarg2(masterSection->BiosWrite, 3) + .hexarg2(masterSection->MeRead, 3) + .hexarg2(masterSection->MeWrite, 3) + .hexarg2(masterSection->GbeRead, 3) + .hexarg2(masterSection->GbeWrite, 3) + .hexarg2(masterSection->EcRead, 3) + .hexarg2(masterSection->EcWrite, 3); + + // BIOS access table + info += tr("\nBIOS access table:"); + info += tr("\n Read Write"); + info += tr("\nDesc %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); + info += tr("\nBIOS Yes Yes"); + info += tr("\nME %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); + info += tr("\nGbE %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); + info += tr("\nPDR %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); + info += tr("\nEC %1 %2") + .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ") + .arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No "); + } // VSCC table const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)(descriptor + ((UINT16)upperMap->VsccTableBase << 4)); @@ -474,6 +559,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in QModelIndex pdrIndex; result = parsePdrRegion(pdr, pdrIndex, index); } + // Parse EC region + else if (descriptorVersion == 2 && offsets.at(i) == ecBegin) { + QModelIndex ecIndex; + result = parseEcRegion(ec, ecIndex, index); + } if (result) return result; } @@ -489,6 +579,8 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in IntelDataEnd = biosEnd; else if (LastRegionOffset == pdrBegin) IntelDataEnd = pdrEnd; + else if (descriptorVersion == 2 && LastRegionOffset == ecBegin) + IntelDataEnd = ecEnd; if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged") @@ -615,6 +707,23 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con return ERR_SUCCESS; } +UINT8 FfsEngine::parseEcRegion(const QByteArray & ec, QModelIndex & index, const QModelIndex & parent, const UINT8 mode) +{ + // Check sanity + if (ec.isEmpty()) + return ERR_EMPTY_REGION; + + // Get info + QString name = tr("EC region"); + QString info = tr("Full size: %1h (%2)"). + hexarg(ec.size()).arg(ec.size()); + + // Add tree item + index = model->addItem(Types::Region, Subtypes::EcRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), ec, parent, mode); + + return ERR_SUCCESS; +} + UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode) { if (bios.isEmpty()) @@ -928,10 +1037,10 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // All the rest is either free space or non-UEFI data QByteArray rest = volume.right(volumeSize - fileOffset); if (rest.count(empty) == rest.size()) { // It's a free space - model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode); + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index); } else { //It's non-UEFI data - QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode); + QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index); msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); } // Exit from loop @@ -973,16 +1082,16 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Add all bytes before as free space... if (i > 0) { QByteArray free = freeSpace.left(i); - model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode); + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index); } // ... and all bytes after as a padding QByteArray padding = freeSpace.mid(i); - QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode); + QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index); msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); } else { // Add free space element - model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, index, mode); + model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, index); } break; // Exit from loop } @@ -1989,7 +2098,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte if (header.isEmpty()) // Whole volume volume.append(body); else { // Body only - volume.append(model->header(index)).append(body); + volume.append(header).append(body); INT32 sizeDiff = model->body(index).size() - body.size(); if (sizeDiff > 0) { const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)model->header(index).constData(); @@ -2704,17 +2813,37 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor.constData() + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase); QByteArray gbe; - UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); - UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); + UINT32 gbeBegin = calculateRegionOffset(regionSection->Region2Base); + UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit); QByteArray me; - UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); - UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); + UINT32 meBegin = calculateRegionOffset(regionSection->Region1Base); + UINT32 meEnd = meBegin + calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit); QByteArray bios; - UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); - UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + UINT32 biosBegin = calculateRegionOffset(regionSection->Region0Base); + UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit); QByteArray pdr; - UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); - UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); + UINT32 pdrBegin = calculateRegionOffset(regionSection->Region3Base); + UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->Region3Base, regionSection->Region3Limit); + QByteArray ec; + UINT32 ecBegin = 0; + UINT32 ecEnd = 0; + + const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->ComponentBase); + // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency + UINT8 descriptorVersion = 0; + if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) { // Old descriptor + descriptorVersion = 1; + } + else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) { // Skylake+ descriptor + descriptorVersion = 2; + ecBegin = calculateRegionOffset(regionSection->Region8Base); + ecEnd = ecBegin + calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit); + } + else { + msg(tr("reconstructIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + UINT32 offset = descriptor.size(); // Reconstruct other regions @@ -2764,6 +2893,17 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec reconstructed.append(pdr); offset = pdrEnd; break; + case Subtypes::EcRegion: + if (descriptorVersion == 1) { + msg(tr("reconstructIntelImage: incompatible region type found"), index); + return ERR_INVALID_REGION; + } + ec = region; + if (ecBegin > offset) + reconstructed.append(QByteArray(ecBegin - offset, empty)); + reconstructed.append(ec); + offset = ecEnd; + break; default: msg(tr("reconstructIntelImage: unknown region type found"), index); return ERR_INVALID_REGION; diff --git a/ffsengine.h b/ffsengine.h index 281aa6e..c565921 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -67,6 +67,7 @@ public: UINT8 parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); + UINT8 parseEcRegion(const QByteArray & ec, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex()); UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); diff --git a/types.cpp b/types.cpp index 17ca51f..a9a9300 100644 --- a/types.cpp +++ b/types.cpp @@ -29,6 +29,8 @@ QString regionTypeToQString(const UINT8 type) return QObject::tr("BIOS"); case Subtypes::PdrRegion: return QObject::tr("PDR"); + case Subtypes::EcRegion: + return QObject::tr("EC"); default: return QObject::tr("Unknown"); }; diff --git a/types.h b/types.h index 64df300..7d71953 100644 --- a/types.h +++ b/types.h @@ -69,7 +69,8 @@ namespace Subtypes { GbeRegion, MeRegion, BiosRegion, - PdrRegion + PdrRegion, + EcRegion }; enum PaddingSubtypes { diff --git a/uefitool.cpp b/uefitool.cpp index 5a4ef55..39d77ce 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.20.8")) +version(tr("0.21.0")) { clipboard = QApplication::clipboard(); From c286459676c8ca41a3066c8e23f9c43932597980 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 6 Sep 2015 23:51:50 +0200 Subject: [PATCH 10/22] UP 0.3.6 - changed version number due to rebuild with engine version 0.21.0 --- UEFIPatch/uefipatch_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index 6f37b1f..f1642d0 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.5 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.6 - 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; From 8a149654630a3fa1f02a5d745563ee4630d0146c Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Tue, 8 Sep 2015 08:54:42 +0200 Subject: [PATCH 11/22] Spellchecking Corrections of issue #32 --- descriptor.h | 22 +++++++++++----------- ffs.cpp | 2 +- ffsengine.cpp | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/descriptor.h b/descriptor.h index 989761b..bd4c996 100644 --- a/descriptor.h +++ b/descriptor.h @@ -36,19 +36,20 @@ typedef struct _FLASH_DESCRIPTOR_HEADER { typedef struct _FLASH_DESCRIPTOR_MAP { // FLMAP0 UINT32 ComponentBase : 8; - UINT32 NumberOfFlashChips : 2; // Zero-based number of flash chips installed on board + UINT32 NumberOfFlashChips : 2; // Zero-based number of flash chips installed on board UINT32 : 6; - UINT32 RegionBase : 8; - UINT32 : 8; + UINT32 RegionBase : 8; + UINT32 NumberOfRegions : 3; // Reserved in v2 descriptor + UINT32 : 5; // FLMAP 1 UINT32 MasterBase : 8; UINT32 NumberOfMasters : 2; UINT32 : 6; UINT32 PchStrapsBase : 8; - UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb) + UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb) // FLMAP 2 UINT32 ProcStrapsBase : 8; - UINT32 NumberOfProcStraps : 8; // One-based number of UINT32s to read as processor straps, min=0, max=255 (1 Kb) + UINT32 NumberOfProcStraps : 8; // One-based number of UINT32s to read as processor straps, min=0, max=255 (1 Kb) UINT32: 16; } FLASH_DESCRIPTOR_MAP; @@ -59,11 +60,11 @@ typedef struct _FLASH_PARAMETERS { UINT8 SecondChipDensity : 4; UINT8 : 8; UINT8 : 1; - UINT8 ReadClockFreqency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors and 17 Mhz (110b) in v2 ones + UINT8 ReadClockFrequency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors and 17 Mhz (110b) in v2 ones UINT8 FastReadEnabled : 1; - UINT8 FastReadFreqency : 3; - UINT8 FlashReadStatusFrequency : 3; + UINT8 FastReadFrequency : 3; UINT8 FlashWriteFrequency : 3; + UINT8 FlashReadStatusFrequency : 3; UINT8 DualOutputFastReadSupported : 1; UINT8 : 1; } FLASH_PARAMETERS; @@ -112,8 +113,7 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION_V2 { // All base and limit register are storing upper part of actual UINT32 base and limit // If limit is zero - region is not present typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { - UINT16 :16; - UINT16 FlashBlockEraseSize; // Size of block erased by single BLOCK ERASE command + UINT32 :32; UINT16 Region0Base; // BIOS UINT16 Region0Limit; // UINT16 Region1Base; // ME @@ -198,7 +198,7 @@ typedef struct _VSCC_TABLE_ENTRY { // Base address and size of OEM section #define FLASH_DESCRIPTOR_OEM_SECTION_BASE 0x0F00 -#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0xFF +#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0x100 // Restore previous packing rules #pragma pack(pop) diff --git a/ffs.cpp b/ffs.cpp index fcdf03f..33410c3 100644 --- a/ffs.cpp +++ b/ffs.cpp @@ -155,7 +155,7 @@ UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header) if (!header) return 0; - bool extended = false; + const bool extended = false; /*if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) { extended = true; }*/ diff --git a/ffsengine.cpp b/ffsengine.cpp index 985ea38..42f0a7b 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -269,12 +269,12 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency UINT8 descriptorVersion = 0; - if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) // Old descriptor + if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ) // Old descriptor descriptorVersion = 1; - else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor + else if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor descriptorVersion = 2; else { - msg(tr("parseIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency)); + msg(tr("parseIntelImage: unknown descriptor version with ReadClockFrequency %1h").hexarg(componentSection->FlashParameters.ReadClockFrequency)); return ERR_INVALID_FLASH_DESCRIPTOR; } @@ -2831,16 +2831,16 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->ComponentBase); // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency UINT8 descriptorVersion = 0; - if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) { // Old descriptor + if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ) { // Old descriptor descriptorVersion = 1; } - else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) { // Skylake+ descriptor + else if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_17MHZ) { // Skylake+ descriptor descriptorVersion = 2; ecBegin = calculateRegionOffset(regionSection->Region8Base); ecEnd = ecBegin + calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit); } else { - msg(tr("reconstructIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency)); + msg(tr("reconstructIntelImage: unknown descriptor version with ReadClockFrequency %1h").hexarg(componentSection->FlashParameters.ReadClockFrequency)); return ERR_INVALID_FLASH_DESCRIPTOR; } From e5cf61f89a639ce77197b9e8a8ba129b58196f5c Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sat, 12 Sep 2015 19:44:59 +0200 Subject: [PATCH 12/22] Small fixes of FLASH_DESCRIPTOR_REGION_SECTION definition --- descriptor.h | 46 ++++++++++++++++++--------------------- ffsengine.cpp | 60 +++++++++++++++++++++++++-------------------------- 2 files changed, 51 insertions(+), 55 deletions(-) diff --git a/descriptor.h b/descriptor.h index bd4c996..579e600 100644 --- a/descriptor.h +++ b/descriptor.h @@ -43,7 +43,7 @@ typedef struct _FLASH_DESCRIPTOR_MAP { UINT32 : 5; // FLMAP 1 UINT32 MasterBase : 8; - UINT32 NumberOfMasters : 2; + UINT32 NumberOfMasters : 2; // Zero-based number of flash masters UINT32 : 6; UINT32 PchStrapsBase : 8; UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb) @@ -113,32 +113,28 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION_V2 { // All base and limit register are storing upper part of actual UINT32 base and limit // If limit is zero - region is not present typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { - UINT32 :32; - UINT16 Region0Base; // BIOS - UINT16 Region0Limit; // - UINT16 Region1Base; // ME - UINT16 Region1Limit; // - UINT16 Region2Base; // GbE - UINT16 Region2Limit; // - UINT16 Region3Base; // PDR - UINT16 Region3Limit; // - UINT16 Region4Base; // Reserved region - UINT16 Region4Limit; // - UINT16 Region5Base; // Reserved region - UINT16 Region5Limit; // - UINT16 Region6Base; // Reserved region - UINT16 Region6Limit; // - UINT16 Region7Base; // Reserved region - UINT16 Region7Limit; // - UINT16 Region8Base; // EC - UINT16 Region8Limit; // + UINT16 DescriptorBase; // Descriptor + UINT16 DescriptorLimit; // + UINT16 BiosBase; // BIOS + UINT16 BiosLimit; // + UINT16 MeBase; // ME + UINT16 MeLimit; // + UINT16 GbeBase; // GbE + UINT16 GbeLimit; // + UINT16 PdrBase; // PDR + UINT16 PdrLimit; // + UINT16 Region5Base; // Reserved region + UINT16 Region5Limit; // + UINT16 Region6Base; // Reserved region + UINT16 Region6Limit; // + UINT16 Region7Base; // Reserved region + UINT16 Region7Limit; // + UINT16 Region8Base; // Reserved region + UINT16 Region8Limit; // + UINT16 EcBase; // EC + UINT16 EcLimit; // } FLASH_DESCRIPTOR_REGION_SECTION; -// Flash block erase sizes -#define FLASH_BLOCK_ERASE_SIZE_4KB 0x0000 -#define FLASH_BLOCK_ERASE_SIZE_8KB 0x0001 -#define FLASH_BLOCK_ERASE_SIZE_64KB 0x000F - // Master section typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION { UINT16 BiosId; diff --git a/ffsengine.cpp b/ffsengine.cpp index 42f0a7b..5556ae0 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -282,9 +282,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in QByteArray me; UINT32 meBegin = 0; UINT32 meEnd = 0; - if (regionSection->Region1Limit) { - meBegin = calculateRegionOffset(regionSection->Region1Base); - meEnd = calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit); + if (regionSection->MeLimit) { + meBegin = calculateRegionOffset(regionSection->MeBase); + meEnd = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); me = intelImage.mid(meBegin, meEnd); meEnd += meBegin; } @@ -292,9 +292,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in QByteArray bios; UINT32 biosBegin = 0; UINT32 biosEnd = 0; - if (regionSection->Region0Limit) { - biosBegin = calculateRegionOffset(regionSection->Region0Base); - biosEnd = calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit); + if (regionSection->BiosLimit) { + biosBegin = calculateRegionOffset(regionSection->BiosBase); + biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); // Check for Gigabyte specific descriptor map if (biosEnd - biosBegin == (UINT32)intelImage.size()) { @@ -316,9 +316,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in QByteArray gbe; UINT32 gbeBegin = 0; UINT32 gbeEnd = 0; - if (regionSection->Region2Limit) { - gbeBegin = calculateRegionOffset(regionSection->Region2Base); - gbeEnd = calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit); + if (regionSection->GbeLimit) { + gbeBegin = calculateRegionOffset(regionSection->GbeBase); + gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); gbe = intelImage.mid(gbeBegin, gbeEnd); gbeEnd += gbeBegin; } @@ -326,9 +326,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in QByteArray pdr; UINT32 pdrBegin = 0; UINT32 pdrEnd = 0; - if (regionSection->Region3Limit) { - pdrBegin = calculateRegionOffset(regionSection->Region3Base); - pdrEnd = calculateRegionSize(regionSection->Region3Base, regionSection->Region3Limit); + if (regionSection->PdrLimit) { + pdrBegin = calculateRegionOffset(regionSection->PdrBase); + pdrEnd = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); pdr = intelImage.mid(pdrBegin, pdrEnd); pdrEnd += pdrBegin; } @@ -337,9 +337,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in UINT32 ecBegin = 0; UINT32 ecEnd = 0; if (descriptorVersion == 2) { - if (regionSection->Region8Limit) { - pdrBegin = calculateRegionOffset(regionSection->Region8Base); - pdrEnd = calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit); + if (regionSection->EcLimit) { + pdrBegin = calculateRegionOffset(regionSection->EcBase); + pdrEnd = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit); pdr = intelImage.mid(ecBegin, ecEnd); ecEnd += ecBegin; } @@ -434,23 +434,23 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in // Check regions presence once again QVector offsets; - if (regionSection->Region2Limit) { + if (regionSection->GbeLimit) { offsets.append(gbeBegin); info += tr("\nGbE region offset: %1h").hexarg(gbeBegin); } - if (regionSection->Region1Limit) { + if (regionSection->MeLimit) { offsets.append(meBegin); info += tr("\nME region offset: %1h").hexarg(meBegin); } - if (regionSection->Region0Limit) { + if (regionSection->BiosLimit) { offsets.append(biosBegin); info += tr("\nBIOS region offset: %1h").hexarg(biosBegin); } - if (regionSection->Region3Limit) { + if (regionSection->PdrLimit) { offsets.append(pdrBegin); info += tr("\nPDR region offset: %1h").hexarg(pdrBegin); } - if (descriptorVersion == 2 && regionSection->Region8Limit) { + if (descriptorVersion == 2 && regionSection->EcLimit) { offsets.append(ecBegin); info += tr("\nEC region offset: %1h").hexarg(ecBegin); } @@ -2813,17 +2813,17 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor.constData() + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase); QByteArray gbe; - UINT32 gbeBegin = calculateRegionOffset(regionSection->Region2Base); - UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit); + UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); + UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); QByteArray me; - UINT32 meBegin = calculateRegionOffset(regionSection->Region1Base); - UINT32 meEnd = meBegin + calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit); + UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); + UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); QByteArray bios; - UINT32 biosBegin = calculateRegionOffset(regionSection->Region0Base); - UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit); + UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); + UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); QByteArray pdr; - UINT32 pdrBegin = calculateRegionOffset(regionSection->Region3Base); - UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->Region3Base, regionSection->Region3Limit); + UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); + UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); QByteArray ec; UINT32 ecBegin = 0; UINT32 ecEnd = 0; @@ -2836,8 +2836,8 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec } else if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_17MHZ) { // Skylake+ descriptor descriptorVersion = 2; - ecBegin = calculateRegionOffset(regionSection->Region8Base); - ecEnd = ecBegin + calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit); + ecBegin = calculateRegionOffset(regionSection->EcBase); + ecEnd = ecBegin + calculateRegionSize(regionSection->EcBase, regionSection->EcLimit); } else { msg(tr("reconstructIntelImage: unknown descriptor version with ReadClockFrequency %1h").hexarg(componentSection->FlashParameters.ReadClockFrequency)); From 9c7c94702dd3b15cd5de3c56ff819cab0ccb9b0d Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sat, 12 Sep 2015 20:46:21 +0200 Subject: [PATCH 13/22] Replace action for paddings - and a very small visual bugfix --- ffsengine.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++---- ffsengine.h | 1 + uefitool.cpp | 9 ++++++- uefitool.ui | 2 ++ 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 5556ae0..6848c3c 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -2093,6 +2093,18 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte // Set action model->setAction(fileIndex, action); } + else if (type == Types::Padding) { + // Get info + QString name = tr("Padding"); + QString info = tr("Full size: %1h (%2)") + .hexarg(body.size()).arg(body.size()); + + // Add tree item + QModelIndex fileIndex = model->addItem(Types::Padding, getPaddingType(body), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, index, mode); + + // Set action + model->setAction(fileIndex, action); + } else if (type == Types::Volume) { QByteArray volume; if (header.isEmpty()) // Whole volume @@ -2351,6 +2363,12 @@ UINT8 FfsEngine::replace(const QModelIndex & index, const QByteArray & object, c else return ERR_NOT_IMPLEMENTED; } + else if (model->type(index) == Types::Padding) { + if (mode == REPLACE_MODE_AS_IS) + result = create(index, Types::Padding, QByteArray(), object, CREATE_MODE_AFTER, Actions::Replace); + else + return ERR_NOT_IMPLEMENTED; + } else if (model->type(index) == Types::Volume) { if (mode == REPLACE_MODE_AS_IS) { result = create(index, Types::Volume, QByteArray(), object, CREATE_MODE_AFTER, Actions::Replace); @@ -2973,14 +2991,14 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst if (reconstructed.size() > model->body(index).size()) { msg(tr("reconstructRegion: reconstructed region size %1h (%2) is bigger then original %3h (%4)") .hexarg(reconstructed.size()).arg(reconstructed.size()) - .hexarg(model->body(index).size()).arg(reconstructed.size()), + .hexarg(model->body(index).size()).arg(model->body(index).size()), index); return ERR_INVALID_PARAMETER; } else if (reconstructed.size() < model->body(index).size()) { msg(tr("reconstructRegion: reconstructed region size %1h (%2) is smaller then original %3h (%4)") .hexarg(reconstructed.size()).arg(reconstructed.size()) - .hexarg(model->body(index).size()).arg(reconstructed.size()), + .hexarg(model->body(index).size()).arg(model->body(index).size()), index); return ERR_INVALID_PARAMETER; } @@ -2995,6 +3013,49 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst return ERR_NOT_IMPLEMENTED; } +UINT8 FfsEngine::reconstructPadding(const QModelIndex& index, QByteArray& reconstructed) +{ + if (!index.isValid()) + return ERR_SUCCESS; + + // No action + if (model->action(index) == Actions::NoAction) { + reconstructed = model->body(index); + return ERR_SUCCESS; + } + else if (model->action(index) == Actions::Remove) { + reconstructed.clear(); + return ERR_SUCCESS; + } + else if (model->action(index) == Actions::Rebuild || + model->action(index) == Actions::Replace) { + // Use stored item body + reconstructed = model->body(index); + + // Check size of reconstructed region, it must be same + if (reconstructed.size() > model->body(index).size()) { + msg(tr("reconstructPadding: reconstructed padding size %1h (%2) is bigger then original %3h (%4)") + .hexarg(reconstructed.size()).arg(reconstructed.size()) + .hexarg(model->body(index).size()).arg(model->body(index).size()), + index); + return ERR_INVALID_PARAMETER; + } + else if (reconstructed.size() < model->body(index).size()) { + msg(tr("reconstructPadding: reconstructed padding size %1h (%2) is smaller then original %3h (%4)") + .hexarg(reconstructed.size()).arg(reconstructed.size()) + .hexarg(model->body(index).size()).arg(model->body(index).size()), + index); + return ERR_INVALID_PARAMETER; + } + + // Reconstruction successful + return ERR_SUCCESS; + } + + // All other actions are not supported + return ERR_NOT_IMPLEMENTED; +} + UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & reconstructed) { if (!index.isValid()) @@ -3710,9 +3771,9 @@ UINT8 FfsEngine::reconstruct(const QModelIndex &index, QByteArray& reconstructed break; case Types::Padding: - // No reconstruction needed - reconstructed = model->header(index).append(model->body(index)); - return ERR_SUCCESS; + result = reconstructPadding(index, reconstructed); + if (result) + return result; break; case Types::Volume: diff --git a/ffsengine.h b/ffsengine.h index c565921..4fe5223 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -83,6 +83,7 @@ public: UINT8 reconstruct(const QModelIndex &index, QByteArray & reconstructed); 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); diff --git a/uefitool.cpp b/uefitool.cpp index 39d77ce..1689387 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -153,7 +153,7 @@ void UEFITool::populateUi(const QModelIndex ¤t) (type == Types::Section && (subtype == EFI_SECTION_COMPRESSION || subtype == EFI_SECTION_GUID_DEFINED || subtype == EFI_SECTION_DISPOSABLE))); ui->actionInsertBefore->setEnabled(type == Types::File || type == Types::Section); ui->actionInsertAfter->setEnabled(type == Types::File || type == Types::Section); - ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::Volume || type == Types::File || type == Types::Section); + ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::Padding || type == Types::Volume || type == Types::File || type == Types::Section); ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section); ui->actionMessagesCopy->setEnabled(false); } @@ -327,6 +327,13 @@ void UEFITool::replace(const UINT8 mode) else return; } + else if (model->type(index) == Types::Padding) { + if (mode == REPLACE_MODE_AS_IS) { + path = QFileDialog::getOpenFileName(this, tr("Select padding file to replace selected object"), currentDir, "Padding files (*.pad *.bin);;All files (*)"); + } + else + return; + } else if (model->type(index) == Types::Volume) { if (mode == REPLACE_MODE_AS_IS) { path = QFileDialog::getOpenFileName(this, tr("Select volume file to replace selected object"), currentDir, "Volume files (*.vol *.bin);;All files (*)"); diff --git a/uefitool.ui b/uefitool.ui index 5b5953a..8e0a19d 100644 --- a/uefitool.ui +++ b/uefitool.ui @@ -232,6 +232,8 @@ &Padding + + From 4e8431b1695087817316bb1cdcbabd3f0ac496bf Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sat, 12 Sep 2015 21:01:42 +0200 Subject: [PATCH 14/22] UT 0.21.1 - added replace action for paddings - fixed a rare visual bug (wrong image sizes in reconstructRegion messages) - parts of the new flash region map are defined a bit better --- uefitool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uefitool.cpp b/uefitool.cpp index 1689387..3b63ae2 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.21.0")) +version(tr("0.21.1")) { clipboard = QApplication::clipboard(); From 93881e48920305ad8abb1c65ed680e7807cf3bb7 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sat, 12 Sep 2015 21:40:45 +0200 Subject: [PATCH 15/22] Corrected EC region placement --- descriptor.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/descriptor.h b/descriptor.h index 579e600..0de5476 100644 --- a/descriptor.h +++ b/descriptor.h @@ -129,8 +129,6 @@ typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { UINT16 Region6Limit; // UINT16 Region7Base; // Reserved region UINT16 Region7Limit; // - UINT16 Region8Base; // Reserved region - UINT16 Region8Limit; // UINT16 EcBase; // EC UINT16 EcLimit; // } FLASH_DESCRIPTOR_REGION_SECTION; From ed038c21bfce62c8344a3c8868a2f4193bc9709e Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Thu, 1 Oct 2015 08:24:35 +0200 Subject: [PATCH 16/22] Corrected #34 - padding data was a part of the image, now BIOS region --- ffsengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 6848c3c..1a32bdb 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -589,7 +589,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in return ERR_TRUNCATED_IMAGE; } else if (IntelDataEnd < (UINT32)intelImage.size()) { // Insert padding - QByteArray padding = bios.right(intelImage.size() - IntelDataEnd); + QByteArray padding = intelImage.mid(IntelDataEnd); // Get info name = tr("Padding"); info = tr("Full size: %1h (%2)") From 388dd2509358997e81f36f5fea6e406ce202cf1b Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Fri, 2 Oct 2015 09:14:11 +0200 Subject: [PATCH 17/22] UT 0.21.2 - fixed a bug with tailed files extraction and replacing (#35) - fixed a bug with wrong source of padding after all Intel image regions (#34) --- ffsengine.cpp | 24 +++++++++++++++++------- uefitool.cpp | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 1a32bdb..160dba7 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -1259,7 +1259,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U .arg(guidToQString(fileHeader->Name)) .hexarg2(fileHeader->Type, 2) .hexarg2(fileHeader->Attributes, 2) - .hexarg(header.size() + body.size()).arg(header.size() + body.size()) + .hexarg(header.size() + body.size() + tail.size()).arg(header.size() + body.size() + tail.size()) .hexarg(header.size()).arg(header.size()) .hexarg(body.size()).arg(body.size()) .hexarg2(fileHeader->State, 2); @@ -2137,12 +2137,22 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte return ERR_INVALID_FILE; QByteArray newHeader = header; + QByteArray newBody = body; EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)newHeader.data(); + // Check if the file has a tail + UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof(UINT16) : 0; + if (tailSize) { + // Remove the tail, it will then be added back for revision 1 volumes + newBody = newBody.left(newBody.size() - tailSize); + // Remove the attribute for rev2+ volumes + if (revision != 1) { + fileHeader->Attributes &= ~(FFS_ATTRIB_TAIL_PRESENT); + } + } // Correct file size - UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof(UINT16) : 0; - uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + body.size() + tailSize, fileHeader->Size); + uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + newBody.size() + tailSize, fileHeader->Size); // Recalculate header checksum fileHeader->IntegrityCheck.Checksum.Header = 0; @@ -2151,17 +2161,17 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte // Recalculate data checksum, if needed if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) - fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((const UINT8*)body.constData(), body.size()); + fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((const UINT8*)newBody.constData(), newBody.size()); else if (revision == 1) fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; else fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM2; - // Append body - created.append(body); + // Append new body + created.append(newBody); // Append tail, if needed - if (tailSize) { + if (revision ==1 && tailSize) { UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header; UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File; created.append(ht).append(ft); diff --git a/uefitool.cpp b/uefitool.cpp index 3b63ae2..c300a89 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.21.1")) +version(tr("0.21.2")) { clipboard = QApplication::clipboard(); From 1ab52fde3599c717964f99a7401d957501d05106 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 4 Oct 2015 21:58:44 +0200 Subject: [PATCH 18/22] UT 0.21.3 / UP 0.3.7 - solved a bug with Gigabyte-specific descriptor settings (BIOS region has size of the whole image), thanks to lordkag for #37 --- UEFIPatch/uefipatch_main.cpp | 2 +- ffsengine.cpp | 24 ++++++++++++++++++++++-- uefitool.cpp | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index f1642d0..57f7e25 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.6 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.7 - 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/ffsengine.cpp b/ffsengine.cpp index 160dba7..a71ec4f 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -303,10 +303,18 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in return ERR_INVALID_FLASH_DESCRIPTOR; } biosBegin = meEnd; + // biosEnd will point to the end of the image file + // it may be wrong, but it's pretty hard to detect a padding after BIOS region + // with malformed descriptor + } + // Normal descriptor map + else { + // Calculate biosEnd + biosEnd += biosBegin; } bios = intelImage.mid(biosBegin, biosEnd); - biosEnd += biosBegin; + } else { msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); @@ -2843,15 +2851,27 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec QByteArray gbe; UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); + QByteArray me; UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); + QByteArray bios; UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); - UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + UINT32 biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + // Gigabyte descriptor map + if (biosEnd - biosBegin == model->header(index).size() + model->body(index).size()) { + biosBegin = meEnd; + biosEnd = model->header(index).size() + model->body(index).size(); + } + // Normal descriptor map + else + biosEnd += biosBegin; + QByteArray pdr; UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); + QByteArray ec; UINT32 ecBegin = 0; UINT32 ecEnd = 0; diff --git a/uefitool.cpp b/uefitool.cpp index c300a89..99e5cbf 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.21.2")) +version(tr("0.21.3")) { clipboard = QApplication::clipboard(); From 9d0bcd0bed421e312582932772eb70a9c45a8b42 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 4 Oct 2015 22:05:38 +0200 Subject: [PATCH 19/22] Fix a compiler warning --- ffsengine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index a71ec4f..8a312c8 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -314,7 +314,6 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in } bios = intelImage.mid(biosBegin, biosEnd); - } else { msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); @@ -2860,7 +2859,7 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); UINT32 biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); // Gigabyte descriptor map - if (biosEnd - biosBegin == model->header(index).size() + model->body(index).size()) { + if (biosEnd - biosBegin == (UINT32)(model->header(index).size() + model->body(index).size())) { biosBegin = meEnd; biosEnd = model->header(index).size() + model->body(index).size(); } From 7ebbc58b9bcfef399284b6f3293590025a77946e Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 4 Oct 2015 22:28:44 +0200 Subject: [PATCH 20/22] UT 0.21.4 / UP 0.3.8 - fixed a bug introduced in 0.21.3 commit --- UEFIPatch/uefipatch_main.cpp | 2 +- ffsengine.cpp | 4 ++-- uefitool.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index 57f7e25..419fd97 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.7 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.8 - 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/ffsengine.cpp b/ffsengine.cpp index 8a312c8..aa85da2 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -303,17 +303,17 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in return ERR_INVALID_FLASH_DESCRIPTOR; } biosBegin = meEnd; + bios = intelImage.mid(biosBegin, biosEnd); // biosEnd will point to the end of the image file // it may be wrong, but it's pretty hard to detect a padding after BIOS region // with malformed descriptor } // Normal descriptor map else { + bios = intelImage.mid(biosBegin, biosEnd); // Calculate biosEnd biosEnd += biosBegin; } - - bios = intelImage.mid(biosBegin, biosEnd); } else { msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); diff --git a/uefitool.cpp b/uefitool.cpp index 99e5cbf..f9d36f8 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.21.3")) +version(tr("0.21.4")) { clipboard = QApplication::clipboard(); From 19cc0312445145bbde46333bfab593e45d770da2 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Thu, 12 Nov 2015 09:37:38 +0100 Subject: [PATCH 21/22] UT 0.21.5 /UP 0.3.9 untested - fixed various crashes reported in #39 - changes aren't tested yet, please don't use until #39 is fixed --- basetypes.h | 1 + descriptor.h | 6 +- ffs.h | 2 +- ffsengine.cpp | 197 ++++++++++++++++++++++++++++++++++++++++++++------ uefitool.cpp | 2 +- 5 files changed, 181 insertions(+), 27 deletions(-) diff --git a/basetypes.h b/basetypes.h index e8589ad..3c07309 100644 --- a/basetypes.h +++ b/basetypes.h @@ -86,6 +86,7 @@ typedef unsigned int UINTN; #define ERR_NOTHING_TO_PATCH 41 #define ERR_DEPEX_PARSE_FAILED 42 #define ERR_TRUNCATED_IMAGE 43 +#define ERR_BAD_RELOCATION_ENTRY 44 #define ERR_NOT_IMPLEMENTED 0xFF // UDK porting definitions diff --git a/descriptor.h b/descriptor.h index 0de5476..5bdefd5 100644 --- a/descriptor.h +++ b/descriptor.h @@ -21,7 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // Flash descriptor header typedef struct _FLASH_DESCRIPTOR_HEADER { - UINT8 FfVector[16]; // Must be 16 0xFFs + UINT8 FfVector[16]; // Must be 16 0xFFs UINT32 Signature; // 0x0FF0A55A } FLASH_DESCRIPTOR_HEADER; @@ -53,6 +53,8 @@ typedef struct _FLASH_DESCRIPTOR_MAP { UINT32: 16; } FLASH_DESCRIPTOR_MAP; +#define FLASH_DESCRIPTOR_MAX_BASE 0xE0 + // Component section // Flash parameters DWORD structure typedef struct _FLASH_PARAMETERS { @@ -114,7 +116,7 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION_V2 { // If limit is zero - region is not present typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { UINT16 DescriptorBase; // Descriptor - UINT16 DescriptorLimit; // + UINT16 DescriptorLimit; // UINT16 BiosBase; // BIOS UINT16 BiosLimit; // UINT16 MeBase; // ME diff --git a/ffs.h b/ffs.h index 0adc031..946a141 100644 --- a/ffs.h +++ b/ffs.h @@ -109,7 +109,7 @@ typedef struct _EFI_FIRMWARE_VOLUME_HEADER { UINT16 ExtHeaderOffset; //Reserved in Revision 1 UINT8 Reserved; UINT8 Revision; - //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[1]; + //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[2]; } EFI_FIRMWARE_VOLUME_HEADER; // Standard file system GUIDs diff --git a/ffsengine.cpp b/ffsengine.cpp index aa85da2..7909f10 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -76,6 +76,7 @@ QString errorMessage(UINT8 errorCode) case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch"); case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed"); case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated"); + case ERR_BAD_RELOCATION_ENTRY: return QObject::tr("Bad image relocation entry"); default: return QObject::tr("Unknown error %1").arg(errorCode); } } @@ -257,13 +258,31 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in // Check for buffer size to be greater or equal to descriptor region size if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) { - msg(tr("parseIntelImage: input file is smaller then minimum descriptor size of %1h (%2) bytes").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE)); + msg(tr("parseIntelImage: input file is smaller than minimum descriptor size of 1000h (4096) bytes")); return ERR_INVALID_FLASH_DESCRIPTOR; } // Parse descriptor map const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE); + + // Check sanity of base values + if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE + || descriptorMap->MasterBase == descriptorMap->RegionBase + || descriptorMap->MasterBase == descriptorMap->ComponentBase) { + msg(tr("parseIntelImage: invalid descriptor master base %1h").hexarg2(descriptorMap->MasterBase, 2)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE + || descriptorMap->RegionBase == descriptorMap->ComponentBase) { + msg(tr("parseIntelImage: invalid descriptor region base %1h").hexarg2(descriptorMap->RegionBase, 2)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + if (descriptorMap->ComponentBase > FLASH_DESCRIPTOR_MAX_BASE) { + msg(tr("parseIntelImage: invalid descriptor component base %1h").hexarg2(descriptorMap->ComponentBase, 2)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8(descriptor, descriptorMap->RegionBase); const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase); @@ -807,19 +826,21 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent) // Get volume size result = getVolumeSize(bios, volumeOffset, volumeSize, bmVolumeSize); - if (result) + if (result) { + msg(tr("parseBios: getVolumeSize failed with error \"%1\"").arg(errorMessage(result)), parent); return result; + } - // Check reported size - if (volumeSize != bmVolumeSize) - msgSizeMismach = true; - - //Check that volume is fully present in input - if (volumeOffset + volumeSize > (UINT32)bios.size()) { + // Check that volume is fully present in input + if (volumeSize > (UINT32)bios.size() || volumeOffset + volumeSize > (UINT32)bios.size()) { msg(tr("parseBios: one of volumes inside overlaps the end of data"), parent); return ERR_INVALID_VOLUME; } + // Check reported size against a size calculated using block map + if (volumeSize != bmVolumeSize) + msgSizeMismach = true; + // Check volume revision and alignment const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset); UINT32 alignment; @@ -898,6 +919,10 @@ UINT8 FfsEngine::findNextVolume(const QByteArray & bios, UINT32 volumeOffset, UI UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize) { + // Check that there is space for the volume header and at least two block map entries. + if ((UINT32)bios.size() < volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY)) + return ERR_INVALID_VOLUME; + // Populate volume header const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset); @@ -918,14 +943,37 @@ UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UIN volumeSize = volumeHeader->FvLength; bmVolumeSize = calcVolumeSize; + + if (volumeSize == 0) + return ERR_INVALID_VOLUME; + return ERR_SUCCESS; } UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent, const UINT8 mode) { + // Check that there is space for the volume header + if ((UINT32)volume.size() < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + msg(tr("parseVolume: input volume size %1h (%2) is smaller than volume header size 40h (64)").hexarg(volume.size()).arg(volume.size())); + return ERR_INVALID_VOLUME; + } + // Populate volume header const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData()); + // Check sanity of HeaderLength value + if (ALIGN8(volumeHeader->HeaderLength) > volume.size()) { + msg(tr("parseVolume: volume header overlaps the end of data")); + return ERR_INVALID_VOLUME; + } + + // Check sanity of ExtHeaderOffset value + if (volumeHeader->ExtHeaderOffset > 0 + && (UINT32)volume.size() < ALIGN8(volumeHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER))) { + msg(tr("parseVolume: extended volume header overlaps the end of data")); + return ERR_INVALID_VOLUME; + } + // Calculate volume header size UINT32 headerSize; if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { @@ -940,12 +988,10 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Check for volume structure to be known bool volumeIsUnknown = true; - /*UINT8 volumeFfsVersion = 0;*/ // Check for FFS v2 volume if (FFSv2Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) { volumeIsUnknown = false; - /*volumeFfsVersion = 2;*/ } // Check attributes @@ -1139,6 +1185,8 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co UINT8 FfsEngine::getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize) { + if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER)) + return ERR_INVALID_VOLUME; const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset); fileSize = uint24ToUint32(fileHeader->Size); return ERR_SUCCESS; @@ -1332,6 +1380,8 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U UINT8 FfsEngine::getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize) { + if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER)) + return ERR_INVALID_FILE; const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset); sectionSize = uint24ToUint32(sectionHeader->Size); return ERR_SUCCESS; @@ -1350,6 +1400,9 @@ UINT8 FfsEngine::parseSections(const QByteArray & body, const QModelIndex & pare result = getSectionSize(body, sectionOffset, sectionSize); if (result) return result; + // Exit from loop if no sections left + if (sectionSize == 0) + break; // Parse section QModelIndex sectionIndex; @@ -1531,6 +1584,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c bool msgInvalidCrc = false; bool msgUnknownAuth = false; bool msgSigned = false; + bool msgInvalidSignatureLength = false; bool msgUnknownSignature = false; bool msgUnknownUefiGuidSignature = false; @@ -1594,7 +1648,12 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c else if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) { msgSigned = true; const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)body.constData(); - if (certificateHeader->CertificateType == WIN_CERT_TYPE_EFI_GUID) { + if ((UINT32)body.size() < sizeof(WIN_CERTIFICATE)) { + info += tr("\nSignature type: invalid, wrong length"); + msgInvalidSignatureLength = true; + parseCurrentSection = false; + } + else if (certificateHeader->CertificateType == WIN_CERT_TYPE_EFI_GUID) { info += tr("\nSignature type: UEFI"); const WIN_CERTIFICATE_UEFI_GUID* guidCertificateHeader = (const WIN_CERTIFICATE_UEFI_GUID*)certificateHeader; if (QByteArray((const char*)&guidCertificateHeader->CertType, sizeof(EFI_GUID)) == EFI_CERT_TYPE_RSA2048_SHA256_GUID) { @@ -1619,10 +1678,17 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c msgUnknownSignature = true; } - // Add additional to the header - header.append(body.left(certificateHeader->Length)); - // Get new body - processed = body = body.mid(certificateHeader->Length); + if ((UINT32)body.size() < certificateHeader->Length) { + info += tr("\nSignature type: invalid, wrong length"); + msgInvalidSignatureLength = true; + parseCurrentSection = false; + } + else { + // Add additional data to the header + header.append(body.left(certificateHeader->Length)); + // Get new body + processed = body = body.mid(certificateHeader->Length); + } } // Unknown GUIDed section else { @@ -1665,6 +1731,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c msg(tr("parseSection: signature may become invalid after any modification"), index); if (msgUnknownUefiGuidSignature) msg(tr("parseSection: GUID defined section with unknown signature subtype"), index); + if (msgInvalidSignatureLength) + msg(tr("parseSection: GUID defined section with invalid signature length"), index); if (msgUnknownSignature) msg(tr("parseSection: GUID defined section with unknown signature type"), index); @@ -1796,6 +1864,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c // Get PE info bool msgInvalidDosSignature = false; + bool msgInvalidDosHeader = false; bool msgInvalidPeSignature = false; bool msgUnknownOptionalHeaderSignature = false; @@ -1806,7 +1875,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c } else { const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew); - if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) { + if ((UINT32)body.size() < dosHeader->e_lfanew + sizeof(EFI_IMAGE_PE_HEADER)) { + info += tr("\nDOS lfanew: %1h, invalid").hexarg2(dosHeader->e_lfanew, 8); + msgInvalidDosHeader = true; + } + else if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) { info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8); msgInvalidPeSignature = true; } @@ -1853,6 +1926,9 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c if (msgInvalidDosSignature) { msg("parseSection: PE32 image with invalid DOS signature", index); } + if (msgInvalidDosHeader) { + msg("parseSection: PE32 image with invalid DOS header", index); + } if (msgInvalidPeSignature) { msg("parseSection: PE32 image with invalid PE signature", index); } @@ -2845,16 +2921,40 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec return result; reconstructed.append(descriptor); + // Check descriptor size + if ((UINT32)descriptor.size() < FLASH_DESCRIPTOR_SIZE) { + msg(tr("reconstructIntelImage: descriptor is smaller than minimum size of 1000h (4096) bytes")); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor.constData() + sizeof(FLASH_DESCRIPTOR_HEADER)); + // Check sanity of base values + if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE + || descriptorMap->MasterBase == descriptorMap->RegionBase + || descriptorMap->MasterBase == descriptorMap->ComponentBase) { + msg(tr("reconstructIntelImage: invalid descriptor master base %1h").hexarg2(descriptorMap->MasterBase, 2)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE + || descriptorMap->RegionBase == descriptorMap->ComponentBase) { + msg(tr("reconstructIntelImage: invalid descriptor region base %1h").hexarg2(descriptorMap->RegionBase, 2)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + if (descriptorMap->ComponentBase > FLASH_DESCRIPTOR_MAX_BASE) { + msg(tr("reconstructIntelImage: invalid descriptor component base %1h").hexarg2(descriptorMap->ComponentBase, 2)); + return ERR_INVALID_FLASH_DESCRIPTOR; + } + + const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase); QByteArray gbe; UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); - + QByteArray me; UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); - + QByteArray bios; UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); UINT32 biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); @@ -2870,7 +2970,7 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec QByteArray pdr; UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); - + QByteArray ec; UINT32 ecBegin = 0; UINT32 ecEnd = 0; @@ -2890,7 +2990,7 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec msg(tr("reconstructIntelImage: unknown descriptor version with ReadClockFrequency %1h").hexarg(componentSection->FlashParameters.ReadClockFrequency)); return ERR_INVALID_FLASH_DESCRIPTOR; } - + UINT32 offset = descriptor.size(); // Reconstruct other regions @@ -3107,6 +3207,12 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon QByteArray body = model->body(index); EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)header.data(); + // Check sanity of HeaderLength + if (volumeHeader->HeaderLength > header.size()) { + msg(tr("reconstructVolume: invalid volume header length, reconstruction is not possible"), index); + return ERR_INVALID_VOLUME; + } + // Recalculate volume header checksum volumeHeader->Checksum = 0; volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength); @@ -3170,8 +3276,8 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon // Calculate relative base address UINT32 relbase = fileOffset + sectionOffset + model->header(image).size(); // Calculate offset of image relative to file base - UINT32 imagebase; - result = getBase(model->body(image), imagebase); + UINT32 imagebase = 0; + result = getBase(model->body(image), imagebase); // imagebase passed by reference if (!result) { // Calculate volume base volumeBase = imagebase - relbase; @@ -3694,6 +3800,12 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, if (guidDefinedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) { // CRC32 section if (QByteArray((const char*)&guidDefinedHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_CRC32) { + // Check header size + if ((UINT32)header.size() != sizeof(EFI_GUID_DEFINED_SECTION) + sizeof(UINT32)) { + msg(tr("reconstructSection: invalid CRC32 section size %1h (%2)") + .hexarg(header.size()).arg(header.size()), index); + return ERR_INVALID_SECTION; + } // Calculate CRC32 of section data UINT32 crc = crc32(0, (const UINT8*)compressed.constData(), compressed.size()); // Store new CRC32 @@ -3831,6 +3943,10 @@ UINT8 FfsEngine::reconstruct(const QModelIndex &index, QByteArray& reconstructed UINT8 FfsEngine::growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize) { + // Check sanity + if ((UINT32)header.size() < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) + return ERR_INVALID_VOLUME; + // Adjust new size to be representable by current FvBlockMap EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)header.data(); EFI_FV_BLOCK_MAP_ENTRY* blockMap = (EFI_FV_BLOCK_MAP_ENTRY*)(header.data() + sizeof(EFI_FIRMWARE_VOLUME_HEADER)); @@ -4042,11 +4158,15 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) QByteArray file = executable; // Populate DOS header + if ((UINT32)file.size() < sizeof(EFI_IMAGE_DOS_HEADER)) + return ERR_INVALID_FILE; EFI_IMAGE_DOS_HEADER* dosHeader = (EFI_IMAGE_DOS_HEADER*)file.data(); // Check signature if (dosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE){ UINT32 offset = dosHeader->e_lfanew; + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_PE_HEADER)) + return ERR_UNKNOWN_IMAGE_TYPE; EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(file.data() + offset); if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) return ERR_UNKNOWN_IMAGE_TYPE; @@ -4054,8 +4174,12 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) // Skip file header offset += sizeof(EFI_IMAGE_FILE_HEADER); // Check optional header magic + if ((UINT32)file.size() < offset + sizeof(UINT16)) + return ERR_UNKNOWN_IMAGE_TYPE; UINT16 magic = *(UINT16*)(file.data() + offset); if (magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_OPTIONAL_HEADER32)) + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; EFI_IMAGE_OPTIONAL_HEADER32* optHeader = (EFI_IMAGE_OPTIONAL_HEADER32*)(file.data() + offset); delta = base - optHeader->ImageBase; if (!delta) @@ -4067,6 +4191,8 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) optHeader->ImageBase = base; } else if (magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_OPTIONAL_HEADER64)) + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; EFI_IMAGE_OPTIONAL_HEADER64* optHeader = (EFI_IMAGE_OPTIONAL_HEADER64*)(file.data() + offset); delta = base - optHeader->ImageBase; if (!delta) @@ -4082,6 +4208,8 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) } else if (dosHeader->e_magic == EFI_IMAGE_TE_SIGNATURE){ // Populate TE header + if ((UINT32)file.size() < sizeof(EFI_IMAGE_TE_HEADER)) + return ERR_INVALID_FILE; EFI_IMAGE_TE_HEADER* teHeader = (EFI_IMAGE_TE_HEADER*)file.data(); delta = base - teHeader->ImageBase; if (!delta) @@ -4121,7 +4249,10 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) // Run this relocation record while (Reloc < RelocEnd) { - UINT8* data = (UINT8*)(file.data() + RelocBase->VirtualAddress - teFixup + (*Reloc & 0x0FFF)); + UINT32 RelocLocation = RelocBase->VirtualAddress - teFixup + (*Reloc & 0x0FFF); + if ((UINT32)file.size() < RelocLocation) + return ERR_BAD_RELOCATION_ENTRY; + UINT8* data = (UINT8*)(file.data() + RelocLocation); switch ((*Reloc) >> 12) { case EFI_IMAGE_REL_BASED_ABSOLUTE: // Do nothing @@ -4197,11 +4328,15 @@ UINT8 FfsEngine::getEntryPoint(const QByteArray &file, UINT32& entryPoint) return ERR_INVALID_FILE; // Populate DOS header + if ((UINT32)file.size() < sizeof(EFI_IMAGE_DOS_HEADER)) + return ERR_INVALID_FILE; const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)file.constData(); // Check signature if (dosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE){ UINT32 offset = dosHeader->e_lfanew; + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_PE_HEADER)) + return ERR_UNKNOWN_IMAGE_TYPE; const EFI_IMAGE_PE_HEADER* peHeader = (const EFI_IMAGE_PE_HEADER*)(file.constData() + offset); if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) return ERR_UNKNOWN_IMAGE_TYPE; @@ -4213,10 +4348,14 @@ UINT8 FfsEngine::getEntryPoint(const QByteArray &file, UINT32& entryPoint) // Check optional header magic const UINT16 magic = *(const UINT16*)(file.constData() + offset); if (magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_OPTIONAL_HEADER32)) + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; const EFI_IMAGE_OPTIONAL_HEADER32* optHeader = (const EFI_IMAGE_OPTIONAL_HEADER32*)(file.constData() + offset); entryPoint = optHeader->ImageBase + optHeader->AddressOfEntryPoint; } else if (magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_OPTIONAL_HEADER64)) + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; const EFI_IMAGE_OPTIONAL_HEADER64* optHeader = (const EFI_IMAGE_OPTIONAL_HEADER64*)(file.constData() + offset); entryPoint = optHeader->ImageBase + optHeader->AddressOfEntryPoint; } @@ -4225,6 +4364,8 @@ UINT8 FfsEngine::getEntryPoint(const QByteArray &file, UINT32& entryPoint) } else if (dosHeader->e_magic == EFI_IMAGE_TE_SIGNATURE){ // Populate TE header + if ((UINT32)file.size() < sizeof(EFI_IMAGE_TE_HEADER)) + return ERR_INVALID_FILE; const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)file.constData(); UINT32 teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); entryPoint = teHeader->ImageBase + teHeader->AddressOfEntryPoint - teFixup; @@ -4238,11 +4379,15 @@ UINT8 FfsEngine::getBase(const QByteArray& file, UINT32& base) return ERR_INVALID_FILE; // Populate DOS header + if ((UINT32)file.size() < sizeof(EFI_IMAGE_DOS_HEADER)) + return ERR_INVALID_FILE; const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)file.constData(); // Check signature if (dosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE){ UINT32 offset = dosHeader->e_lfanew; + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_PE_HEADER)) + return ERR_UNKNOWN_IMAGE_TYPE; const EFI_IMAGE_PE_HEADER* peHeader = (const EFI_IMAGE_PE_HEADER*)(file.constData() + offset); if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) return ERR_UNKNOWN_IMAGE_TYPE; @@ -4254,10 +4399,14 @@ UINT8 FfsEngine::getBase(const QByteArray& file, UINT32& base) // Check optional header magic const UINT16 magic = *(const UINT16*)(file.constData() + offset); if (magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_OPTIONAL_HEADER32)) + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; const EFI_IMAGE_OPTIONAL_HEADER32* optHeader = (const EFI_IMAGE_OPTIONAL_HEADER32*)(file.constData() + offset); base = optHeader->ImageBase; } else if (magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { + if ((UINT32)file.size() < offset + sizeof(EFI_IMAGE_OPTIONAL_HEADER64)) + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; const EFI_IMAGE_OPTIONAL_HEADER64* optHeader = (const EFI_IMAGE_OPTIONAL_HEADER64*)(file.constData() + offset); base = optHeader->ImageBase; } @@ -4266,6 +4415,8 @@ UINT8 FfsEngine::getBase(const QByteArray& file, UINT32& base) } else if (dosHeader->e_magic == EFI_IMAGE_TE_SIGNATURE){ // Populate TE header + if ((UINT32)file.size() < sizeof(EFI_IMAGE_TE_HEADER)) + return ERR_INVALID_FILE; const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)file.constData(); //!TODO: add handling base = teHeader->ImageBase; diff --git a/uefitool.cpp b/uefitool.cpp index f9d36f8..34ca9e0 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.21.4")) +version(tr("0.21.5")) { clipboard = QApplication::clipboard(); From d54f215e673d1dc338ef3171e82a220376d40c9a Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Thu, 12 Nov 2015 09:38:14 +0100 Subject: [PATCH 22/22] Forgot to bump UP version --- UEFIPatch/uefipatch_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index 419fd97..e14e59f 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.8 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.9 - 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;