From 63088afd8714210cbc2203e60c3da57b6071bfe1 Mon Sep 17 00:00:00 2001 From: Alex Matrosov Date: Sun, 10 Dec 2017 17:56:00 -0800 Subject: [PATCH] A45 + FFSv3 support with large files and large sections + proper names for Flash Descriptor v2 regions (#89) + better alignment calculations (#96) + improved NVRAM parser + post IBB hash support for Boot Guard + bugfixes + companion tool updated --- UEFIDump/CMakeLists.txt | 1 + UEFIDump/uefidump_main.cpp | 4 +- UEFIExtract/uefiextract.pro | 1 + UEFIExtract/uefiextract_main.cpp | 48 ++--- UEFIFind/uefifind.pro | 5 +- UEFIFind/uefifind_main.cpp | 8 +- UEFITool/uefitool.cpp | 17 +- UEFITool/uefitool.h | 1 + common/descriptor.cpp | 4 +- common/descriptor.h | 38 ++-- common/ffs.cpp | 3 + common/ffs.h | 17 +- common/ffsbuilder.cpp | 12 +- common/ffsparser.cpp | 360 +++++++++++++++++-------------- common/ffsparser.h | 46 ++-- common/nvram.h | 25 ++- common/nvramparser.cpp | 308 ++++++++++++++------------ common/nvramparser.h | 11 +- common/treemodel.cpp | 41 ++-- common/treemodel.h | 13 +- common/types.cpp | 41 ++-- common/types.h | 14 +- common/utility.cpp | 15 +- common/utility.h | 3 + 24 files changed, 583 insertions(+), 453 deletions(-) diff --git a/UEFIDump/CMakeLists.txt b/UEFIDump/CMakeLists.txt index 067bf8c..b0c8bbc 100644 --- a/UEFIDump/CMakeLists.txt +++ b/UEFIDump/CMakeLists.txt @@ -19,6 +19,7 @@ SET(PROJECT_SOURCES ../common/LZMA/SDK/C/LzmaDec.c ../common/Tiano/EfiTianoDecompress.c ../common/ustring.cpp + ../common/sha256.c ../common/bstrlib/bstrlib.c ../common/bstrlib/bstrwrap.cpp ) diff --git a/UEFIDump/uefidump_main.cpp b/UEFIDump/uefidump_main.cpp index fb1a433..b280a3d 100644 --- a/UEFIDump/uefidump_main.cpp +++ b/UEFIDump/uefidump_main.cpp @@ -1,6 +1,6 @@ /* uefidump_main.cpp -Copyright (c) 2016, Nikolaj Schlej. All rights reserved. +Copyright (c) 2017, LongSoft. All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -29,7 +29,7 @@ int main(int argc, char *argv[]) return (uefidumper.dump(buffer, UString(argv[1])) != U_SUCCESS); } - std::cout << "UEFIDump 0.1.5" << std::endl << std::endl + std::cout << "UEFIDump 0.1.6" << std::endl << std::endl << "Usage: UEFIDump imagefile" << std::endl; return 0; } diff --git a/UEFIExtract/uefiextract.pro b/UEFIExtract/uefiextract.pro index e383dfa..d2411e9 100644 --- a/UEFIExtract/uefiextract.pro +++ b/UEFIExtract/uefiextract.pro @@ -26,6 +26,7 @@ SOURCES += \ ../common/LZMA/SDK/C/LzmaDec.c \ ../common/Tiano/EfiTianoDecompress.c \ ../common/ustring.cpp + ../common/sha256.c HEADERS += \ ffsdumper.h \ diff --git a/UEFIExtract/uefiextract_main.cpp b/UEFIExtract/uefiextract_main.cpp index ff3897c..d8a9cb5 100644 --- a/UEFIExtract/uefiextract_main.cpp +++ b/UEFIExtract/uefiextract_main.cpp @@ -1,5 +1,5 @@ /* uefiextract_main.cpp -Copyright (c) 2016, Nikolaj Schlej. All rights reserved. +Copyright (c) 2017, LongSoft. All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -20,8 +20,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); - a.setOrganizationName("CodeRush"); - a.setOrganizationDomain("coderush.me"); + a.setOrganizationName("LongSoft"); + a.setOrganizationDomain("longsoft.me"); a.setApplicationName("UEFIExtract"); if (a.arguments().length() > 32) { @@ -63,17 +63,17 @@ int main(int argc, char *argv[]) // Get last VTF std::vector, QModelIndex > > fitTable = ffsParser.getFitTable(); if (fitTable.size()) { - std::cout << "---------------------------------------------------------------------------" << std::endl; - std::cout << " Address | Size | Ver | CS | Type / Info " << std::endl; - std::cout << "---------------------------------------------------------------------------" << std::endl; - for (size_t i = 0; i < fitTable.size(); i++) { - std::cout << fitTable[i].first[0].toLatin1().constData() << " | " - << fitTable[i].first[1].toLatin1().constData() << " | " - << fitTable[i].first[2].toLatin1().constData() << " | " - << fitTable[i].first[3].toLatin1().constData() << " | " - << fitTable[i].first[4].toLatin1().constData() << " | " - << fitTable[i].first[5].toLatin1().constData() << std::endl; - } + std::cout << "---------------------------------------------------------------------------" << std::endl; + std::cout << " Address | Size | Ver | CS | Type / Info " << std::endl; + std::cout << "---------------------------------------------------------------------------" << std::endl; + for (size_t i = 0; i < fitTable.size(); i++) { + std::cout << fitTable[i].first[0].toLatin1().constData() << " | " + << fitTable[i].first[1].toLatin1().constData() << " | " + << fitTable[i].first[2].toLatin1().constData() << " | " + << fitTable[i].first[3].toLatin1().constData() << " | " + << fitTable[i].first[4].toLatin1().constData() << " | " + << fitTable[i].first[5].toLatin1().constData() << std::endl; + } } @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) if (a.arguments().length() == 3 && a.arguments().at(2) == QString("dump")) { return (ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump")) != U_SUCCESS); } - else if (a.arguments().length() > 3 || + else if (a.arguments().length() > 3 || (a.arguments().length() == 3 && a.arguments().at(2) != QString("all") && a.arguments().at(2) != QString("report"))) { // Dump specific files, without report UINT32 returned = 0; for (int i = 2; i < a.arguments().length(); i++) { @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) } return returned; } - + // Create ffsReport FfsReport ffsReport(&model); std::vector report = ffsReport.generate(); @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) file.close(); } } - + // Dump all non-leaf elements, with report, default if (a.arguments().length() == 2) { return (ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump")) != U_SUCCESS); @@ -121,12 +121,12 @@ int main(int argc, char *argv[]) } } // If parameters are different, show version and usage information - std::cout << "UEFIExtract 0.13.4" << std::endl << std::endl - << "Usage: UEFIExtract imagefile - generate report and dump only leaf tree items into .dump folder." << std::endl - << " UEFIExtract imagefile all - generate report and dump all tree items." << std::endl - << " UEFIExtract imagefile dump - only generate dump, no report needed." << std::endl - << " UEFIExtract imagefile report - only generate report, no dump needed." << std::endl - << " UEFIExtract imagefile GUID_1 GUID_2 ... GUID_31 - dump only FFS file(s) with specific GUID(s), without report." << std::endl - << "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise." << std::endl; + std::cout << "UEFIExtract 0.13.5" << std::endl << std::endl + << "Usage: UEFIExtract imagefile - generate report and dump only leaf tree items into .dump folder." << std::endl + << " UEFIExtract imagefile all - generate report and dump all tree items." << std::endl + << " UEFIExtract imagefile dump - only generate dump, no report needed." << std::endl + << " UEFIExtract imagefile report - only generate report, no dump needed." << std::endl + << " UEFIExtract imagefile GUID_1 GUID_2 ... GUID_31 - dump only FFS file(s) with specific GUID(s), without report." << std::endl + << "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise." << std::endl; return 1; } \ No newline at end of file diff --git a/UEFIFind/uefifind.pro b/UEFIFind/uefifind.pro index 3f5643a..e4b3e7f 100644 --- a/UEFIFind/uefifind.pro +++ b/UEFIFind/uefifind.pro @@ -21,7 +21,8 @@ SOURCES += uefifind_main.cpp \ ../common/LZMA/LzmaDecompress.c \ ../common/LZMA/SDK/C/LzmaDec.c \ ../common/Tiano/EfiTianoDecompress.c \ - ../common/ustring.cpp + ../common/ustring.cpp \ + ../common/sha256.c HEADERS += uefifind.h \ ../common/guiddatabase.h \ @@ -41,5 +42,5 @@ HEADERS += uefifind.h \ ../common/Tiano/EfiTianoDecompress.h \ ../common/ustring.h \ ../common/ubytearray.h \ - ../common/bootguard.h \ + ../common/bootguard.h \ ../common/sha256.h diff --git a/UEFIFind/uefifind_main.cpp b/UEFIFind/uefifind_main.cpp index ee29196..09c64ec 100644 --- a/UEFIFind/uefifind_main.cpp +++ b/UEFIFind/uefifind_main.cpp @@ -1,6 +1,6 @@ /* uefifind_main.cpp -Copyright (c) 2016, Nikolaj Schlej. All rights reserved. +Copyright (c) 2017, LongSoft. All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -17,8 +17,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); - a.setOrganizationName("CodeRush"); - a.setOrganizationDomain("coderush.me"); + a.setOrganizationName("LongSoft"); + a.setOrganizationDomain("longsoft.me"); a.setApplicationName("UEFIFind"); UEFIFind w; @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) return U_SUCCESS; } else { - std::cout << "UEFIFind 0.10.9" << std::endl << std::endl << + std::cout << "UEFIFind 0.10.10" << std::endl << std::endl << "Usage: UEFIFind {header | body | all} {list | count} pattern imagefile" << std::endl << " or UEFIFind file patternsfile imagefile" << std::endl; return U_INVALID_PARAMETER; diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index 5a9fc2c..95bd58a 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("NE alpha 44")) +version(tr("NE alpha 45")) { clipboard = QApplication::clipboard(); @@ -150,6 +150,10 @@ void UEFITool::init() delete ffsParser; ffsParser = new FfsParser(model); + // Set proper marking state + model->setMarkingEnabled(markingEnabled); + ui->actionToggleBootGuardMarking->setChecked(markingEnabled); + // Connect connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(populateUi(const QModelIndex &))); @@ -199,7 +203,7 @@ void UEFITool::populateUi(const QModelIndex ¤t) || type == Types::EvsaEntry || type == Types::FlashMapEntry); ui->menuStoreActions->setEnabled(type == Types::VssStore - || type == Types::LenovoVssStore + || type == Types::Vss2Store || type == Types::FdcStore || type == Types::FsysStore || type == Types::EvsaStore @@ -631,7 +635,7 @@ void UEFITool::extract(const UINT8 mode) case Types::EvsaEntry: path = QFileDialog::getSaveFileName(this, tr("Save EVSA entry to file"), name + ".evse", "EVSA entry files (*.evse *.bin);;All files (*)"); break; case Types::FlashMapEntry: path = QFileDialog::getSaveFileName(this, tr("Save FlashMap entry to file"), name + ".fme", "FlashMap entry files (*.fme *.bin);;All files (*)"); break; case Types::VssStore: path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", "VSS store files (*.vss *.bin);;All files (*)"); break; - case Types::LenovoVssStore: path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", "VSS store files (*.vss *.bin);;All files (*)"); break; + case Types::Vss2Store: path = QFileDialog::getSaveFileName(this, tr("Save VSS2 store to file"), name + ".vss2", "VSS2 store files (*.vss2 *.bin);;All files (*)"); break; case Types::FdcStore: path = QFileDialog::getSaveFileName(this, tr("Save FDC store to file"), name + ".fdc", "FDC store files (*.fdc *.bin);;All files (*)"); break; case Types::FsysStore: path = QFileDialog::getSaveFileName(this, tr("Save Fsys store to file"), name + ".fsys", "Fsys store files (*.fsys *.bin);;All files (*)"); break; case Types::EvsaStore: path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", "EVSA store files (*.evsa *.bin);;All files (*)"); break; @@ -672,7 +676,7 @@ void UEFITool::extract(const UINT8 mode) case Types::FlashMapEntry: case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save entry body to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); break; case Types::VssStore: - case Types::LenovoVssStore: + case Types::Vss2Store: case Types::FtwStore: case Types::FdcStore: case Types::FsysStore: @@ -921,6 +925,7 @@ void UEFITool::clearMessages() void UEFITool::toggleBootGuardMarking(bool enabled) { model->setMarkingEnabled(enabled); + markingEnabled = enabled; } void UEFITool::dragEnterEvent(QDragEnterEvent* event) @@ -1041,7 +1046,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event) case Types::EvsaEntry: case Types::FlashMapEntry: ui->menuEntryActions->exec(event->globalPos()); break; case Types::VssStore: - case Types::LenovoVssStore: + case Types::Vss2Store: case Types::FdcStore: case Types::FsysStore: case Types::EvsaStore: @@ -1069,6 +1074,7 @@ void UEFITool::readSettings() ui->structureTreeView->setColumnWidth(1, settings.value("tree/columnWidth1", ui->structureTreeView->columnWidth(1)).toInt()); ui->structureTreeView->setColumnWidth(2, settings.value("tree/columnWidth2", ui->structureTreeView->columnWidth(2)).toInt()); ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt()); + markingEnabled = settings.value("tree/markingEnabled", true).toBool(); } void UEFITool::writeSettings() @@ -1084,6 +1090,7 @@ void UEFITool::writeSettings() settings.setValue("tree/columnWidth1", ui->structureTreeView->columnWidth(1)); settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2)); settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3)); + settings.setValue("tree/markingEnabled", markingEnabled); } void UEFITool::showFitTable() diff --git a/UEFITool/uefitool.h b/UEFITool/uefitool.h index 4dfa01c..dbc243e 100644 --- a/UEFITool/uefitool.h +++ b/UEFITool/uefitool.h @@ -134,6 +134,7 @@ private: QString currentPath; QString currentProgramPath; const QString version; + bool markingEnabled; bool enableExtractBodyUncompressed(const QModelIndex ¤t); diff --git a/common/descriptor.cpp b/common/descriptor.cpp index 2365b2c..578bd82 100644 --- a/common/descriptor.cpp +++ b/common/descriptor.cpp @@ -25,13 +25,13 @@ const UINT8* calculateAddress16(const UINT8* baseAddress, const UINT16 baseOrLim return baseAddress + baseOrLimit * 0x1000; } -// Calculate offset of region using its base +// Calculate offset of region using it's base UINT32 calculateRegionOffset(const UINT16 base) { return base * 0x1000; } -//Calculate size of region using its base and limit +//Calculate size of region using it's base and limit UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit) { if (limit) diff --git a/common/descriptor.h b/common/descriptor.h index 1aa076f..edd324f 100644 --- a/common/descriptor.h +++ b/common/descriptor.h @@ -106,25 +106,37 @@ typedef struct FLASH_DESCRIPTOR_COMPONENT_SECTION_ { // 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 + UINT16 MeBase; // Management Engine UINT16 MeLimit; // - UINT16 GbeBase; // GbE + UINT16 GbeBase; // Gigabit Ethernet UINT16 GbeLimit; // - UINT16 PdrBase; // PDR + UINT16 PdrBase; // Platform Data UINT16 PdrLimit; // - UINT16 Reserved1Base; // Reserved1 - UINT16 Reserved1Limit; // - UINT16 Reserved2Base; // Reserved2 - UINT16 Reserved2Limit; // - UINT16 Reserved3Base; // Reserved3 - UINT16 Reserved3Limit; // - UINT16 EcBase; // EC + UINT16 DevExp1Base; // Device Expansion 1 + UINT16 DevExp1Limit; // + UINT16 Bios2Base; // Secondary BIOS + UINT16 Bios2Limit; // + UINT16 MicrocodeBase; // CPU microcode + UINT16 MicrocodeLimit; // + UINT16 EcBase; // Embedded Controller UINT16 EcLimit; // - UINT16 Reserved4Base; // Reserved4 - UINT16 Reserved4Limit; // + UINT16 DevExp2Base; // Device Expansion 2 + UINT16 DevExp2Limit; // + UINT16 IeBase; // Innovation Engine + UINT16 IeLimit; // + UINT16 Tgbe1Base; // 10 Gigabit Ethernet 1 + UINT16 Tgbe1Limit; // + UINT16 Tgbe2Base; // 10 Gigabit Ethernet 2 + UINT16 Tgbe2Limit; // + UINT16 Reserved1Base; // Reserved 1 + UINT16 Reserved1Limit; // + UINT16 Reserved2Base; // Reserved 2 + UINT16 Reserved2Limit; // + UINT16 PttBase; // Platform Trust Technology + UINT16 PttLimit; // } FLASH_DESCRIPTOR_REGION_SECTION; // Master section diff --git a/common/ffs.cpp b/common/ffs.cpp index 97e119f..9b87e2d 100644 --- a/common/ffs.cpp +++ b/common/ffs.cpp @@ -32,6 +32,9 @@ const std::vector FFSv3Volumes(1, EFI_FIRMWARE_FILE_SYSTEM3_GUID); const UINT8 ffsAlignmentTable[] = { 0, 4, 7, 9, 10, 12, 15, 16 }; +const UINT8 ffsAlignment2Table[] = +{ 17, 18, 19, 20, 21, 22, 23, 24 }; + VOID uint32ToUint24(UINT32 size, UINT8* ffsSize) { ffsSize[2] = (UINT8)((size) >> 16); diff --git a/common/ffs.h b/common/ffs.h index 61e1e84..56e1b85 100644 --- a/common/ffs.h +++ b/common/ffs.h @@ -288,7 +288,7 @@ UINT8 Type; UINT8 Attributes; UINT8 Size[3]; // Set to 0xFFFFFF UINT8 State; -UINT32 ExtendedSize; +UINT64 ExtendedSize; } EFI_FFS_FILE_HEADER2; // Standard data checksum, used if FFS_ATTRIB_CHECKSUM is clear @@ -324,6 +324,7 @@ UINT32 ExtendedSize; #define FFS_ATTRIB_TAIL_PRESENT 0x01 // Valid only for revision 1 volumes #define FFS_ATTRIB_RECOVERY 0x02 // Valid only for revision 1 volumes #define FFS_ATTRIB_LARGE_FILE 0x01 // Valid only for FFSv3 volumes +#define FFS_ATTRIB_DATA_ALIGNMENT2 0x02 // Volaid only for revision 2 volumes, added in UEFI PI 1.6 #define FFS_ATTRIB_FIXED 0x04 #define FFS_ATTRIB_DATA_ALIGNMENT 0x38 #define FFS_ATTRIB_CHECKSUM 0x40 @@ -331,6 +332,10 @@ UINT32 ExtendedSize; // FFS alignment table extern const UINT8 ffsAlignmentTable[]; +// Extended FFS alignment table, added in UEFI PI 1.6 +extern const UINT8 ffsAlignment2Table[]; + + // File states #define EFI_FILE_HEADER_CONSTRUCTION 0x01 #define EFI_FILE_HEADER_VALID 0x02 @@ -338,7 +343,7 @@ extern const UINT8 ffsAlignmentTable[]; #define EFI_FILE_MARKED_FOR_UPDATE 0x08 #define EFI_FILE_DELETED 0x10 #define EFI_FILE_HEADER_INVALID 0x20 -#define EFI_FILE_ERASE_POLARITY 0x80 // Defined as "all other bits must be set to ERASE_POLARITY" in UEFI PI Vol3 +#define EFI_FILE_ERASE_POLARITY 0x80 // Defined as "all other bits must be set to ERASE_POLARITY" in UEFI PI // PEI apriori file const UByteArray EFI_PEI_APRIORI_FILE_GUID @@ -356,10 +361,14 @@ const UByteArray EFI_FFS_VOLUME_TOP_FILE_GUID const UByteArray EFI_FFS_PAD_FILE_GUID ("\x85\x65\x53\xE4\x09\x79\x60\x4A\xB5\xC6\xEC\xDE\xA6\xEB\xFB\x54", 16); -// DXE core file -const UByteArray EFI_DXE_CORE_GUID // 5AE3F37E-4EAE-41AE-8240-35465B5E81EB +// AMI DXE core file +const UByteArray AMI_CORE_DXE_GUID // 5AE3F37E-4EAE-41AE-8240-35465B5E81EB ("\x7E\xF3\xE3\x5A\xAE\x4E\xAE\x41\x82\x40\x35\x46\x5B\x5E\x81\xEB", 16); +// EDK2 DXE code file +const UByteArray EFI_DXE_CORE_GUID // D6A2CB7F-6A18-4E2F-B43B-9920A733700A +("\x7F\xCB\xA2\xD6\x18\x6A\x2F\x4E\xB4\x3B\x99\x20\xA7\x33\x70\x0A", 16); + // FFS size conversion routines extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize); extern UINT32 uint24ToUint32(const UINT8* ffsSize); diff --git a/common/ffsbuilder.cpp b/common/ffsbuilder.cpp index d943ef8..f643082 100644 --- a/common/ffsbuilder.cpp +++ b/common/ffsbuilder.cpp @@ -193,13 +193,19 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte return result; } break; - case Subtypes::GbeRegion: case Subtypes::MeRegion: + case Subtypes::GbeRegion: + case Subtypes::DevExp1Region: + case Subtypes::Bios2Region: + case Subtypes::MicrocodeRegion: case Subtypes::EcRegion: + case Subtypes::DevExp2Region: + case Subtypes::IeRegion: + case Subtypes::Tgbe1Region: + case Subtypes::Tgbe2Region: case Subtypes::Reserved1Region: case Subtypes::Reserved2Region: - case Subtypes::Reserved3Region: - case Subtypes::Reserved4Region: + case Subtypes::PttRegion: // Add region as is region = model->header(currentRegion).append(model->body(currentRegion)); break; diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 545568f..7b27b91 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -28,6 +28,18 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "parsingdata.h" #include "types.h" +#include "nvramparser.h" +#include "meparser.h" + +#ifndef QT_CORE_LIB +namespace Qt { + enum GlobalColor { + red = 7, + cyan = 10, + yellow = 12, + }; +} +#endif // Region info structure definition struct REGION_INFO { @@ -38,6 +50,30 @@ struct REGION_INFO { friend bool operator< (const REGION_INFO & lhs, const REGION_INFO & rhs){ return lhs.offset < rhs.offset; } }; +// Constructor +FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel), +capsuleOffsetFixup(0), addressDiff(0x100000000ULL), +bgAcmFound(false), bgKeyManifestFound(false), bgBootPolicyFound(false), bgFirstVolumeOffset(0x100000000ULL) { + nvramParser = new NvramParser(treeModel, this); + meParser = new MeParser(treeModel); +} + +// Destructor +FfsParser::~FfsParser() { + delete nvramParser; + delete meParser; +} + +// Obtain parser messages +std::vector > FfsParser::getMessages() const { + std::vector > meVector = meParser->getMessages(); + std::vector > nvramVector = nvramParser->getMessages(); + std::vector > resultVector = messagesVector; + resultVector.insert(resultVector.end(), meVector.begin(), meVector.end()); + resultVector.insert(resultVector.end(), nvramVector.begin(), nvramVector.end()); + return resultVector; +} + // Firmware image parsing functions USTATUS FfsParser::parse(const UByteArray & buffer) { @@ -286,11 +322,9 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l } // BIOS region - REGION_INFO bios; - bios.type = Subtypes::BiosRegion; - bios.offset = 0; - bios.length = 0; if (regionSection->BiosLimit) { + REGION_INFO bios; + bios.type = Subtypes::BiosRegion; bios.offset = calculateRegionOffset(regionSection->BiosBase); bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); @@ -317,93 +351,22 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l return U_INVALID_FLASH_DESCRIPTOR; } - // GbE region - REGION_INFO gbe; - gbe.type = Subtypes::GbeRegion; - gbe.offset = 0; - gbe.length = 0; - if (regionSection->GbeLimit) { - gbe.offset = calculateRegionOffset(regionSection->GbeBase); - gbe.length = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); - gbe.data = intelImage.mid(gbe.offset, gbe.length); - regions.push_back(gbe); - } + // Add all other regions + for (UINT8 i = Subtypes::GbeRegion; i <= Subtypes::PttRegion; i++) { + if (descriptorVersion == 1 && i == Subtypes::MicrocodeRegion) + break; // Do not parse Microcode and other following regions for old descriptors - // PDR region - REGION_INFO pdr; - pdr.type = Subtypes::PdrRegion; - pdr.offset = 0; - pdr.length = 0; - if (regionSection->PdrLimit) { - pdr.offset = calculateRegionOffset(regionSection->PdrBase); - pdr.length = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); - pdr.data = intelImage.mid(pdr.offset, pdr.length); - regions.push_back(pdr); - } - - // Reserved1 region - REGION_INFO reserved1; - reserved1.type = Subtypes::Reserved1Region; - reserved1.offset = 0; - reserved1.length = 0; - if (regionSection->Reserved1Limit && regionSection->Reserved1Base != 0xFFFF && regionSection->Reserved1Limit != 0xFFFF) { - reserved1.offset = calculateRegionOffset(regionSection->Reserved1Base); - reserved1.length = calculateRegionSize(regionSection->Reserved1Base, regionSection->Reserved1Limit); - reserved1.data = intelImage.mid(reserved1.offset, reserved1.length); - regions.push_back(reserved1); - } - - // Reserved2 region - REGION_INFO reserved2; - reserved2.type = Subtypes::Reserved2Region; - reserved2.offset = 0; - reserved2.length = 0; - if (regionSection->Reserved2Limit && regionSection->Reserved2Base != 0xFFFF && regionSection->Reserved2Limit != 0xFFFF) { - reserved2.offset = calculateRegionOffset(regionSection->Reserved2Base); - reserved2.length = calculateRegionSize(regionSection->Reserved2Base, regionSection->Reserved2Limit); - reserved2.data = intelImage.mid(reserved2.offset, reserved2.length); - regions.push_back(reserved2); - } - - // Reserved3 region - REGION_INFO reserved3; - reserved3.type = Subtypes::Reserved3Region; - reserved3.offset = 0; - reserved3.length = 0; - - // EC region - REGION_INFO ec; - ec.type = Subtypes::EcRegion; - ec.offset = 0; - ec.length = 0; - - // Reserved4 region - REGION_INFO reserved4; - reserved3.type = Subtypes::Reserved4Region; - reserved4.offset = 0; - reserved4.length = 0; - - // Check for EC and reserved region 4 only for v2 descriptor - if (descriptorVersion == 2) { - if (regionSection->Reserved3Limit) { - reserved3.offset = calculateRegionOffset(regionSection->Reserved3Base); - reserved3.length = calculateRegionSize(regionSection->Reserved3Base, regionSection->Reserved3Limit); - reserved3.data = intelImage.mid(reserved3.offset, reserved3.length); - regions.push_back(reserved3); - } - - if (regionSection->EcLimit) { - ec.offset = calculateRegionOffset(regionSection->EcBase); - ec.length = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit); - ec.data = intelImage.mid(ec.offset, ec.length); - regions.push_back(ec); - } - - if (regionSection->Reserved4Limit) { - reserved4.offset = calculateRegionOffset(regionSection->Reserved4Base); - reserved4.length = calculateRegionSize(regionSection->Reserved4Base, regionSection->Reserved4Limit); - reserved4.data = intelImage.mid(reserved4.offset, reserved4.length); - regions.push_back(reserved4); + const UINT16* RegionBase = ((const UINT16*)regionSection) + 2 * i; + const UINT16* RegionLimit = ((const UINT16*)regionSection) + 2 * i + 1; + if (*RegionLimit && !(*RegionBase == 0xFFFF && *RegionLimit == 0xFFFF)) { + REGION_INFO region; + region.type = i; + region.offset = calculateRegionOffset(*RegionBase); + region.length = calculateRegionSize(*RegionBase, *RegionLimit); + if (region.length != 0) { + region.data = intelImage.mid(region.offset, region.length); + regions.push_back(region); + } } } @@ -556,10 +519,10 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)(descriptor + ((UINT16)upperMap->VsccTableBase << 4)); info += UString("\nFlash chips in VSCC table:"); UINT8 vsscTableSize = upperMap->VsccTableSize * sizeof(UINT32) / sizeof(VSCC_TABLE_ENTRY); + UString jedecId = jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1); for (UINT8 i = 0; i < vsscTableSize; i++) { - info += usprintf("\n%02X%02X%02X (", - vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1) - + jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1) + info += usprintf("\n%02X%02X%02X (", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1) + + jedecId + UString(")"); vsccTableEntry++; } @@ -567,6 +530,11 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l // Add descriptor tree item UModelIndex regionIndex = model->addItem(localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index); + // Show messages + if (jedecId == UString("Unknown")) { + msg(usprintf("SPI flash with unknown JEDEC ID %02X%02X%02X found in VSCC table", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1), regionIndex); + } + // Parse regions UINT8 result = U_SUCCESS; UINT8 parseResult = U_SUCCESS; @@ -585,12 +553,18 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l case Subtypes::PdrRegion: result = parsePdrRegion(region.data, region.offset, index, regionIndex); break; + case Subtypes::DevExp1Region: + case Subtypes::Bios2Region: + case Subtypes::MicrocodeRegion: + case Subtypes::EcRegion: + case Subtypes::DevExp2Region: + case Subtypes::IeRegion: + case Subtypes::Tgbe1Region: + case Subtypes::Tgbe2Region: case Subtypes::Reserved1Region: case Subtypes::Reserved2Region: - case Subtypes::Reserved3Region: - case Subtypes::EcRegion: - case Subtypes::Reserved4Region: - result = parseGeneralRegion(region.type, region.data, region.offset, index, regionIndex); + case Subtypes::PttRegion: + result = parseGenericRegion(region.type, region.data, region.offset, index, regionIndex); break; case Subtypes::ZeroPadding: case Subtypes::OnePadding: @@ -702,7 +676,7 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset msg(UString("parseMeRegion: ME version is unknown, it can be damaged"), index); } else { - meParser.parseMeRegionBody(index); + meParser->parseMeRegionBody(index); } return U_SUCCESS; @@ -729,7 +703,7 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs return U_SUCCESS; } -USTATUS FfsParser::parseGeneralRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) +USTATUS FfsParser::parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { // Check sanity if (region.isEmpty()) @@ -1184,7 +1158,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index) // Parse VSS NVRAM volumes with a dedicated function if (model->subtype(index) == Subtypes::NvramVolume) - return nvramParser.parseNvramVolumeBody(index); + return nvramParser->parseNvramVolumeBody(index); // Get required values from parsing data UINT8 emptyByte = 0xFF; @@ -1351,7 +1325,7 @@ UINT32 FfsParser::getFileSize(const UByteArray & volume, const UINT32 fileOffset return 0; const EFI_FFS_FILE_HEADER2* fileHeader = (const EFI_FFS_FILE_HEADER2*)(volume.constData() + fileOffset); if (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE) - return fileHeader->ExtendedSize; + return (UINT32) fileHeader->ExtendedSize; else return uint24ToUint32(fileHeader->Size); } @@ -1384,17 +1358,24 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf // Get file header UByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER)); - const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData(); - if (ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) { + bool largeFile = false; + EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)header.data(); + if (ffsVersion == 3 && (tempFileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) { if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2)) return U_INVALID_FILE; header = file.left(sizeof(EFI_FFS_FILE_HEADER2)); + largeFile = true; } + const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData(); // Check file alignment bool msgUnalignedFile = false; UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; - UINT32 alignment = (UINT32)pow(2.0, alignmentPower); + if (volumeRevision > 1 && (fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2)) { + alignmentPower = ffsAlignment2Table[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; + } + + UINT32 alignment = (UINT32)(1UL << alignmentPower); if ((localOffset + header.size()) % alignment) msgUnalignedFile = true; @@ -1403,45 +1384,6 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf if (!isWeakAligned && volumeAlignment < alignment) msgFileAlignmentIsGreaterThanVolumeAlignment = true; - // Check header checksum - UByteArray tempHeader = header; - EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)(tempHeader.data()); - tempFileHeader->IntegrityCheck.Checksum.Header = 0; - tempFileHeader->IntegrityCheck.Checksum.File = 0; - UINT8 calculatedHeader = calculateChecksum8((const UINT8*)tempFileHeader, header.size() - 1); - bool msgInvalidHeaderChecksum = false; - if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader) - msgInvalidHeaderChecksum = true; - - // Check data checksum - // Data checksum must be calculated - bool msgInvalidDataChecksum = false; - UINT8 calculatedData = 0; - if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { - UINT32 bufferSize = file.size() - header.size(); - // Exclude file tail from data checksum calculation - if (volumeRevision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) - bufferSize -= sizeof(UINT16); - calculatedData = calculateChecksum8((const UINT8*)(file.constData() + header.size()), bufferSize); - if (fileHeader->IntegrityCheck.Checksum.File != calculatedData) - msgInvalidDataChecksum = true; - } - // Data checksum must be one of predefined values - else if (volumeRevision == 1 && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) { - calculatedData = FFS_FIXED_CHECKSUM; - msgInvalidDataChecksum = true; - } - else if (volumeRevision == 2 && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2) { - calculatedData = FFS_FIXED_CHECKSUM2; - msgInvalidDataChecksum = true; - } - - // Check file type - bool msgUnknownType = false; - if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) { - msgUnknownType = true; - }; - // Get file body UByteArray body = file.mid(header.size()); @@ -1459,6 +1401,36 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf body = body.left(body.size() - sizeof(UINT16)); } + // Check header checksum + UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State); + bool msgInvalidHeaderChecksum = false; + if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader) + msgInvalidHeaderChecksum = true; + + // Check data checksum + // Data checksum must be calculated + bool msgInvalidDataChecksum = false; + UINT8 calculatedData = 0; + if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { + calculatedData = calculateChecksum8((const UINT8*)body.constData(), body.size()); + } + // Data checksum must be one of predefined values + else if (volumeRevision == 1) { + calculatedData = FFS_FIXED_CHECKSUM; + } + else { + calculatedData = FFS_FIXED_CHECKSUM2; + } + + if (fileHeader->IntegrityCheck.Checksum.File != calculatedData) + msgInvalidDataChecksum = true; + + // Check file type + bool msgUnknownType = false; + if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) { + msgUnknownType = true; + }; + // Get info UString name; UString info; @@ -1492,9 +1464,9 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf text = UString("Volume Top File"); } // Check if the file is the first DXE Core - else if (fileGuid == EFI_DXE_CORE_GUID) { - // Mark is as first DXE code - // This information may be used to determine DXE volume offset for old AMI protected ranges + else if (fileGuid == EFI_DXE_CORE_GUID || fileGuid == AMI_CORE_DXE_GUID) { + // Mark is as first DXE core + // This information may be used to determine DXE volume offset for old AMI or post-IBB protected ranges isDxeCore = true; } @@ -1579,7 +1551,7 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index) // Parse NVAR store if (fileGuid == NVRAM_NVAR_STORE_FILE_GUID) - return nvramParser.parseNvarStore(index); + return nvramParser->parseNvarStore(index); // Parse vendor hash file else if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) @@ -2699,7 +2671,7 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index) } else if (parentFileGuid == NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID) { // AMI NVRAM external defaults // Parse NVAR area - nvramParser.parseNvarStore(index); + nvramParser->parseNvarStore(index); // Set parent file text model->setText(parentFile, UString("NVRAM external defaults")); @@ -2709,7 +2681,6 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index) parseVendorHashFile(parentFileGuid, index); } - // Parse as raw area return parseRawArea(index); } @@ -3009,9 +2980,9 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) UByteArray protectedParts; bool bgProtectedRangeFound = false; for (UINT32 i = 0; i < (UINT32)bgProtectedRanges.size(); i++) { - if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD) { + if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB) { bgProtectedRangeFound = true; - bgProtectedRanges[i].Offset -= addressDiff; + bgProtectedRanges[i].Offset -= (UINT32)addressDiff; protectedParts += openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); markProtectedRangeRecursive(index, bgProtectedRanges[i]); } @@ -3019,7 +2990,7 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) if (bgProtectedRangeFound) { UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); - sha256(protectedParts.constData(), protectedParts.length(), digest.data()); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); if (digest != bgBpDigest) { msg(UString("checkProtectedRanges: BG-protected ranges hash mismatch, opened image may refuse to boot"), index); @@ -3031,7 +3002,8 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) // Calculate digests for vendor-protected ranges for (UINT32 i = 0; i < (UINT32)bgProtectedRanges.size(); i++) { - if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD) { + if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF) { if (!bgDxeCoreIndex.isValid()) { msg(UString("checkProtectedRanges: can't determine DXE volume offset, old AMI protected range hash can't be checked"), index); } @@ -3046,10 +3018,10 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); - sha256(protectedParts.constData(), protectedParts.length(), digest.data()); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); if (digest != bgProtectedRanges[i].Hash) { - msg(usprintf("checkProtectedRanges: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", + msg(usprintf("checkProtectedRanges: old AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), model->findByOffset(bgProtectedRanges[i].Offset)); } @@ -3058,12 +3030,44 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) } } } - else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW) { - bgProtectedRanges[i].Offset -= addressDiff; + else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB) { + if (!bgDxeCoreIndex.isValid()) { + msg(UString("checkProtectedRanges: can't determine DXE volume offset, post-IBB protected range hash can't be checked"), index); + } + else { + // Offset will be determined as the offset of root volume with first DXE core + UModelIndex dxeRootVolumeIndex = model->findLastParentOfType(bgDxeCoreIndex, Types::Volume); + if (!dxeRootVolumeIndex.isValid()) { + msg(UString("checkProtectedRanges: can't determine DXE volume offset, post-IBB protected range hash can't be checked"), index); + } + else + { + bgProtectedRanges[i].Offset = model->offset(dxeRootVolumeIndex); + bgProtectedRanges[i].Size = model->header(dxeRootVolumeIndex).size() + model->body(dxeRootVolumeIndex).size() + model->tail(dxeRootVolumeIndex).size(); + protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); + + UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); + + if (digest != bgProtectedRanges[i].Hash) { + msg(usprintf("checkProtectedRanges: post-IBB protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", + bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), + model->findByOffset(bgProtectedRanges[i].Offset)); + } + + markProtectedRangeRecursive(index, bgProtectedRanges[i]); + } + } + } + else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF + && bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { + + bgProtectedRanges[i].Offset -= (UINT32)addressDiff; protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); - sha256(protectedParts.constData(), protectedParts.length(), digest.data()); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("checkProtectedRanges: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", @@ -3073,12 +3077,14 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) markProtectedRangeRecursive(index, bgProtectedRanges[i]); } - else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX) { - bgProtectedRanges[i].Offset += bgFirstVolumeOffset; + else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF + && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { + bgProtectedRanges[i].Offset += (UINT32)bgFirstVolumeOffset; protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); - sha256(protectedParts.constData(), protectedParts.length(), digest.data()); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("checkProtectedRanges: Phoenix protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", @@ -3088,12 +3094,14 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) markProtectedRangeRecursive(index, bgProtectedRanges[i]); } - else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT) { - bgProtectedRanges[i].Offset -= addressDiff; + else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF + && bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { + bgProtectedRanges[i].Offset -= (UINT32)addressDiff; protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); - sha256(protectedParts.constData(), protectedParts.length(), digest.data()); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("checkProtectedRanges: Microsoft protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", @@ -3125,7 +3133,7 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const if (std::min(currentOffset + currentSize, range.Offset + range.Size) > std::max(currentOffset, range.Offset)) { if (range.Offset <= currentOffset && currentOffset + currentSize <= range.Offset + range.Size) { // Mark as fully in range - model->setMarking(index, range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD ? Qt::red : Qt::cyan); + model->setMarking(index, range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ? Qt::red : Qt::cyan); } else { // Mark as partially in range model->setMarking(index, Qt::yellow); @@ -3579,6 +3587,15 @@ USTATUS FfsParser::parseIntelBootGuardKeyManifest(const UByteArray & keyManifest header->KmSvn, header->KmId ); + + // Add hash of Key Manifest PubKey, this hash will be written to FPFs + UINT8 hash[SHA256_DIGEST_SIZE]; + sha256(&header->KeyManifestSignature.PubKey.Modulus, sizeof(header->KeyManifestSignature.PubKey.Modulus), hash); + bootGuardInfo += UString("\n\nKey Manifest RSA Public Key Hash:\n"); + for (UINT8 i = 0; i < sizeof(hash); i++) { + bootGuardInfo += usprintf("%02X", hash[i]); + } + // Add BpKeyHash bootGuardInfo += UString("\n\nBoot Policy RSA Public Key Hash:\n"); for (UINT8 i = 0; i < sizeof(header->BpKeyHash.HashBuffer); i++) { @@ -3702,11 +3719,22 @@ USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy, elementHeader->PmrlLimit, elementHeader->EntryPoint ); + // Add PostIbbHash bootGuardInfo += UString("\n\nPost IBB Hash:\n"); for (UINT8 i = 0; i < sizeof(elementHeader->IbbHash.HashBuffer); i++) { bootGuardInfo += usprintf("%02X", elementHeader->IbbHash.HashBuffer[i]); } + + // Check for non-empry PostIbbHash + UByteArray postIbbHash((const char*)elementHeader->IbbHash.HashBuffer, sizeof(elementHeader->IbbHash.HashBuffer)); + if (postIbbHash.count('\x00') != postIbbHash.size() && postIbbHash.count('\xFF') != postIbbHash.size()) { + BG_PROTECTED_RANGE range; + range.Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB; + range.Hash = postIbbHash; + bgProtectedRanges.push_back(range); + } + // Add Digest bgBpDigest = UByteArray((const char*)elementHeader->Digest.HashBuffer, sizeof(elementHeader->Digest.HashBuffer)); bootGuardInfo += UString("\n\nIBB Digest:\n"); @@ -3724,7 +3752,7 @@ USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy, BG_PROTECTED_RANGE range; range.Offset = segments[i].Base; range.Size = segments[i].Size; - range.Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD; + range.Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB; bgProtectedRanges.push_back(range); } } diff --git a/common/ffsparser.h b/common/ffsparser.h index 8493d49..496bcb0 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -1,6 +1,6 @@ /* ffsparser.h -Copyright (c) 2016, Nikolaj Schlej. All rights reserved. +Copyright (c) 2017, LongSoft. All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -19,8 +19,6 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "ustring.h" #include "ubytearray.h" #include "treemodel.h" -#include "nvramparser.h" -#include "meparser.h" #include "bootguard.h" typedef struct BG_PROTECTED_RANGE_ @@ -31,31 +29,25 @@ typedef struct BG_PROTECTED_RANGE_ UByteArray Hash; } BG_PROTECTED_RANGE; -#define BG_PROTECTED_RANGE_INTEL_BOOT_GUARD 0x01 -#define BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX 0x02 -#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD 0x03 -#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW 0x04 -#define BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT 0x05 +#define BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB 0x01 +#define BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB 0x02 +#define BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX 0x03 +#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD 0x04 +#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW 0x05 +#define BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT 0x06 + +class NvramParser; +class MeParser; class FfsParser { public: - // Default constructor and destructor - FfsParser(TreeModel* treeModel) : model(treeModel), nvramParser(treeModel), meParser(treeModel), - capsuleOffsetFixup(0), addressDiff(0x100000000ULL), - bgAcmFound(false), bgKeyManifestFound(false), bgBootPolicyFound(false), bgFirstVolumeOffset(0x100000000ULL) {} - ~FfsParser() {} + // Constructor and destructor + FfsParser(TreeModel* treeModel); + ~FfsParser(); // Obtain parser messages - std::vector > getMessages() const { - std::vector > meVector = meParser.getMessages(); - std::vector > nvramVector = nvramParser.getMessages(); - std::vector > resultVector = messagesVector; - resultVector.insert(resultVector.end(), meVector.begin(), meVector.end()); - resultVector.insert(resultVector.end(), nvramVector.begin(), nvramVector.end()); - return resultVector; - } - + std::vector > getMessages() const; // Clear messages void clearMessages() { messagesVector.clear(); } @@ -78,8 +70,8 @@ private: messagesVector.push_back(std::pair(message, index)); }; - NvramParser nvramParser; - MeParser meParser; + NvramParser* nvramParser; + MeParser* meParser; UByteArray openedImage; UModelIndex lastVtf; @@ -114,7 +106,7 @@ private: USTATUS parseMeRegion(const UByteArray & me, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseBiosRegion(const UByteArray & bios, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parsePdrRegion(const UByteArray & pdr, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseGeneralRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); + USTATUS parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parsePadFileBody(const UModelIndex & index); USTATUS parseVolumeNonUefiData(const UByteArray & data, const UINT32 localOffset, const UModelIndex & index); @@ -163,6 +155,10 @@ private: USTATUS parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize); USTATUS findNextElement(const UByteArray & bootPolicy, const UINT32 elementOffset, UINT32 & nextElementOffset, UINT32 & nextElementSize); #endif + +#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT + friend class NvramParser; // Make FFS parsing routines accessible to NvramParser +#endif }; #endif // FFSPARSER_H diff --git a/common/nvram.h b/common/nvram.h index 4cfb7c5..7b9c423 100644 --- a/common/nvram.h +++ b/common/nvram.h @@ -171,29 +171,32 @@ typedef struct VSS_AUTH_VARIABLE_HEADER_ { extern UString vssAttributesToUString(const UINT32 attributes); // -// Lenovo VSS variables +// VSS2 variables // -//aaf32c78-947b-439a-a180-2e144ec37792 -#define LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 0xaaf32c78 -const UByteArray LENOVO_AUTH_VAR_KEY_DATABASE_GUID +// aaf32c78-947b-439a-a180-2e144ec37792 +#define NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 0xaaf32c78 +const UByteArray NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID ("\x78\x2C\xF3\xAA\x7B\x94\x9A\x43\xA1\x80\x2E\x14\x4E\xC3\x77\x92"); -#define LENOVO_VSS_STORE_GUID_PART1 0xddcf3617 -const UByteArray LENOVO_VSS_STORE_GUID +#define NVRAM_VSS2_STORE_GUID_PART1 0xddcf3617 +const UByteArray NVRAM_VSS2_STORE_GUID ("\x17\x36\xCF\xDD\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D"); +const UByteArray NVRAM_FDC_STORE_GUID +("\x16\x36\xCF\xDD\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D"); + // Variable store header -typedef struct LENOVO_VSS_VARIABLE_STORE_HEADER_ { - EFI_GUID Signature; +typedef struct VSS2_VARIABLE_STORE_HEADER_ { + EFI_GUID Signature; // VSS2 Store Guid UINT32 Size; // Size of variable store, including store header UINT8 Format; // Store format state UINT8 State; // Store health state UINT16 Unknown; UINT32 : 32; -} LENOVO_VSS_VARIABLE_STORE_HEADER; +} VSS2_VARIABLE_STORE_HEADER; -// VSS entries are 4-bytes aligned in Lenovo stores +// VSS2 entries are 4-bytes aligned in VSS2 stores // // _FDC region @@ -220,7 +223,7 @@ const UByteArray EDKII_WORKING_BLOCK_SIGNATURE_GUID ("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 16); // 9E58292B-7C68-497D-A0CE6500FD9F1B95 -const UByteArray LENOVO_WORKING_BLOCK_SIGNATURE_GUID +const UByteArray VSS2_WORKING_BLOCK_SIGNATURE_GUID ("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\xA0\xCE\x65\x00\xFD\x9F\x1B\x95", 16); #define NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 0xFFF12B8D diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index d71b790..9fbcd73 100644 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -78,13 +78,13 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) UByteArray header; UByteArray body; UByteArray tail; - + UINT32 guidAreaSize = guidsInStore * sizeof(EFI_GUID); UINT32 unparsedSize = (UINT32)data.size() - offset - guidAreaSize; // Get entry header const NVAR_ENTRY_HEADER* entryHeader = (const NVAR_ENTRY_HEADER*)(data.constData() + offset); - + // Check header size and signature if (unparsedSize < sizeof(NVAR_ENTRY_HEADER) || entryHeader->Signature != NVRAM_NVAR_ENTRY_SIGNATURE || @@ -109,7 +109,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Add tree item model->addItem(localOffset + offset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Add GUID store area UByteArray guidArea = data.right(guidAreaSize); // Get info @@ -122,13 +122,13 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) return U_SUCCESS; } - + // Contruct generic header and body header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER)); body = data.mid(offset + sizeof(NVAR_ENTRY_HEADER), entryHeader->Size - sizeof(NVAR_ENTRY_HEADER)); UINT32 lastVariableFlag = emptyByte ? 0xFFFFFF : 0; - + // Set default next to predefined last value NVAR_ENTRY_PARSING_DATA pdata; pdata.emptyByte = emptyByte; @@ -146,7 +146,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) subtype = Subtypes::LinkNvarEntry; pdata.next = entryHeader->Next; } - + // Entry with extended header if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_EXT_HEADER) { hasExtendedHeader = true; @@ -181,7 +181,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) } // Include entry attributes calculatedChecksum += entryHeader->Attributes; - + hasChecksum = true; msgUnknownExtDataFormat = false; } @@ -204,7 +204,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) msgUnknownExtDataFormat = false; } else { // Full or link variable have hash - if ((UINT32)tail.size() < sizeof(UINT64) + SHA256_HASH_SIZE) { + if ((UINT32)tail.size() < sizeof(UINT64) + SHA256_HASH_SIZE) { msgExtDataTooShort = true; isInvalid = true; // Do not parse further @@ -287,7 +287,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER) + nameOffset + nameSize); body = body.mid(nameOffset + nameSize); } -parsing_done: + parsing_done: UString info; // Rename invalid entries according to their types @@ -304,7 +304,7 @@ parsing_done: } else // Add GUID info for valid entries info += UString("Variable GUID: ") + guid + UString("\n"); - + // Add GUID index information if (hasGuidIndex) info += usprintf("GUID index: %u\n", guidIndex); @@ -314,13 +314,13 @@ parsing_done: entryHeader->Size, entryHeader->Size, header.size(), header.size(), body.size(), body.size()); - + // Add attributes info info += usprintf("\nAttributes: %02Xh", entryHeader->Attributes); // Translate attributes to text if (entryHeader->Attributes && entryHeader->Attributes != 0xFF) info += UString(" (") + nvarAttributesToUString(entryHeader->Attributes) + UString(")"); - + // Add next node info if (!isInvalid && entryHeader->Next != lastVariableFlag) info += usprintf("\nNext node at offset: %Xh", localOffset + offset + entryHeader->Next); @@ -334,17 +334,17 @@ parsing_done: // Add checksum if (hasChecksum) info += usprintf("\nChecksum: %02Xh", storedChecksum) + - (calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid")); - + (calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid")); + // Add timestamp - if (hasTimestamp) + if (hasTimestamp) info += usprintf("\nTimestamp: %" PRIX64 "h", timestamp); - + // Add hash - if (hasHash) + if (hasHash) info += UString("\nHash: ") + UString(hash.toHex().constData()); } - + // Add tree item UModelIndex varIndex = model->addItem(localOffset + offset, Types::NvarEntry, subtype, name, text, info, header, body, tail, Movable, index); @@ -354,19 +354,19 @@ parsing_done: // Show messages if (msgUnknownExtDataFormat) msg(UString("parseNvarStore: unknown extended data format"), varIndex); if (msgExtHeaderTooLong) msg(usprintf("parseNvarStore: extended header size (%Xh) is greater than body size (%Xh)", - extendedHeaderSize, body.size()), varIndex); + extendedHeaderSize, body.size()), varIndex); if (msgExtDataTooShort) msg(usprintf("parseNvarStore: extended header size (%Xh) is too small for timestamp and hash", - tail.size()), varIndex); + tail.size()), varIndex); // Try parsing the entry data as NVAR storage if it begins with NVAR signature - if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry) + if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry) && *(const UINT32*)body.constData() == NVRAM_NVAR_ENTRY_SIGNATURE) parseNvarStore(varIndex); - + // Move to next exntry offset += entryHeader->Size; } - + return U_SUCCESS; } @@ -496,15 +496,15 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.child(i, 0); switch (model->type(current)) { - case Types::VssStore: - case Types::FdcStore: parseVssStoreBody(current, 0); break; - case Types::LenovoVssStore: parseVssStoreBody(current, 4); break; - case Types::FsysStore: parseFsysStoreBody(current); break; - case Types::EvsaStore: parseEvsaStoreBody(current); break; - case Types::FlashMapStore: parseFlashMapBody(current); break; + case Types::FdcStore: return parseFdcStoreBody(current); + case Types::VssStore: return parseVssStoreBody(current, 0); + case Types::Vss2Store: return parseVssStoreBody(current, 4); + case Types::FsysStore: return parseFsysStoreBody(current); + case Types::EvsaStore: return parseEvsaStoreBody(current); + case Types::FlashMapStore: return parseFlashMapBody(current); } } - + return U_SUCCESS; } @@ -531,18 +531,18 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == LENOVO_VSS_STORE_GUID_PART1) { //Lenovo VSS store signatures found, perform checks + else if (*currentPos == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == NVRAM_VSS2_STORE_GUID_PART1) { //VSS2 store signatures found, perform checks UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); - if (guid != LENOVO_AUTH_VAR_KEY_DATABASE_GUID && guid != LENOVO_VSS_STORE_GUID) // Check the whole signature + if (guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID && guid != NVRAM_VSS2_STORE_GUID) // Check the whole signature continue; - const LENOVO_VSS_VARIABLE_STORE_HEADER* vssHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)currentPos; + const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)currentPos; if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) { - msg(usprintf("findNextStore: Lenovo VSS store candidate at offset %Xh skipped, has invalid format %02Xh", localOffset + offset, vssHeader->Format), index); + msg(usprintf("findNextStore: VSS2 store candidate at offset %Xh skipped, has invalid format %02Xh", localOffset + offset, vssHeader->Format), index); continue; } if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) { - msg(usprintf("findNextStore: Lenovo VSS store candidate at offset %Xh skipped, has invalid size %Xh", localOffset + offset, vssHeader->Size), index); + msg(usprintf("findNextStore: VSS2 store candidate at offset %Xh skipped, has invalid size %Xh", localOffset + offset, vssHeader->Size), index); continue; } // All checks passed, store found @@ -585,7 +585,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & } else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *currentPos == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { //Possible FTW block signature found UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); - if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != LENOVO_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature + if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != VSS2_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature continue; // Detect header variant based on WriteQueueSize @@ -659,11 +659,11 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & break; } else if (*currentPos == OEM_ACTIVATION_MARKER_WINDOWS_FLAG_PART1) { // SLIC marker - if (offset >= dataSize - sizeof(UINT64) || + if (offset >= dataSize - sizeof(UINT64) || *(const UINT64*)currentPos != OEM_ACTIVATION_MARKER_WINDOWS_FLAG || offset < 26) // Check full windows flag and structure size continue; - + const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)(volume.constData() + offset - 26); // Check reserved bytes bool reservedBytesValid = true; @@ -696,8 +696,8 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature; storeSize = vssHeader->Size; } - else if (*signature == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == LENOVO_VSS_STORE_GUID_PART1) { - const LENOVO_VSS_VARIABLE_STORE_HEADER* vssHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)signature; + else if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1) { + const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)signature; storeSize = vssHeader->Size; } else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) { @@ -744,10 +744,10 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff return U_SUCCESS; } -USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) +USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (const UINT32)store.size(); - + // Check store size if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) { msg(UString("parseVssStoreHeader: volume body is too small even for VSS store header"), parent); @@ -757,28 +757,34 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 // Get VSS store header const VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS_VARIABLE_STORE_HEADER*)store.constData(); + // Check for size override + UINT32 storeSize = vssStoreHeader->Size; + if (sizeOverride) { + storeSize = dataSize; + } + // Check store size - if (dataSize < vssStoreHeader->Size) { + if (dataSize < storeSize) { msg(usprintf("parseVssStoreHeader: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)", - vssStoreHeader->Size, vssStoreHeader->Size, + storeSize, storeSize, dataSize, dataSize), parent); return U_SUCCESS; } // Construct header and body UByteArray header = store.left(sizeof(VSS_VARIABLE_STORE_HEADER)); - UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), vssStoreHeader->Size - sizeof(VSS_VARIABLE_STORE_HEADER)); + UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS_VARIABLE_STORE_HEADER)); // Add info bool isSvsStore = (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE); UString name = isSvsStore ? UString("SVS store") : UString("VSS store"); UString info = usprintf("Signature: %s\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", isSvsStore ? "$SVS" : "$VSS", - vssStoreHeader->Size, vssStoreHeader->Size, + storeSize, storeSize, header.size(), header.size(), body.size(), body.size(), vssStoreHeader->Format, - vssStoreHeader->State, + vssStoreHeader->State, vssStoreHeader->Unknown); // Add tree item @@ -787,44 +793,50 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 return U_SUCCESS; } -USTATUS NvramParser::parseLenovoVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) +USTATUS NvramParser::parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (const UINT32)store.size(); // Check store size - if (dataSize < sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)) { - msg(UString("parseLenovoVssStoreHeader: volume body is too small even for VSS store header"), parent); + if (dataSize < sizeof(VSS2_VARIABLE_STORE_HEADER)) { + msg(UString("parseVss2StoreHeader: volume body is too small even for VSS2 store header"), parent); return U_SUCCESS; } - // Get VSS store header - const LENOVO_VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)store.constData(); + // Get VSS2 store header + const VSS2_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS2_VARIABLE_STORE_HEADER*)store.constData(); + + // Check for size override + UINT32 storeSize = vssStoreHeader->Size; + if (sizeOverride) { + storeSize = dataSize; + } // Check store size - if (dataSize < vssStoreHeader->Size) { - msg(usprintf("parseLenovoVssStoreHeader: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)", - vssStoreHeader->Size, vssStoreHeader->Size, + if (dataSize < storeSize) { + msg(usprintf("parseVssStoreHeader: VSS2 store size %Xh (%u) is greater than volume body size %Xh (%u)", + storeSize, storeSize, dataSize, dataSize), parent); return U_SUCCESS; } // Construct header and body - UByteArray header = store.left(sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)); - UByteArray body = store.mid(sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER), vssStoreHeader->Size - sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)); + UByteArray header = store.left(sizeof(VSS2_VARIABLE_STORE_HEADER)); + UByteArray body = store.mid(sizeof(VSS2_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS2_VARIABLE_STORE_HEADER)); // Add info - UString name = UString("Lenovo VSS store"); + UString name = UString("VSS2 store"); UString info = UString("Signature: ") + guidToUString(vssStoreHeader->Signature, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", - vssStoreHeader->Size, vssStoreHeader->Size, - header.size(), header.size(), - body.size(), body.size(), - vssStoreHeader->Format, - vssStoreHeader->State, - vssStoreHeader->Unknown); + storeSize, storeSize, + header.size(), header.size(), + body.size(), body.size(), + vssStoreHeader->Format, + vssStoreHeader->State, + vssStoreHeader->Unknown); // Add tree item - index = model->addItem(localOffset, Types::LenovoVssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); + index = model->addItem(localOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); return U_SUCCESS; } @@ -886,12 +898,12 @@ USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 UString name("FTW store"); UString info = UString("Signature: ") + guidToUString(ftw32BlockHeader->Signature, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh", - ftwBlockSize, ftwBlockSize, - headerSize, headerSize, - body.size(), body.size(), - ftw32BlockHeader->State, - ftw32BlockHeader->Crc) + - (ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); + ftwBlockSize, ftwBlockSize, + headerSize, headerSize, + body.size(), body.size(), + ftw32BlockHeader->State, + ftw32BlockHeader->Crc) + + (ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); // Add tree item index = model->addItem(localOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); @@ -920,29 +932,11 @@ USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32 return U_SUCCESS; } - // Determine internal volume header size - const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(fdcStoreHeader + 1); - UINT32 headerSize; - if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { - const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)((const UINT8*)volumeHeader + volumeHeader->ExtHeaderOffset); - headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize; - } - else - headerSize = volumeHeader->HeaderLength; - - // Extended header end can be unaligned - headerSize = ALIGN8(headerSize); - - // Add VSS store header - headerSize += sizeof(VSS_VARIABLE_STORE_HEADER); - - // Add FDC header - headerSize += sizeof(FDC_VOLUME_HEADER); - - // Check sanity of combined header size + // Check header size + UINT32 headerSize = sizeof(FDC_VOLUME_HEADER); if (dataSize < headerSize) { msg(usprintf("parseFdcStoreHeader: FDC store header size %Xh (%u) is greater than volume body size %Xh (%u)", - fdcStoreHeader->Size,fdcStoreHeader->Size, + fdcStoreHeader->Size, fdcStoreHeader->Size, dataSize, dataSize), parent); return U_SUCCESS; } @@ -958,8 +952,6 @@ USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32 header.size(), header.size(), body.size(), body.size()); - // TODO: add internal headers info - // Add tree item index = model->addItem(localOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); @@ -1003,7 +995,7 @@ USTATUS NvramParser::parseFsysStoreHeader(const UByteArray & store, const UINT32 fsysStoreHeader->Size, fsysStoreHeader->Size, header.size(), header.size(), body.size(), body.size(), - fsysStoreHeader->Unknown0, + fsysStoreHeader->Unknown0, fsysStoreHeader->Unknown1) + (storedCrc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); @@ -1101,7 +1093,7 @@ USTATUS NvramParser::parseFlashMapStoreHeader(const UByteArray & store, const UI USTATUS NvramParser::parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (const UINT32)store.size(); - + // Check store size if (dataSize < sizeof(PHOENIX_CMDB_HEADER)) { msg(UString("parseCmdbStoreHeader: volume body is too small even for CMDB store header"), parent); @@ -1208,7 +1200,7 @@ USTATUS NvramParser::parseSlicMarkerHeader(const UByteArray & store, const UINT3 "Version: %08Xh\nOEM ID: %s\nOEM table ID: %s\nWindows flag: WINDOWS\nSLIC version: %08Xh", markerHeader->Size, markerHeader->Size, header.size(), header.size(), - markerHeader->Version, + markerHeader->Version, (const char*)UString((const char*)&(markerHeader->OemId)).left(6).toLocal8Bit(), (const char*)UString((const char*)&(markerHeader->OemTableId)).left(8).toLocal8Bit(), markerHeader->SlicVersion); @@ -1257,10 +1249,10 @@ USTATUS NvramParser::parseIntelMicrocodeHeader(const UByteArray & store, const U ucodeHeader->DateDay, ucodeHeader->DateMonth, ucodeHeader->DateYear, - ucodeHeader->CpuSignature, + ucodeHeader->CpuSignature, ucodeHeader->Revision, - ucodeHeader->Checksum, - ucodeHeader->LoaderRevision, + ucodeHeader->Checksum, + ucodeHeader->LoaderRevision, ucodeHeader->CpuFlags); // Add tree item @@ -1281,28 +1273,28 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc // Check signature and run parser function needed // VSS/SVS store - if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) - return parseVssStoreHeader(store, localOffset, parent, index); - // Lenovo VSS store - if (*signature == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == LENOVO_VSS_STORE_GUID_PART1) - return parseLenovoVssStoreHeader(store, localOffset, parent, index); + if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) + return parseVssStoreHeader(store, localOffset, false, parent, index); + // VSS2 store + if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1) + return parseVss2StoreHeader(store, localOffset, false, parent, index); // FTW store - else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) + else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) return parseFtwStoreHeader(store, localOffset, parent, index); // FDC store - else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) + else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) return parseFdcStoreHeader(store, localOffset, parent, index); // Apple Fsys/Gaid store - else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) + else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) return parseFsysStoreHeader(store, localOffset, parent, index); // EVSA store - else if (*(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE) + else if (*(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE) return parseEvsaStoreHeader(store, localOffset, parent, index); // Phoenix SCT flash map - else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) + else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) return parseFlashMapStoreHeader(store, localOffset, parent, index); // Phoenix CMDB store - else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) + else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) return parseCmdbStoreHeader(store, localOffset, parent, index); // SLIC pubkey else if (*(signature + 4) == OEM_ACTIVATION_PUBKEY_MAGIC) @@ -1319,6 +1311,49 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc return U_SUCCESS; } +USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index) +{ + // Sanity check + if (!index.isValid()) + return U_INVALID_PARAMETER; + + // Get item data + const UByteArray data = model->body(index); + + // Get local offset + UINT32 localOffset = model->offset(index) + model->header(index).size(); + + // The body is a firmware volume with either a VSS or VSS2 store + UModelIndex volumeIndex; + USTATUS status = ffsParser->parseVolumeHeader(data, localOffset, index, volumeIndex); + if (status || !volumeIndex.isValid()) { + msg(UString("parseFdcStoreBody: store can't be parsed as FDC store"), index); + return U_SUCCESS; + } + + // Determine if it's a VSS or VSS2 store inside + UByteArray store = model->body(volumeIndex); + if (store.size() >= sizeof(UINT32) && *(const UINT32*)store.constData() == NVRAM_VSS_STORE_SIGNATURE) { + UModelIndex vssIndex; + status = parseVssStoreHeader(store, localOffset + model->header(volumeIndex).size(), true, volumeIndex, vssIndex); + if (status) + return status; + return parseVssStoreBody(vssIndex, 0); + } + else if (store.size() >= sizeof(EFI_GUID) && store.left(sizeof(EFI_GUID)) == NVRAM_FDC_STORE_GUID) { + UModelIndex vss2Index; + status = parseVss2StoreHeader(store, localOffset + model->header(volumeIndex).size(), true, volumeIndex, vss2Index); + if (status) + return status; + return parseVssStoreBody(vss2Index, 0); + } + else { + msg(UString("parseFdcStoreBody: internal volume can't be parsed as VSS/VSS2 store"), index); + return U_SUCCESS; + } + +} + USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment) { // Sanity check @@ -1346,7 +1381,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen msg(UString("parseVssStoreBody: store body is too small even for VSS variable header"), index); return U_SUCCESS; } - + UINT32 offset = 0; // Parse all variables @@ -1355,7 +1390,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen bool isAuthenticated = false; bool isAppleCrc32 = false; bool isIntelSpecial = false; - + UINT32 storedCrc32 = 0; UINT32 calculatedCrc32 = 0; UINT64 monotonicCounter = 0; @@ -1489,7 +1524,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen } UString info; - + // Rename invalid variables if (isInvalid) { name = UString("Invalid"); @@ -1504,7 +1539,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen info += usprintf("Full size: %Xh (%u)\nHeader size %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (", variableSize, variableSize, header.size(), header.size(), - body.size(), body.size(), + body.size(), body.size(), variableHeader->State, variableHeader->Reserved, variableHeader->Attributes) + vssAttributesToUString(variableHeader->Attributes) + UString(")"); @@ -1568,7 +1603,7 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) UINT8 nameSize = *(UINT8*)(data.constData() + offset); bool valid = !(nameSize & 0x80); // Last bit is a validity bit, 0 means valid nameSize &= 0x7F; - + // Check sanity if (unparsedSize >= nameSize + sizeof(UINT8)) { variableSize = nameSize + sizeof(UINT8); @@ -1582,7 +1617,7 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) // There is no data afterward, add EOF variable and free space and return UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize); UString info = usprintf("Full size: %Xh (%u)", header.size(), header.size()); - + // Add EOF tree item model->addItem(localOffset + offset, Types::FsysEntry, Subtypes::NormalFsysEntry, UString("EOF"), UString(), info, header, UByteArray(), UByteArray(), Fixed, index); @@ -1610,7 +1645,7 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) // Add padding tree item model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + // Show message msg(UString("parseFsysStoreBody: next variable appears too big, added as padding"), index); @@ -1633,7 +1668,7 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) // Move to next variable offset += variableSize; } - + return U_SUCCESS; } @@ -1703,7 +1738,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) calculated = calculateChecksum8(((const UINT8*)entryHeader) + 2, entryHeader->Size - 2); // GUID entry - if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID1 || + if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID1 || entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID2) { const EVSA_GUID_ENTRY* guidHeader = (const EVSA_GUID_ENTRY*)entryHeader; header = data.mid(offset, sizeof(EVSA_GUID_ENTRY)); @@ -1733,7 +1768,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) header.size(), header.size(), body.size(), body.size(), nameHeader->Header.Type, - nameHeader->Header.Checksum) + nameHeader->Header.Checksum) + (nameHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + usprintf("\nVarId: %04Xh", nameHeader->VarId); subtype = Subtypes::NameEvsaEntry; @@ -1765,9 +1800,9 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) dataHeader->Header.Checksum) + (dataHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (", - dataHeader->VarId, - dataHeader->GuidId, - dataHeader->Attributes) + dataHeader->VarId, + dataHeader->GuidId, + dataHeader->Attributes) + evsaAttributesToUString(dataHeader->Attributes) + UString(")"); subtype = Subtypes::DataEvsaEntry; } @@ -1786,7 +1821,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) // Show message msg(usprintf("parseEvsaStoreBody: unknown variable of type %02Xh found at offset %Xh, the rest of unparsed store added as padding", entryHeader->Type, offset), itemIndex); - } + } break; } @@ -1805,12 +1840,12 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) UByteArray header = model->header(current); const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)header.constData(); UString guid; - if (guidMap.count(dataHeader->GuidId)) + if (guidMap.count(dataHeader->GuidId)) guid = guidToUString(guidMap[dataHeader->GuidId], false); UString name; if (nameMap.count(dataHeader->VarId)) name = nameMap[dataHeader->VarId]; - + // Check for variable validity if (guid.isEmpty() && name.isEmpty()) { // Both name and guid aren't found model->setSubtype(current, Subtypes::InvalidEvsaEntry); @@ -1855,7 +1890,7 @@ USTATUS NvramParser::parseFlashMapBody(const UModelIndex & index) UINT32 localOffset = model->offset(index) + model->header(index).size(); const UByteArray data = model->body(index); - + const UINT32 dataSize = (UINT32)data.size(); UINT32 offset = 0; UINT32 unparsedSize = dataSize; @@ -1880,18 +1915,19 @@ USTATUS NvramParser::parseFlashMapBody(const UModelIndex & index) } UString name = guidToUString(entryHeader->Guid); - + // Construct header UByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY)); // Add info - UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) + usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n" - "Entry type: %04Xh\nData type: %04Xh\nMemory address: %08Xh\nSize: %08Xh\nOffset: %08Xh", - entryHeader->EntryType, - entryHeader->DataType, - entryHeader->PhysicalAddress, - entryHeader->Size, - entryHeader->Offset); + UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) + + usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n" + "Entry type: %04Xh\nData type: %04Xh\nMemory address: %08Xh\nSize: %08Xh\nOffset: %08Xh", + entryHeader->EntryType, + entryHeader->DataType, + entryHeader->PhysicalAddress, + entryHeader->Size, + entryHeader->Offset); // Determine subtype UINT8 subtype = 0; diff --git a/common/nvramparser.h b/common/nvramparser.h index fed1f13..5f99b86 100644 --- a/common/nvramparser.h +++ b/common/nvramparser.h @@ -21,13 +21,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "ustring.h" #include "ubytearray.h" #include "treemodel.h" +#include "ffsparser.h" #ifdef U_ENABLE_NVRAM_PARSING_SUPPORT class NvramParser { public: // Default constructor and destructor - NvramParser(TreeModel* treeModel) : model(treeModel) {} + NvramParser(TreeModel* treeModel, FfsParser* parser) : model(treeModel), ffsParser(parser) {} ~NvramParser() {} // Returns messages @@ -41,6 +42,7 @@ public: private: TreeModel *model; + FfsParser *ffsParser; std::vector > messagesVector; void msg(const UString message, const UModelIndex index = UModelIndex()) { messagesVector.push_back(std::pair(message, index)); @@ -50,8 +52,8 @@ private: USTATUS getStoreSize(const UByteArray & data, const UINT32 storeOffset, UINT32 & storeSize); USTATUS parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseLenovoVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); + USTATUS parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index); + USTATUS parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index); USTATUS parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); @@ -62,6 +64,7 @@ private: USTATUS parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); + USTATUS parseFdcStoreBody(const UModelIndex & index); USTATUS parseVssStoreBody(const UModelIndex & index, const UINT8 alignment); USTATUS parseFsysStoreBody(const UModelIndex & index); USTATUS parseEvsaStoreBody(const UModelIndex & index); @@ -72,7 +75,7 @@ class NvramParser { public: // Default constructor and destructor - NvramParser(TreeModel* treeModel) { U_UNUSED_PARAMETER(treeModel); } + NvramParser(TreeModel* treeModel, FfsParser* parser) { U_UNUSED_PARAMETER(treeModel); U_UNUSED_PARAMETER(parser); } ~NvramParser() {} // Returns messages diff --git a/common/treemodel.cpp b/common/treemodel.cpp index 606ac09..e34f3fd 100644 --- a/common/treemodel.cpp +++ b/common/treemodel.cpp @@ -26,11 +26,13 @@ QVariant TreeModel::data(const UModelIndex &index, int role) const if (role == Qt::DisplayRole) { return (const char*)item->data(index.column()).toLocal8Bit(); } +#if defined (QT_GUI_LIB) else if (role == Qt::BackgroundRole) { - if (markingEnabled && marking(index) > 0) { + if (markingEnabledFlag && marking(index) > 0) { return QBrush((Qt::GlobalColor)marking(index)); } } +#endif else if (role == Qt::UserRole) { return (const char*)item->info().toLocal8Bit(); } @@ -50,18 +52,12 @@ QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - switch (section) - { - case 0: - return tr("Name"); - case 1: - return tr("Action"); - case 2: - return tr("Type"); - case 3: - return tr("Subtype"); - case 4: - return tr("Text"); + switch (section) { + case 0: return tr("Name"); + case 1: return tr("Action"); + case 2: return tr("Type"); + case 3: return tr("Subtype"); + case 4: return tr("Text"); } } @@ -90,16 +86,11 @@ UString TreeModel::headerData(int section, int orientation, if (orientation == 1 && role == 0) { switch (section) { - case 0: - return UString("Name"); - case 1: - return UString("Action"); - case 2: - return UString("Type"); - case 3: - return UString("Subtype"); - case 4: - return UString("Text"); + case 0: return UString("Name"); + case 1: return UString("Action"); + case 2: return UString("Type"); + case 3: return UString("Subtype"); + case 4: return UString("Text"); } } @@ -330,7 +321,9 @@ void TreeModel::setCompressed(const UModelIndex &index, const bool compressed) void TreeModel::TreeModel::setMarkingEnabled(const bool enabled) { - markingEnabled = enabled; emit dataChanged(QModelIndex(), QModelIndex()); + markingEnabledFlag = enabled; + + emit dataChanged(UModelIndex(), UModelIndex()); } void TreeModel::setMarking(const UModelIndex &index, const UINT8 marking) diff --git a/common/treemodel.h b/common/treemodel.h index 89c971b..cc62561 100644 --- a/common/treemodel.h +++ b/common/treemodel.h @@ -25,7 +25,9 @@ enum ItemFixedState { #include #include #include +#if defined(QT_GUI_LIB) #include +#endif #include "ustring.h" #include "ubytearray.h" @@ -86,15 +88,15 @@ class TreeModel : public QAbstractItemModel { Q_OBJECT private: - bool markingEnabled; TreeItem *rootItem; + bool markingEnabledFlag; public: QVariant data(const UModelIndex &index, int role) const; Qt::ItemFlags flags(const UModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabled(true) { + TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabledFlag(true) { rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), UByteArray(), UByteArray(), UByteArray(), true, false); } @@ -105,6 +107,8 @@ class TreeModel { private: TreeItem *rootItem; + bool markingEnabledFlag; + void dataChanged(const UModelIndex &, const UModelIndex &) {} void layoutAboutToBeChanged() {} void layoutChanged() {} @@ -130,6 +134,9 @@ public: delete rootItem; } + bool markingEnabled() { return markingEnabledFlag; } + void setMarkingEnabled(const bool enabled); + UModelIndex index(int row, int column, const UModelIndex &parent = UModelIndex()) const; UModelIndex parent(const UModelIndex &index) const; int rowCount(const UModelIndex &parent = UModelIndex()) const; @@ -145,7 +152,6 @@ public: void addInfo(const UModelIndex &index, const UString &info, const bool append = TRUE); void setFixed(const UModelIndex &index, const bool fixed); void setCompressed(const UModelIndex &index, const bool compressed); - void setMarkingEnabled(const bool enabled); void setMarking(const UModelIndex &index, const UINT8 marking); UINT32 offset(const UModelIndex &index) const; @@ -163,7 +169,6 @@ public: bool fixed(const UModelIndex &index) const; bool compressed(const UModelIndex &index) const; UINT8 marking(const UModelIndex &index) const; - UINT8 action(const UModelIndex &index) const; UByteArray parsingData(const UModelIndex &index) const; diff --git a/common/types.cpp b/common/types.cpp index dee411f..c422aa1 100644 --- a/common/types.cpp +++ b/common/types.cpp @@ -23,11 +23,17 @@ UString regionTypeToUString(const UINT8 type) case Subtypes::MeRegion: return UString("ME"); case Subtypes::GbeRegion: return UString("GbE"); case Subtypes::PdrRegion: return UString("PDR"); + case Subtypes::DevExp1Region: return UString("DevExp1"); + case Subtypes::Bios2Region: return UString("BIOS2"); + case Subtypes::MicrocodeRegion: return UString("Microcode"); + case Subtypes::EcRegion: return UString("EC"); + case Subtypes::DevExp2Region: return UString("DevExp2"); + case Subtypes::IeRegion: return UString("IE"); + case Subtypes::Tgbe1Region: return UString("10GbE1"); + case Subtypes::Tgbe2Region: return UString("10GbE2"); case Subtypes::Reserved1Region: return UString("Reserved1"); case Subtypes::Reserved2Region: return UString("Reserved2"); - case Subtypes::Reserved3Region: return UString("Reserved3"); - case Subtypes::EcRegion: return UString("EC"); - case Subtypes::Reserved4Region: return UString("Reserved4"); + case Subtypes::PttRegion: return UString("PTT"); }; return UString("Unknown"); @@ -46,7 +52,7 @@ UString itemTypeToUString(const UINT8 type) case Types::Section: return UString("Section"); case Types::FreeSpace: return UString("Free space"); case Types::VssStore: return UString("VSS store"); - case Types::LenovoVssStore: return UString("Lenovo VSS store"); + case Types::Vss2Store: return UString("VSS2 store"); case Types::FtwStore: return UString("FTW store"); case Types::FdcStore: return UString("FDC store"); case Types::FsysStore: return UString("Fsys store"); @@ -71,7 +77,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) case Types::Root: case Types::FreeSpace: case Types::VssStore: - case Types::LenovoVssStore: + case Types::Vss2Store: case Types::FdcStore: case Types::FsysStore: case Types::EvsaStore: @@ -149,7 +155,7 @@ UString compressionTypeToUString(const UINT8 algorithm) case COMPRESSION_ALGORITHM_TIANO: return UString("Tiano"); case COMPRESSION_ALGORITHM_UNDECIDED: return UString("Undecided Tiano/EFI 1.1"); case COMPRESSION_ALGORITHM_LZMA: return UString("LZMA"); - case COMPRESSION_ALGORITHM_IMLZMA: return UString("Intel modified LZMA"); + case COMPRESSION_ALGORITHM_IMLZMA: return UString("Intel LZMA"); } return UString("Unknown"); @@ -173,16 +179,17 @@ UString actionTypeToUString(const UINT8 action) UString fitEntryTypeToUString(const UINT8 type) { switch (type & 0x7F) { - case FIT_TYPE_HEADER: return ("FIT Header"); - case FIT_TYPE_MICROCODE: return ("Microcode"); - case FIT_TYPE_BIOS_AC_MODULE: return ("BIOS ACM"); - case FIT_TYPE_BIOS_INIT_MODULE: return ("BIOS Init"); - case FIT_TYPE_TPM_POLICY: return ("TPM Policy"); - case FIT_TYPE_BIOS_POLICY_DATA: return ("BIOS Policy Data"); - case FIT_TYPE_TXT_CONF_POLICY: return ("TXT Configuration Policy"); - case FIT_TYPE_AC_KEY_MANIFEST: return ("BootGuard Key Manifest"); - case FIT_TYPE_AC_BOOT_POLICY: return ("BootGuard Boot Policy"); - case FIT_TYPE_EMPTY: return ("Empty"); - default: return ("Unknown"); + case FIT_TYPE_HEADER: return UString("FIT Header"); + case FIT_TYPE_MICROCODE: return UString("Microcode"); + case FIT_TYPE_BIOS_AC_MODULE: return UString("BIOS ACM"); + case FIT_TYPE_BIOS_INIT_MODULE: return UString("BIOS Init"); + case FIT_TYPE_TPM_POLICY: return UString("TPM Policy"); + case FIT_TYPE_BIOS_POLICY_DATA: return UString("BIOS Policy Data"); + case FIT_TYPE_TXT_CONF_POLICY: return UString("TXT Configuration Policy"); + case FIT_TYPE_AC_KEY_MANIFEST: return UString("BootGuard Key Manifest"); + case FIT_TYPE_AC_BOOT_POLICY: return UString("BootGuard Boot Policy"); + case FIT_TYPE_EMPTY: return UString("Empty"); } + + return UString("Unknown"); } \ No newline at end of file diff --git a/common/types.h b/common/types.h index 41268af..18973ef 100644 --- a/common/types.h +++ b/common/types.h @@ -44,7 +44,7 @@ namespace Types { Section, FreeSpace, VssStore, - LenovoVssStore, + Vss2Store, FtwStore, FdcStore, FsysStore, @@ -87,11 +87,17 @@ namespace Subtypes { MeRegion, GbeRegion, PdrRegion, + DevExp1Region, + Bios2Region, + MicrocodeRegion, + EcRegion, + DevExp2Region, + IeRegion, + Tgbe1Region, + Tgbe2Region, Reserved1Region, Reserved2Region, - Reserved3Region, - EcRegion, - Reserved4Region + PttRegion }; enum PaddingSubtypes { diff --git a/common/utility.cpp b/common/utility.cpp index c3e726c..31491e2 100644 --- a/common/utility.cpp +++ b/common/utility.cpp @@ -300,8 +300,8 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp } } -// 8bit checksum calculation routine -UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize) +// 8bit sum calculation routine +UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize) { if (!buffer) return 0; @@ -311,7 +311,16 @@ UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize) while (bufferSize--) counter += buffer[bufferSize]; - return (UINT8)(0x100 - counter); + return counter; +} + +// 8bit checksum calculation routine +UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize) +{ + if (!buffer) + return 0; + + return (UINT8)0x100 - calculateSum8(buffer, bufferSize); } // 16bit checksum calculation routine diff --git a/common/utility.h b/common/utility.h index 3a7994d..6cfb9bf 100644 --- a/common/utility.h +++ b/common/utility.h @@ -34,6 +34,9 @@ USTATUS decompress(const UByteArray & compressed, const UINT8 compressionType, U // CRC32 calculation routine UINT32 crc32(UINT32 initial, const UINT8* buffer, const UINT32 length); +// 8bit sum calculation routine +UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize); + // 8bit checksum calculation routine UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);