From b3c68b7006055f07a2c1399e4f90d85228ebd90f Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Mon, 3 Mar 2025 01:27:24 +0700 Subject: [PATCH] Add Insyde Flash Device Map parser --- UEFIExtract/CMakeLists.txt | 2 + UEFIFind/CMakeLists.txt | 2 + UEFITool/CMakeLists.txt | 2 + UEFITool/uefitool.cpp | 9 +- UEFITool/uefitool.pro | 4 + common/ffs.cpp | 42 +++++ common/ffs.h | 93 ++++++++-- common/ffsparser.cpp | 159 ++++++++++++++++- common/ffsparser.h | 1 + common/generated/edk2_ftw.cpp | 38 +--- common/generated/edk2_ftw.h | 28 +-- common/generated/edk2_vss2.cpp | 2 +- common/generated/insyde_fdm.cpp | 179 +++++++++++++++++++ common/generated/insyde_fdm.h | 232 ++++++++++++++++++++++++ common/generated/phoenix_evsa.cpp | 98 ++++++++--- common/generated/phoenix_evsa.h | 85 +++++++-- common/ksy/edk2_ftw.ksy | 15 +- common/ksy/edk2_vss2.ksy | 10 +- common/ksy/insyde_fdm.ksy | 91 ++++++++++ common/ksy/phoenix_evsa.ksy | 90 +++++++--- common/meson.build | 2 + common/nvram.cpp | 2 +- common/nvram.h | 4 +- common/nvramparser.cpp | 281 ++++++++++++++++++++++++++---- common/types.cpp | 108 +++++++----- common/types.h | 7 +- common/utility.cpp | 3 +- fuzzing/CMakeLists.txt | 2 + 28 files changed, 1361 insertions(+), 230 deletions(-) create mode 100644 common/generated/insyde_fdm.cpp create mode 100644 common/generated/insyde_fdm.h create mode 100644 common/ksy/insyde_fdm.ksy diff --git a/UEFIExtract/CMakeLists.txt b/UEFIExtract/CMakeLists.txt index e27c748..b1f0533 100644 --- a/UEFIExtract/CMakeLists.txt +++ b/UEFIExtract/CMakeLists.txt @@ -40,7 +40,9 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/insyde_fdm.cpp ../common/generated/phoenix_flm.cpp + ../common/generated/phoenix_evsa.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp ../common/generated/intel_keym_v1.cpp diff --git a/UEFIFind/CMakeLists.txt b/UEFIFind/CMakeLists.txt index fcfeece..e27a5eb 100644 --- a/UEFIFind/CMakeLists.txt +++ b/UEFIFind/CMakeLists.txt @@ -37,7 +37,9 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/insyde_fdm.cpp ../common/generated/phoenix_flm.cpp + ../common/generated/phoenix_evsa.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp ../common/generated/intel_keym_v1.cpp diff --git a/UEFITool/CMakeLists.txt b/UEFITool/CMakeLists.txt index 3228960..9ba54df 100644 --- a/UEFITool/CMakeLists.txt +++ b/UEFITool/CMakeLists.txt @@ -73,6 +73,8 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/insyde_fdm.cpp + ../common/generated/phoenix_evsa.cpp ../common/generated/phoenix_flm.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index 99a3c04..a5b1eeb 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -247,7 +247,8 @@ void UEFITool::populateUi(const QModelIndex ¤t) || type == Types::VssEntry || type == Types::SysFEntry || type == Types::EvsaEntry - || type == Types::FlashMapEntry + || type == Types::PhoenixFlashMapEntry + || type == Types::InsydeFlashDeviceMapEntry || type == Types::IfwiHeader || type == Types::IfwiPartition || type == Types::FptPartition @@ -266,7 +267,8 @@ void UEFITool::populateUi(const QModelIndex ¤t) || type == Types::SysFStore || type == Types::EvsaStore || type == Types::FtwStore - || type == Types::FlashMapStore + || type == Types::PhoenixFlashMapStore + || type == Types::InsydeFlashDeviceMapStore || type == Types::NvarGuidStore || type == Types::CmdbStore || type == Types::FptStore @@ -910,7 +912,8 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event) case Types::SysFStore: case Types::EvsaStore: case Types::FtwStore: - case Types::FlashMapStore: + case Types::PhoenixFlashMapStore: + case Types::InsydeFlashDeviceMapStore: case Types::NvarGuidStore: case Types::CmdbStore: case Types::FptStore: diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro index 39e6d28..6de5332 100644 --- a/UEFITool/uefitool.pro +++ b/UEFITool/uefitool.pro @@ -56,7 +56,9 @@ HEADERS += uefitool.h \ ../common/generated/edk2_vss2.h \ ../common/generated/edk2_ftw.h \ ../common/generated/insyde_fdc.h \ + ../common/generated/insyde_fdm.h \ ../common/generated/phoenix_flm.h \ + ../common/generated/phoenix_evsa.h \ ../common/generated/intel_acbp_v1.h \ ../common/generated/intel_acbp_v2.h \ ../common/generated/intel_keym_v1.h \ @@ -129,7 +131,9 @@ SOURCES += uefitool_main.cpp \ ../common/generated/edk2_vss2.cpp \ ../common/generated/edk2_ftw.cpp \ ../common/generated/insyde_fdc.cpp \ + ../common/generated/insyde_fdm.cpp \ ../common/generated/phoenix_flm.cpp \ + ../common/generated/phoenix_evsa.cpp \ ../common/generated/intel_acbp_v1.cpp \ ../common/generated/intel_acbp_v2.cpp \ ../common/generated/intel_keym_v1.cpp \ diff --git a/common/ffs.cpp b/common/ffs.cpp index 4cefbbe..0897962 100644 --- a/common/ffs.cpp +++ b/common/ffs.cpp @@ -85,6 +85,48 @@ extern const UByteArray EFI_DXE_CORE_GUID // D6A2CB7F-6A18-4E2F-B43B-9920A733700 extern const UByteArray AMD_COMPRESSED_RAW_FILE_GUID //20BC8AC9-94D1-4208-AB28-5D673FD73487 ("\xC9\x8A\xBC\x20\xD1\x94\x08\x42\xAB\x28\x5D\x67\x3F\xD7\x34\x87", 16); +// Insyde Flash Device Map GUIDs +extern const UByteArray INSYDE_FLASH_MAP_REGION_BOOT_FV_GUID +("\x56\x6d\xd7\xe3\x8a\x98\x6b\x4d\x89\x13\x64\xf2\xdf\x1d\xf6\xa6", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_BVDT_GUID +("\xFC\x5D\x41\x32\x06\xD1\xC7\x48\x9E\xB5\x80\x6C\x11\x4D\xD1\x07", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_EC_GUID +("\xBF\xF3\x3E\xA7\xCC\x33\xA9\x43\xB3\x9C\xA9\x12\xC7\x48\x9A\x57", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_FTW_BACKUP_GUID +("\xD3\x15\x8E\xB7\xA5\xF0\x48\x42\x8E\x2F\xD3\x15\x7A\xEF\x88\x36", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_FTW_STATE_GUID +("\x04\x6E\x41\xC8\x34\x99\x79\x40\xBE\x9A\x39\xF8\xD6\x02\x84\x98", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_FV_GUID +("\x58\xE7\xE8\xB5\xE6\xA7\x8B\x4C\xAB\x85\xFF\x2A\x95\x9B\x99\xBA", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_FLASH_DEVICE_MAP_GUID +("\xA0\xC1\x78\xF0\x52\xFC\x3F\x4C\xBE\x1F\xD6\x88\x81\x5A\x62\xC0", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_LOGO_GUID +("\x69\xAB\xCF\xDA\x77\xF9\x84\x47\x8A\xD8\x77\x24\xA6\xF4\xB4\x40", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_MICROCODE_GUID +("\xF8\x66\x98\xB4\xD2\x8C\xE4\x49\xA1\x6D\xB6\x0F\xBE\xC3\x1C\x4B", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_MSDM_TABLE_GUID +("\x1A\xEB\x44\xB3\x7E\xF9\x14\x4F\xA1\xE1\x7E\x63\xBC\x40\xC8\xCE", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_MULTI_CONFIG_GUID +("\x92\xB5\x94\x59\x14\x2F\xD5\x48\xBB\x40\xBD\x27\x96\x9C\x77\x80", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_VAR_DEFAULT_GUID +("\xA2\xAC\xDD\xD9\x16\x08\xF3\x48\xAD\xED\x6B\x71\x65\x6B\x24\x8A", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_SMBIOS_UPDATE_GUID +("\xDC\xFE\x64\x89\xE7\x6F\x1E\x4E\xA5\x5E\xFF\x82\x1D\x71\xFF\xCF", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_VAR_GUID +("\x74\x53\x3C\x77\xD1\x81\x43\x4D\xB2\x93\xF3\xD7\x4F\x18\x1D\x6B", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_UNKNOWN_GUID +("\xE5\x65\x1D\x20\x23\xBE\x75\x48\x80\xF8\xB1\xD4\x79\x5E\x7E\x08", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_UNUSED_GUID +("\x20\xB0\xC8\x13\x27\x4F\x3B\x45\x8F\x80\x1B\xFC\xA1\x87\x38\x0F", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_USB_OPTION_ROM_GUID +("\x0F\xF3\x7B\x60\x2B\x5F\xA2\x4D\xAE\xED\x56\xF9\xBD\xCD\x2D\x21", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_DXE_FV_GUID +("\xCE\xBA\xD0\x1F\x0A\x6F\x85\x40\x90\x1E\xF6\x21\x03\x85\xCB\x6F", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_PEI_FV_GUID +("\xC5\x06\x14\xCF\xEC\x3F\xEB\x47\xA6\xC3\xB7\x1A\x3E\xE0\x0B\x95", 16); +extern const UByteArray INSYDE_FLASH_MAP_REGION_UNSIGNED_FV_GUID +("\xB6\x16\xA0\xF2\x14\xE8\x2E\x40\xA3\x95\x46\xD3\xCF\x75\x26\x4A", 16); + // GUIDs of GUID-defined sections extern const UByteArray EFI_GUIDED_SECTION_CRC32 // FC1BCDB0-7D31-49AA-936A-A4600D9DD083 ("\xB0\xCD\x1B\xFC\x31\x7D\xAA\x49\x93\x6A\xA4\x60\x0D\x9D\xD0\x83", 16); diff --git a/common/ffs.h b/common/ffs.h index 210817c..4075bd6 100644 --- a/common/ffs.h +++ b/common/ffs.h @@ -845,22 +845,83 @@ typedef struct PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V3_ // // AMI ROM Hole files // -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_0; //05CA01FC-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_1; //05CA01FD-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_2; //05CA01FE-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_3; //05CA01FF-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_4; //05CA0200-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_5; //05CA0201-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_6; //05CA0202-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_7; //05CA0203-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_8; //05CA0204-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_9; //05CA0205-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_10; //05CA0206-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_11; //05CA0207-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_12; //05CA0208-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_13; //05CA0209-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_14; //05CA020A-0FC1-11DC-9011-00173153EBA8 -extern const UByteArray AMI_ROM_HOLE_FILE_GUID_15; //05CA020B-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_0; // 05CA01FC-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_1; // 05CA01FD-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_2; // 05CA01FE-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_3; // 05CA01FF-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_4; // 05CA0200-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_5; // 05CA0201-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_6; // 05CA0202-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_7; // 05CA0203-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_8; // 05CA0204-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_9; // 05CA0205-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_10; // 05CA0206-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_11; // 05CA0207-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_12; // 05CA0208-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_13; // 05CA0209-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_14; // 05CA020A-0FC1-11DC-9011-00173153EBA8 +extern const UByteArray AMI_ROM_HOLE_FILE_GUID_15; // 05CA020B-0FC1-11DC-9011-00173153EBA8 + +// +// Insyde Flash Device Map +// +#define INSYDE_FLASH_DEVICE_MAP_SIGNATURE 0x4D444648 // HFDM + +typedef struct _INSYDE_FLASH_DEVICE_MAP_HEADER { + UINT32 Signature; + UINT32 Size; + UINT32 DataOffset; + UINT32 EntrySize; + UINT8 EntryFormat; + UINT8 Revision; + UINT8 ExtensionCount; + UINT8 Checksum; + UINT64 FdBaseAddress; +//INSYDE_FLASH_DEVICE_MAP_EXTENSION Extensions[ExtensionCount]; +} INSYDE_FLASH_DEVICE_MAP_HEADER; + +typedef struct _INSYDE_FLASH_DEVICE_MAP_EXTENSION { + UINT16 EntryOffset; + UINT16 EntryCount; +} INSYDE_FLASH_DEVICE_MAP_EXTENSION; + +typedef struct _INSYDE_FLASH_DEVICE_MAP_ENTRY { + EFI_GUID RegionTypeGuid; + UINT8 RegionId[16]; + UINT64 RegionOffset; + UINT64 RegionSize; + UINT32 Attributes; +//UINT8 Hash[]; // Size depends on EntryFormat and EntrySize of the header +} INSYDE_FLASH_DEVICE_MAP_ENTRY; + +typedef struct _INSYDE_FLASH_DEVICE_MAP_BOARD_ID_MAP { + UINT32 BoardIdIndex; + UINT32 BoardIdCount; +//UINT64 BoardIds[Count]; +} INSYDE_FLASH_DEVICE_MAP_BOARD_ID_MAP; + +#define INSYDE_FLASH_DEVICE_MAP_ENTRY_ATTRIBUTE_MODIFIABLE 0x00000001 + +extern const UByteArray INSYDE_FLASH_MAP_REGION_BOOT_FV_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_BVDT_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_EC_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_FTW_BACKUP_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_FTW_STATE_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_FV_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_FLASH_DEVICE_MAP_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_LOGO_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_MICROCODE_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_MSDM_TABLE_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_MULTI_CONFIG_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_VAR_DEFAULT_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_SMBIOS_UPDATE_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_VAR_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_UNKNOWN_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_UNUSED_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_USB_OPTION_ROM_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_DXE_FV_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_PEI_FV_GUID; +extern const UByteArray INSYDE_FLASH_MAP_REGION_UNSIGNED_FV_GUID; // Restore previous packing rules #pragma pack(pop) diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 9639e33..3706036 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -35,6 +35,10 @@ #include "digest/sha2.h" #include "digest/sm3.h" +#include "umemstream.h" +#include "kaitai/kaitaistream.h" +#include "generated/insyde_fdm.h" + // Constructor FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel), imageBase(0), addressDiff(0x100000000ULL), protectedRegionsBase(0) { @@ -948,6 +952,114 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index) msg(usprintf("%s: BPDT store parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index); } } + else if (itemType == Types::InsydeFlashDeviceMapStore) { + UByteArray fdm = data.mid(itemOffset, itemSize); + umemstream is(fdm.constData(), fdm.size()); + kaitai::kstream ks(&is); + insyde_fdm_t parsed(&ks); + UINT32 storeSize = (UINT32)fdm.size(); + + // Construct header and body + UByteArray header = fdm.left(parsed.data_offset()); + UByteArray body = fdm.mid(header.size(), storeSize - header.size()); + + // Add info + UString name = UString("Insyde H2O FlashDeviceMap"); + UString info = usprintf("Signature: HFDM\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nData offset: %Xh\nEntry size: %Xh (%u)\nEntry format: %02Xh\nRevision: %02Xh\nExtension count: %u\nFlash descriptor base address: %08Xh\nChecksum: %02Xh", + storeSize, storeSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + parsed.data_offset(), + parsed.entry_size(), parsed.entry_size(), + parsed.entry_format(), + parsed.revision(), + parsed.num_extensions(), + (UINT32)parsed.fd_base_address(), + parsed.checksum()); + + // Check header checksum + { + UByteArray tempHeader = data.mid(itemOffset, sizeof(INSYDE_FLASH_DEVICE_MAP_HEADER)); + INSYDE_FLASH_DEVICE_MAP_HEADER* tempFdmHeader = (INSYDE_FLASH_DEVICE_MAP_HEADER*)tempHeader.data(); + tempFdmHeader->Checksum = 0; + UINT8 calculated = calculateChecksum8((const UINT8*)tempFdmHeader, (UINT32)tempHeader.size()); + if (calculated == parsed.checksum()) { + info += UString(", valid"); + } + else { + info += usprintf(", invalid, should be %02Xh", calculated); + } + } + + // Add board IDs + if (parsed.revision() == 3) { + info += usprintf("\nRegion index: %Xh\nBoardId Count: %u", + parsed.board_ids()->region_index(), + parsed.board_ids()->num_board_ids()); + UINT32 i = 0; + for (const auto & boardId : *parsed.board_ids()->board_ids()) { + info += usprintf("\nBoardId #%u: %" PRIX64 "\n", i++, boardId); + } + } + + // Add header tree item + UModelIndex headerIndex = model->addItem(headerSize + itemOffset, Types::InsydeFlashDeviceMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); + + // Add entries + UINT32 entryOffset = parsed.data_offset(); + bool protectedRangeFound = false; + for (const auto & entry : *parsed.entries()->entries()) { + const EFI_GUID guid = readUnaligned((const EFI_GUID*)entry->guid().c_str()); + name = insydeFlashDeviceMapEntryTypeGuidToUString(guid); + UString text; + header = data.mid(itemOffset + entryOffset, sizeof(INSYDE_FLASH_DEVICE_MAP_ENTRY)); + body = data.mid(itemOffset + entryOffset + header.size(), parsed.entry_size() - header.size()); + + // Add info + UINT32 entrySize = (UINT32)header.size() + (UINT32)body.size(); + info = UString("Region type: ") + guidToUString(guid, false) + "\n"; + info += UString("Region id: "); + for (UINT8 i = 0; i < 16; i++) { + info += usprintf("%02X", *(const UINT8*)(entry->region_id().c_str() + i)); + } + info += usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nRegion address: %08Xh\nRegion size: %08Xh\nAttributes: %08Xh", + entrySize, entrySize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + (UINT32)entry->region_base(), + (UINT32)entry->region_size(), + entry->attributes()); + + if ((entry->attributes() & INSYDE_FLASH_DEVICE_MAP_ENTRY_ATTRIBUTE_MODIFIABLE) == 0) { + if (!protectedRangeFound) { + securityInfo += usprintf("Insyde Flash Device Map found at base %08Xh\nProtected ranges:\n", model->base(headerIndex)); + protectedRangeFound = true; + } + + // TODO: make sure that the only hash possible here is SHA256 + + // Add this region to the list of Insyde protected regions + PROTECTED_RANGE range = {}; + range.Offset = (UINT32)entry->region_base(); + range.Size = (UINT32)entry->region_size(); + range.AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256; + range.Type = PROTECTED_RANGE_VENDOR_HASH_INSYDE; + range.Hash = body; + protectedRanges.push_back(range); + + securityInfo += usprintf("Address: %08Xh Size: %Xh\nHash: ", range.Offset, range.Size) + UString(body.toHex().constData()) + "\n"; + } + + // Add tree item + model->addItem(entryOffset, Types::InsydeFlashDeviceMapEntry, 0, name, text, info, header, body, UByteArray(), Fixed, headerIndex); + + entryOffset += entrySize; + } + + if (protectedRangeFound) { + securityInfo += "\n"; + } + } else { return U_UNKNOWN_ITEM_TYPE; } @@ -992,6 +1104,9 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index) case Types::BpdtPartition: // Parsing already done break; + case Types::InsydeFlashDeviceMapStore: + // Parsing already done + break; case Types::Padding: // No parsing required break; @@ -1293,7 +1408,7 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l for (; offset < dataSize - sizeof(UINT32); offset++) { const UINT32* currentPos = (const UINT32*)(data.constData() + offset); UINT32 restSize = dataSize - offset; - if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode + if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) { // Intel microcode // Check data size if (restSize < sizeof(INTEL_MICROCODE_HEADER)) { continue; @@ -1415,6 +1530,28 @@ continue_searching: {} nextItemOffset = offset; break; } + else if (readUnaligned(currentPos) == INSYDE_FLASH_DEVICE_MAP_SIGNATURE) { + // Check data size + if (restSize < sizeof(INSYDE_FLASH_DEVICE_MAP_HEADER)) + continue; + + const INSYDE_FLASH_DEVICE_MAP_HEADER *fdmHeader = (const INSYDE_FLASH_DEVICE_MAP_HEADER *)currentPos; + + if (restSize < fdmHeader->Size) + continue; + + if (fdmHeader->Revision > 3) { + msg(usprintf("%s: Insyde Flash Device Map candidate with unknown revision %u", __FUNCTION__, fdmHeader->Revision), index); + continue; + } + + // All checks passed, FDM found + nextItemType = Types::InsydeFlashDeviceMapStore; + nextItemSize = fdmHeader->Size; + nextItemAlternativeSize = fdmHeader->Size; + nextItemOffset = offset; + break; + } } // No more stores found @@ -3764,6 +3901,26 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) // Do nothing, this range is likely not found in the image } } + else if (protectedRanges[i].Type == PROTECTED_RANGE_VENDOR_HASH_INSYDE) { + try { + protectedRanges[i].Offset -= (UINT32)addressDiff; + protectedParts = openedImage.mid(protectedRanges[i].Offset, protectedRanges[i].Size); + + UByteArray digest(SHA256_HASH_SIZE, '\x00'); + sha256(protectedParts.constData(), protectedParts.size(), digest.data()); + + if (digest != protectedRanges[i].Hash) { + msg(usprintf("%s: Insyde protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__, + protectedRanges[i].Offset, protectedRanges[i].Offset + protectedRanges[i].Size), + model->findByBase(protectedRanges[i].Offset)); + } + + markProtectedRangeRecursive(index, protectedRanges[i]); + } + catch(...) { + // Do nothing, this range is likely not found in the image + } + } } return U_SUCCESS; diff --git a/common/ffsparser.h b/common/ffsparser.h index 5d2d647..ef7ccc4 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -67,6 +67,7 @@ typedef struct PROTECTED_RANGE_ { #define PROTECTED_RANGE_VENDOR_HASH_AMI_V2 0x06 #define PROTECTED_RANGE_VENDOR_HASH_AMI_V3 0x07 #define PROTECTED_RANGE_VENDOR_HASH_MICROSOFT_PMDA 0x08 +#define PROTECTED_RANGE_VENDOR_HASH_INSYDE 0x09 class FitParser; class NvramParser; diff --git a/common/generated/edk2_ftw.cpp b/common/generated/edk2_ftw.cpp index ebc775b..e50c598 100644 --- a/common/generated/edk2_ftw.cpp +++ b/common/generated/edk2_ftw.cpp @@ -12,35 +12,11 @@ edk2_ftw_t::edk2_ftw_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, edk2_ } void edk2_ftw_t::_read() { - m_signature = m__io->read_u4le(); + m_signature = m__io->read_bytes(16); { - uint32_t _ = signature(); - if (!( ((_ == 4293995405UL) || (_ == 2656577835UL)) )) { - throw kaitai::validation_expr_error(signature(), _io(), std::string("/seq/0")); - } - } - n_signature_main = true; - if (signature() == 4293995405UL) { - n_signature_main = false; - m_signature_main = m__io->read_bytes(12); - if (!(signature_main() == std::string("\x96\x76\x8B\x4C\xA9\x85\x27\x47\x07\x5B\x4F\x50", 12))) { - throw kaitai::validation_not_equal_error(std::string("\x96\x76\x8B\x4C\xA9\x85\x27\x47\x07\x5B\x4F\x50", 12), signature_main(), _io(), std::string("/seq/1")); - } - } - n_signature_edk2_working_block = true; - if (signature() == 2656577835UL) { - n_signature_edk2_working_block = false; - m_signature_edk2_working_block = m__io->read_bytes(12); - if (!(signature_edk2_working_block() == std::string("\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 12))) { - throw kaitai::validation_not_equal_error(std::string("\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 12), signature_edk2_working_block(), _io(), std::string("/seq/2")); - } - } - n_signature_vss2_working_block = true; - if (signature() == 2656577835UL) { - n_signature_vss2_working_block = false; - m_signature_vss2_working_block = m__io->read_bytes(12); - if (!(signature_vss2_working_block() == std::string("\x68\x7C\x7D\x49\xA0\xCE\x65\x00\xFD\x9F\x1B\x95", 12))) { - throw kaitai::validation_not_equal_error(std::string("\x68\x7C\x7D\x49\xA0\xCE\x65\x00\xFD\x9F\x1B\x95", 12), signature_vss2_working_block(), _io(), std::string("/seq/3")); + std::string _ = signature(); + if (!( ((_ == std::string("\x8D\x2B\xF1\xFF\x96\x76\x8B\x4C\xA9\x85\x27\x47\x07\x5B\x4F\x50", 16)) || (_ == std::string("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 16)) || (_ == std::string("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\xA0\xCE\x65\x00\xFD\x9F\x1B\x95", 16))) )) { + throw kaitai::validation_expr_error(signature(), _io(), std::string("/seq/0")); } } m_crc = m__io->read_u4le(); @@ -69,12 +45,6 @@ edk2_ftw_t::~edk2_ftw_t() { } void edk2_ftw_t::_clean_up() { - if (!n_signature_main) { - } - if (!n_signature_edk2_working_block) { - } - if (!n_signature_vss2_working_block) { - } if (!n_len_write_queue_64) { } if (!n_write_queue_32) { diff --git a/common/generated/edk2_ftw.h b/common/generated/edk2_ftw.h index 7399d3e..dc03753 100644 --- a/common/generated/edk2_ftw.h +++ b/common/generated/edk2_ftw.h @@ -38,28 +38,7 @@ public: int8_t len_ftw_store_header_64(); private: - uint32_t m_signature; - std::string m_signature_main; - bool n_signature_main; - -public: - bool _is_null_signature_main() { signature_main(); return n_signature_main; }; - -private: - std::string m_signature_edk2_working_block; - bool n_signature_edk2_working_block; - -public: - bool _is_null_signature_edk2_working_block() { signature_edk2_working_block(); return n_signature_edk2_working_block; }; - -private: - std::string m_signature_vss2_working_block; - bool n_signature_vss2_working_block; - -public: - bool _is_null_signature_vss2_working_block() { signature_vss2_working_block(); return n_signature_vss2_working_block; }; - -private: + std::string m_signature; uint32_t m_crc; uint8_t m_state; std::string m_reserved; @@ -89,10 +68,7 @@ private: kaitai::kstruct* m__parent; public: - uint32_t signature() const { return m_signature; } - std::string signature_main() const { return m_signature_main; } - std::string signature_edk2_working_block() const { return m_signature_edk2_working_block; } - std::string signature_vss2_working_block() const { return m_signature_vss2_working_block; } + std::string signature() const { return m_signature; } uint32_t crc() const { return m_crc; } uint8_t state() const { return m_state; } std::string reserved() const { return m_reserved; } diff --git a/common/generated/edk2_vss2.cpp b/common/generated/edk2_vss2.cpp index 763c7f2..b9ffd83 100644 --- a/common/generated/edk2_vss2.cpp +++ b/common/generated/edk2_vss2.cpp @@ -354,7 +354,7 @@ int32_t edk2_vss2_t::vss2_variable_t::end_offset() { int32_t edk2_vss2_t::vss2_variable_t::len_alignment_padding_auth() { if (f_len_alignment_padding_auth) return m_len_alignment_padding_auth; - m_len_alignment_padding_auth = ((((end_offset_auth() - offset()) + 3) & ~3) - (end_offset() - offset())); + m_len_alignment_padding_auth = ((((end_offset_auth() - offset()) + 3) & ~3) - (end_offset_auth() - offset())); f_len_alignment_padding_auth = true; return m_len_alignment_padding_auth; } diff --git a/common/generated/insyde_fdm.cpp b/common/generated/insyde_fdm.cpp new file mode 100644 index 0000000..ebef703 --- /dev/null +++ b/common/generated/insyde_fdm.cpp @@ -0,0 +1,179 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "insyde_fdm.h" +#include "../kaitai/exceptions.h" + +insyde_fdm_t::insyde_fdm_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, insyde_fdm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; (void)p__root; + m_extensions = nullptr; + m__io__raw_extensions = nullptr; + m_board_ids = nullptr; + m_entries = nullptr; + m__io__raw_entries = nullptr; + _read(); +} + +void insyde_fdm_t::_read() { + m_signature = m__io->read_u4le(); + if (!(signature() == 1296320072)) { + throw kaitai::validation_not_equal_error(1296320072, signature(), _io(), std::string("/seq/0")); + } + m_store_size = m__io->read_u4le(); + m_data_offset = m__io->read_u4le(); + m_entry_size = m__io->read_u4le(); + m_entry_format = m__io->read_u1(); + m_revision = m__io->read_u1(); + m_num_extensions = m__io->read_u1(); + m_checksum = m__io->read_u1(); + m_fd_base_address = m__io->read_u8le(); + n_extensions = true; + if (revision() == 3) { + n_extensions = false; + m__raw_extensions = m__io->read_bytes((num_extensions() * 4)); + m__io__raw_extensions = std::unique_ptr(new kaitai::kstream(m__raw_extensions)); + m_extensions = std::unique_ptr(new fdm_extensions_t(m__io__raw_extensions.get(), this, m__root)); + } + n_board_ids = true; + if (revision() == 3) { + n_board_ids = false; + m_board_ids = std::unique_ptr(new fdm_board_ids_t(m__io, this, m__root)); + } + m__raw_entries = m__io->read_bytes((store_size() - data_offset())); + m__io__raw_entries = std::unique_ptr(new kaitai::kstream(m__raw_entries)); + m_entries = std::unique_ptr(new fdm_entries_t(m__io__raw_entries.get(), this, m__root)); +} + +insyde_fdm_t::~insyde_fdm_t() { + _clean_up(); +} + +void insyde_fdm_t::_clean_up() { + if (!n_extensions) { + } + if (!n_board_ids) { + } +} + +insyde_fdm_t::fdm_entries_t::fdm_entries_t(kaitai::kstream* p__io, insyde_fdm_t* p__parent, insyde_fdm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_entries = nullptr; + _read(); +} + +void insyde_fdm_t::fdm_entries_t::_read() { + m_entries = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + while (!m__io->is_eof()) { + m_entries->push_back(std::move(std::unique_ptr(new fdm_entry_t(m__io, this, m__root)))); + i++; + } + } +} + +insyde_fdm_t::fdm_entries_t::~fdm_entries_t() { + _clean_up(); +} + +void insyde_fdm_t::fdm_entries_t::_clean_up() { +} + +insyde_fdm_t::fdm_extension_t::fdm_extension_t(kaitai::kstream* p__io, insyde_fdm_t::fdm_extensions_t* p__parent, insyde_fdm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void insyde_fdm_t::fdm_extension_t::_read() { + m_offset = m__io->read_u2le(); + m_count = m__io->read_u2le(); +} + +insyde_fdm_t::fdm_extension_t::~fdm_extension_t() { + _clean_up(); +} + +void insyde_fdm_t::fdm_extension_t::_clean_up() { +} + +insyde_fdm_t::fdm_board_ids_t::fdm_board_ids_t(kaitai::kstream* p__io, insyde_fdm_t* p__parent, insyde_fdm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_board_ids = nullptr; + _read(); +} + +void insyde_fdm_t::fdm_board_ids_t::_read() { + m_region_index = m__io->read_u4le(); + m_num_board_ids = m__io->read_u4le(); + m_board_ids = std::unique_ptr>(new std::vector()); + const int l_board_ids = num_board_ids(); + for (int i = 0; i < l_board_ids; i++) { + m_board_ids->push_back(std::move(m__io->read_u8le())); + } +} + +insyde_fdm_t::fdm_board_ids_t::~fdm_board_ids_t() { + _clean_up(); +} + +void insyde_fdm_t::fdm_board_ids_t::_clean_up() { +} + +insyde_fdm_t::fdm_extensions_t::fdm_extensions_t(kaitai::kstream* p__io, insyde_fdm_t* p__parent, insyde_fdm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_extensions = nullptr; + _read(); +} + +void insyde_fdm_t::fdm_extensions_t::_read() { + m_extensions = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + while (!m__io->is_eof()) { + m_extensions->push_back(std::move(std::unique_ptr(new fdm_extension_t(m__io, this, m__root)))); + i++; + } + } +} + +insyde_fdm_t::fdm_extensions_t::~fdm_extensions_t() { + _clean_up(); +} + +void insyde_fdm_t::fdm_extensions_t::_clean_up() { +} + +insyde_fdm_t::fdm_entry_t::fdm_entry_t(kaitai::kstream* p__io, insyde_fdm_t::fdm_entries_t* p__parent, insyde_fdm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + f_region_base = false; + _read(); +} + +void insyde_fdm_t::fdm_entry_t::_read() { + m_guid = m__io->read_bytes(16); + m_region_id = m__io->read_bytes(16); + m_region_offset = m__io->read_u8le(); + m_region_size = m__io->read_u8le(); + m_attributes = m__io->read_u4le(); + m_hash = m__io->read_bytes((((((_parent()->_parent()->entry_size() - 16) - 16) - 8) - 8) - 4)); +} + +insyde_fdm_t::fdm_entry_t::~fdm_entry_t() { + _clean_up(); +} + +void insyde_fdm_t::fdm_entry_t::_clean_up() { +} + +int32_t insyde_fdm_t::fdm_entry_t::region_base() { + if (f_region_base) + return m_region_base; + m_region_base = (static_cast(_root()->fd_base_address()) + static_cast(region_offset())); + f_region_base = true; + return m_region_base; +} diff --git a/common/generated/insyde_fdm.h b/common/generated/insyde_fdm.h new file mode 100644 index 0000000..7bbd056 --- /dev/null +++ b/common/generated/insyde_fdm.h @@ -0,0 +1,232 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "../kaitai/kaitaistruct.h" +#include +#include +#include + +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" +#endif + +class insyde_fdm_t : public kaitai::kstruct { + +public: + class fdm_entries_t; + class fdm_extension_t; + class fdm_board_ids_t; + class fdm_extensions_t; + class fdm_entry_t; + + insyde_fdm_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, insyde_fdm_t* p__root = nullptr); + +private: + void _read(); + void _clean_up(); + +public: + ~insyde_fdm_t(); + + class fdm_entries_t : public kaitai::kstruct { + + public: + + fdm_entries_t(kaitai::kstream* p__io, insyde_fdm_t* p__parent = nullptr, insyde_fdm_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~fdm_entries_t(); + + private: + std::unique_ptr>> m_entries; + insyde_fdm_t* m__root; + insyde_fdm_t* m__parent; + + public: + std::vector>* entries() const { return m_entries.get(); } + insyde_fdm_t* _root() const { return m__root; } + insyde_fdm_t* _parent() const { return m__parent; } + }; + + class fdm_extension_t : public kaitai::kstruct { + + public: + + fdm_extension_t(kaitai::kstream* p__io, insyde_fdm_t::fdm_extensions_t* p__parent = nullptr, insyde_fdm_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~fdm_extension_t(); + + private: + uint16_t m_offset; + uint16_t m_count; + insyde_fdm_t* m__root; + insyde_fdm_t::fdm_extensions_t* m__parent; + + public: + uint16_t offset() const { return m_offset; } + uint16_t count() const { return m_count; } + insyde_fdm_t* _root() const { return m__root; } + insyde_fdm_t::fdm_extensions_t* _parent() const { return m__parent; } + }; + + class fdm_board_ids_t : public kaitai::kstruct { + + public: + + fdm_board_ids_t(kaitai::kstream* p__io, insyde_fdm_t* p__parent = nullptr, insyde_fdm_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~fdm_board_ids_t(); + + private: + uint32_t m_region_index; + uint32_t m_num_board_ids; + std::unique_ptr> m_board_ids; + insyde_fdm_t* m__root; + insyde_fdm_t* m__parent; + + public: + uint32_t region_index() const { return m_region_index; } + uint32_t num_board_ids() const { return m_num_board_ids; } + std::vector* board_ids() const { return m_board_ids.get(); } + insyde_fdm_t* _root() const { return m__root; } + insyde_fdm_t* _parent() const { return m__parent; } + }; + + class fdm_extensions_t : public kaitai::kstruct { + + public: + + fdm_extensions_t(kaitai::kstream* p__io, insyde_fdm_t* p__parent = nullptr, insyde_fdm_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~fdm_extensions_t(); + + private: + std::unique_ptr>> m_extensions; + insyde_fdm_t* m__root; + insyde_fdm_t* m__parent; + + public: + std::vector>* extensions() const { return m_extensions.get(); } + insyde_fdm_t* _root() const { return m__root; } + insyde_fdm_t* _parent() const { return m__parent; } + }; + + class fdm_entry_t : public kaitai::kstruct { + + public: + + fdm_entry_t(kaitai::kstream* p__io, insyde_fdm_t::fdm_entries_t* p__parent = nullptr, insyde_fdm_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~fdm_entry_t(); + + private: + bool f_region_base; + int32_t m_region_base; + + public: + int32_t region_base(); + + private: + std::string m_guid; + std::string m_region_id; + uint64_t m_region_offset; + uint64_t m_region_size; + uint32_t m_attributes; + std::string m_hash; + insyde_fdm_t* m__root; + insyde_fdm_t::fdm_entries_t* m__parent; + + public: + std::string guid() const { return m_guid; } + std::string region_id() const { return m_region_id; } + uint64_t region_offset() const { return m_region_offset; } + uint64_t region_size() const { return m_region_size; } + uint32_t attributes() const { return m_attributes; } + std::string hash() const { return m_hash; } + insyde_fdm_t* _root() const { return m__root; } + insyde_fdm_t::fdm_entries_t* _parent() const { return m__parent; } + }; + +private: + uint32_t m_signature; + uint32_t m_store_size; + uint32_t m_data_offset; + uint32_t m_entry_size; + uint8_t m_entry_format; + uint8_t m_revision; + uint8_t m_num_extensions; + uint8_t m_checksum; + uint64_t m_fd_base_address; + std::unique_ptr m_extensions; + bool n_extensions; + +public: + bool _is_null_extensions() { extensions(); return n_extensions; }; + +private: + std::unique_ptr m_board_ids; + bool n_board_ids; + +public: + bool _is_null_board_ids() { board_ids(); return n_board_ids; }; + +private: + std::unique_ptr m_entries; + insyde_fdm_t* m__root; + kaitai::kstruct* m__parent; + std::string m__raw_extensions; + bool n__raw_extensions; + +public: + bool _is_null__raw_extensions() { _raw_extensions(); return n__raw_extensions; }; + +private: + std::unique_ptr m__io__raw_extensions; + std::string m__raw_entries; + std::unique_ptr m__io__raw_entries; + +public: + uint32_t signature() const { return m_signature; } + uint32_t store_size() const { return m_store_size; } + uint32_t data_offset() const { return m_data_offset; } + uint32_t entry_size() const { return m_entry_size; } + uint8_t entry_format() const { return m_entry_format; } + uint8_t revision() const { return m_revision; } + uint8_t num_extensions() const { return m_num_extensions; } + uint8_t checksum() const { return m_checksum; } + uint64_t fd_base_address() const { return m_fd_base_address; } + fdm_extensions_t* extensions() const { return m_extensions.get(); } + fdm_board_ids_t* board_ids() const { return m_board_ids.get(); } + fdm_entries_t* entries() const { return m_entries.get(); } + insyde_fdm_t* _root() const { return m__root; } + kaitai::kstruct* _parent() const { return m__parent; } + std::string _raw_extensions() const { return m__raw_extensions; } + kaitai::kstream* _io__raw_extensions() const { return m__io__raw_extensions.get(); } + std::string _raw_entries() const { return m__raw_entries; } + kaitai::kstream* _io__raw_entries() const { return m__io__raw_entries.get(); } +}; diff --git a/common/generated/phoenix_evsa.cpp b/common/generated/phoenix_evsa.cpp index 84bdb85..1315663 100644 --- a/common/generated/phoenix_evsa.cpp +++ b/common/generated/phoenix_evsa.cpp @@ -17,18 +17,18 @@ void phoenix_evsa_t::_read() { throw kaitai::validation_not_equal_error(236, type(), _io(), std::string("/seq/0")); } m_checksum = m__io->read_u1(); - m_size = m__io->read_u2le(); - if (!(size() == 20)) { - throw kaitai::validation_not_equal_error(20, size(), _io(), std::string("/seq/2")); + m_len_evsa_store_header = m__io->read_u2le(); + if (!(len_evsa_store_header() == 20)) { + throw kaitai::validation_not_equal_error(20, len_evsa_store_header(), _io(), std::string("/seq/2")); } m_signature = m__io->read_u4le(); if (!(signature() == 1095980613)) { throw kaitai::validation_not_equal_error(1095980613, signature(), _io(), std::string("/seq/3")); } m_attributes = m__io->read_u4le(); - m_store_size = m__io->read_u4le(); + m_len_evsa_store = m__io->read_u4le(); m_reserved = m__io->read_u4le(); - m__raw_body = m__io->read_bytes((store_size() - 20)); + m__raw_body = m__io->read_bytes((len_evsa_store() - len_evsa_store_header())); m__io__raw_body = std::unique_ptr(new kaitai::kstream(m__raw_body)); m_body = std::unique_ptr(new evsa_body_t(m__io__raw_body.get(), this, m__root)); } @@ -47,10 +47,18 @@ phoenix_evsa_t::evsa_entry_t::evsa_entry_t(kaitai::kstream* p__io, phoenix_evsa_ } void phoenix_evsa_t::evsa_entry_t::_read() { - m_type = m__io->read_u1(); - m_checksum = m__io->read_u1(); - m_size = m__io->read_u2le(); - switch (type()) { + m_entry_type = m__io->read_u1(); + n_checksum = true; + if ( ((entry_type() == 225) || (entry_type() == 226) || (entry_type() == 227) || (entry_type() == 237) || (entry_type() == 238) || (entry_type() == 239) || (entry_type() == 131)) ) { + n_checksum = false; + m_checksum = m__io->read_u1(); + } + n_len_evsa_entry = true; + if ( ((entry_type() == 225) || (entry_type() == 226) || (entry_type() == 227) || (entry_type() == 237) || (entry_type() == 238) || (entry_type() == 239) || (entry_type() == 131)) ) { + n_len_evsa_entry = false; + m_len_evsa_entry = m__io->read_u2le(); + } + switch (entry_type()) { case 239: { m_body = std::unique_ptr(new evsa_data_t(m__io, this, m__root)); break; @@ -91,6 +99,10 @@ phoenix_evsa_t::evsa_entry_t::~evsa_entry_t() { } void phoenix_evsa_t::evsa_entry_t::_clean_up() { + if (!n_checksum) { + } + if (!n_len_evsa_entry) { + } } phoenix_evsa_t::evsa_unknown_t::evsa_unknown_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) { @@ -114,15 +126,26 @@ phoenix_evsa_t::evsa_body_t::evsa_body_t(kaitai::kstream* p__io, phoenix_evsa_t* m__parent = p__parent; m__root = p__root; m_entries = nullptr; + m_free_space = nullptr; _read(); } void phoenix_evsa_t::evsa_body_t::_read() { m_entries = std::unique_ptr>>(new std::vector>()); + { + int i = 0; + evsa_entry_t* _; + do { + _ = new evsa_entry_t(m__io, this, m__root); + m_entries->push_back(std::move(std::unique_ptr(_))); + i++; + } while (!( (( ((_->entry_type() != 237) && (_->entry_type() != 238) && (_->entry_type() != 239) && (_->entry_type() != 225) && (_->entry_type() != 226) && (_->entry_type() != 227) && (_->entry_type() != 131)) ) || (_io()->is_eof())) )); + } + m_free_space = std::unique_ptr>(new std::vector()); { int i = 0; while (!m__io->is_eof()) { - m_entries->push_back(std::move(std::unique_ptr(new evsa_entry_t(m__io, this, m__root)))); + m_free_space->push_back(std::move(m__io->read_u1())); i++; } } @@ -143,7 +166,7 @@ phoenix_evsa_t::evsa_name_t::evsa_name_t(kaitai::kstream* p__io, phoenix_evsa_t: void phoenix_evsa_t::evsa_name_t::_read() { m_var_id = m__io->read_u2le(); - m_name = m__io->read_bytes((_parent()->size() - 6)); + m_name = m__io->read_bytes((_parent()->len_evsa_entry() - 6)); } phoenix_evsa_t::evsa_name_t::~evsa_name_t() { @@ -162,6 +185,12 @@ phoenix_evsa_t::evsa_guid_t::evsa_guid_t(kaitai::kstream* p__io, phoenix_evsa_t: void phoenix_evsa_t::evsa_guid_t::_read() { m_guid_id = m__io->read_u2le(); m_guid = m__io->read_bytes(16); + { + std::string _ = guid(); + if (!(_parent()->len_evsa_entry() == 22)) { + throw kaitai::validation_expr_error(guid(), _io(), std::string("/types/evsa_guid/seq/1")); + } + } } phoenix_evsa_t::evsa_guid_t::~evsa_guid_t() { @@ -171,30 +200,57 @@ phoenix_evsa_t::evsa_guid_t::~evsa_guid_t() { void phoenix_evsa_t::evsa_guid_t::_clean_up() { } +phoenix_evsa_t::evsa_variable_attributes_t::evsa_variable_attributes_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_data_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void phoenix_evsa_t::evsa_variable_attributes_t::_read() { + m_non_volatile = m__io->read_bits_int_le(1); + m_boot_service = m__io->read_bits_int_le(1); + m_runtime = m__io->read_bits_int_le(1); + m_hw_error_record = m__io->read_bits_int_le(1); + m_auth_write = m__io->read_bits_int_le(1); + m_time_based_auth = m__io->read_bits_int_le(1); + m_append_write = m__io->read_bits_int_le(1); + m_reserved = m__io->read_bits_int_le(21); + m_extended_header = m__io->read_bits_int_le(1); + m_reserved1 = m__io->read_bits_int_le(3); +} + +phoenix_evsa_t::evsa_variable_attributes_t::~evsa_variable_attributes_t() { + _clean_up(); +} + +void phoenix_evsa_t::evsa_variable_attributes_t::_clean_up() { +} + phoenix_evsa_t::evsa_data_t::evsa_data_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_entry_t* p__parent, phoenix_evsa_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + m_attributes = nullptr; _read(); } void phoenix_evsa_t::evsa_data_t::_read() { m_guid_id = m__io->read_u2le(); m_var_id = m__io->read_u2le(); - m_attributes = m__io->read_u4le(); - n_data_size = true; - if ((attributes() & 268435456) != 268435456) { - n_data_size = false; - m_data_size = m__io->read_u4le(); + m_attributes = std::unique_ptr(new evsa_variable_attributes_t(m__io, this, m__root)); + n_len_data_ext = true; + if (attributes()->extended_header()) { + n_len_data_ext = false; + m_len_data_ext = m__io->read_u4le(); } n_data = true; - if ((attributes() & 268435456) == 268435456) { + if (!(attributes()->extended_header())) { n_data = false; - m_data = m__io->read_bytes((_parent()->size() - 12)); + m_data = m__io->read_bytes((_parent()->len_evsa_entry() - 12)); } n_data_ext = true; - if ((attributes() & 268435456) != 268435456) { + if (attributes()->extended_header()) { n_data_ext = false; - m_data_ext = m__io->read_bytes(data_size()); + m_data_ext = m__io->read_bytes(len_data_ext()); } } @@ -203,7 +259,7 @@ phoenix_evsa_t::evsa_data_t::~evsa_data_t() { } void phoenix_evsa_t::evsa_data_t::_clean_up() { - if (!n_data_size) { + if (!n_len_data_ext) { } if (!n_data) { } diff --git a/common/generated/phoenix_evsa.h b/common/generated/phoenix_evsa.h index af94762..694b39b 100644 --- a/common/generated/phoenix_evsa.h +++ b/common/generated/phoenix_evsa.h @@ -19,6 +19,7 @@ public: class evsa_body_t; class evsa_name_t; class evsa_guid_t; + class evsa_variable_attributes_t; class evsa_data_t; phoenix_evsa_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr); @@ -44,17 +45,29 @@ public: ~evsa_entry_t(); private: - uint8_t m_type; + uint8_t m_entry_type; uint8_t m_checksum; - uint16_t m_size; + bool n_checksum; + + public: + bool _is_null_checksum() { checksum(); return n_checksum; }; + + private: + uint16_t m_len_evsa_entry; + bool n_len_evsa_entry; + + public: + bool _is_null_len_evsa_entry() { len_evsa_entry(); return n_len_evsa_entry; }; + + private: std::unique_ptr m_body; phoenix_evsa_t* m__root; phoenix_evsa_t::evsa_body_t* m__parent; public: - uint8_t type() const { return m_type; } + uint8_t entry_type() const { return m_entry_type; } uint8_t checksum() const { return m_checksum; } - uint16_t size() const { return m_size; } + uint16_t len_evsa_entry() const { return m_len_evsa_entry; } kaitai::kstruct* body() const { return m_body.get(); } phoenix_evsa_t* _root() const { return m__root; } phoenix_evsa_t::evsa_body_t* _parent() const { return m__parent; } @@ -99,11 +112,13 @@ public: private: std::unique_ptr>> m_entries; + std::unique_ptr> m_free_space; phoenix_evsa_t* m__root; phoenix_evsa_t* m__parent; public: std::vector>* entries() const { return m_entries.get(); } + std::vector* free_space() const { return m_free_space.get(); } phoenix_evsa_t* _root() const { return m__root; } phoenix_evsa_t* _parent() const { return m__parent; } }; @@ -160,6 +175,48 @@ public: phoenix_evsa_t::evsa_entry_t* _parent() const { return m__parent; } }; + class evsa_variable_attributes_t : public kaitai::kstruct { + + public: + + evsa_variable_attributes_t(kaitai::kstream* p__io, phoenix_evsa_t::evsa_data_t* p__parent = nullptr, phoenix_evsa_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~evsa_variable_attributes_t(); + + private: + bool m_non_volatile; + bool m_boot_service; + bool m_runtime; + bool m_hw_error_record; + bool m_auth_write; + bool m_time_based_auth; + bool m_append_write; + uint64_t m_reserved; + bool m_extended_header; + uint64_t m_reserved1; + phoenix_evsa_t* m__root; + phoenix_evsa_t::evsa_data_t* m__parent; + + public: + bool non_volatile() const { return m_non_volatile; } + bool boot_service() const { return m_boot_service; } + bool runtime() const { return m_runtime; } + bool hw_error_record() const { return m_hw_error_record; } + bool auth_write() const { return m_auth_write; } + bool time_based_auth() const { return m_time_based_auth; } + bool append_write() const { return m_append_write; } + uint64_t reserved() const { return m_reserved; } + bool extended_header() const { return m_extended_header; } + uint64_t reserved1() const { return m_reserved1; } + phoenix_evsa_t* _root() const { return m__root; } + phoenix_evsa_t::evsa_data_t* _parent() const { return m__parent; } + }; + class evsa_data_t : public kaitai::kstruct { public: @@ -176,12 +233,12 @@ public: private: uint16_t m_guid_id; uint16_t m_var_id; - uint32_t m_attributes; - uint32_t m_data_size; - bool n_data_size; + std::unique_ptr m_attributes; + uint32_t m_len_data_ext; + bool n_len_data_ext; public: - bool _is_null_data_size() { data_size(); return n_data_size; }; + bool _is_null_len_data_ext() { len_data_ext(); return n_len_data_ext; }; private: std::string m_data; @@ -204,8 +261,8 @@ public: public: uint16_t guid_id() const { return m_guid_id; } uint16_t var_id() const { return m_var_id; } - uint32_t attributes() const { return m_attributes; } - uint32_t data_size() const { return m_data_size; } + evsa_variable_attributes_t* attributes() const { return m_attributes.get(); } + uint32_t len_data_ext() const { return m_len_data_ext; } std::string data() const { return m_data; } std::string data_ext() const { return m_data_ext; } phoenix_evsa_t* _root() const { return m__root; } @@ -215,10 +272,10 @@ public: private: uint8_t m_type; uint8_t m_checksum; - uint16_t m_size; + uint16_t m_len_evsa_store_header; uint32_t m_signature; uint32_t m_attributes; - uint32_t m_store_size; + uint32_t m_len_evsa_store; uint32_t m_reserved; std::unique_ptr m_body; phoenix_evsa_t* m__root; @@ -229,10 +286,10 @@ private: public: uint8_t type() const { return m_type; } uint8_t checksum() const { return m_checksum; } - uint16_t size() const { return m_size; } + uint16_t len_evsa_store_header() const { return m_len_evsa_store_header; } uint32_t signature() const { return m_signature; } uint32_t attributes() const { return m_attributes; } - uint32_t store_size() const { return m_store_size; } + uint32_t len_evsa_store() const { return m_len_evsa_store; } uint32_t reserved() const { return m_reserved; } evsa_body_t* body() const { return m_body.get(); } phoenix_evsa_t* _root() const { return m__root; } diff --git a/common/ksy/edk2_ftw.ksy b/common/ksy/edk2_ftw.ksy index e3f9fe7..1c23200 100644 --- a/common/ksy/edk2_ftw.ksy +++ b/common/ksy/edk2_ftw.ksy @@ -11,18 +11,11 @@ meta: seq: - id: signature - type: u4 + size: 16 valid: - expr: _ == 0xFFF12B8D or _ == 0x9E58292B -- id: signature_main - contents: [0x96, 0x76, 0x8B, 0x4C, 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50] # FF12B8D-7696-4C8B-A985-2747075B4F50 - if: signature == 0xFFF12B8D -- id: signature_edk2_working_block - contents: [0x68, 0x7C, 0x7D, 0x49, 0x0A, 0xCE, 0x65, 0x00, 0xFD, 0x9F, 0x1B, 0x95] # 9E58292B-7C68-497D-0ACE-6500FD9F1B95 - if: signature == 0x9E58292B -- id: signature_vss2_working_block - contents: [0x68, 0x7C, 0x7D, 0x49, 0xA0, 0xCE, 0x65, 0x00, 0xFD, 0x9F, 0x1B, 0x95] # 9E58292B-7C68-497D-A0CE-6500FD9F1B95 - if: signature == 0x9E58292B + expr: _ == [0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C, 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50] + or _ == [0x2B, 0x29, 0x58, 0x9E, 0x68, 0x7C, 0x7D, 0x49, 0x0A, 0xCE, 0x65, 0x00, 0xFD, 0x9F, 0x1B, 0x95] + or _ == [0x2B, 0x29, 0x58, 0x9E, 0x68, 0x7C, 0x7D, 0x49, 0xA0, 0xCE, 0x65, 0x00, 0xFD, 0x9F, 0x1B, 0x95] - id: crc type: u4 - id: state diff --git a/common/ksy/edk2_vss2.ksy b/common/ksy/edk2_vss2.ksy index 0a79273..5cc9a11 100644 --- a/common/ksy/edk2_vss2.ksy +++ b/common/ksy/edk2_vss2.ksy @@ -13,7 +13,7 @@ seq: - id: signature type: u4 valid: - expr: _ == 0xDDCF3616 or _ == 0xDDCF3617 or _ == 0xAAF32C78 # Beginning of known store GUIDs for VSS2 + expr: _ == 0xDDCF3616 or _ == 0xDDCF3617 or _ == 0xAAF32C78 # Beginning of known store GUIDs for VSS2 - id: signature_auth_var_key_db contents: [0x7B, 0x94, 0x9A, 0x43, 0xA1, 0x80, 0x2E, 0x14, 0x4E, 0xC3, 0x77, 0x92] # AAF32C78-947B-439A-A180-2E144EC37792 if: signature == 0xAAF32C78 @@ -26,7 +26,7 @@ seq: - id: vss2_size type: u4 valid: - expr: _ > len_vss2_store_header.as and _ < 0xFFFFFFFF + expr: _ > len_vss2_store_header.as and _ < 0xFFFFFFFF - id: format type: u1 valid: @@ -40,6 +40,7 @@ seq: - id: body type: vss2_store_body size: vss2_size - len_vss2_store_header + instances: len_vss2_store_header: value: 7 * sizeof @@ -71,7 +72,6 @@ types: - id: reserved type: b25le -# TODO: check if VSS2 stores can have standard VSS variables vss2_variable: seq: - id: invoke_offset @@ -82,7 +82,7 @@ types: - id: signature_last type: u1 valid: - expr: _ == 0x55 + expr: _ == 0x55 if: signature_first == 0xAA - id: state type: u1 @@ -152,7 +152,7 @@ types: len_alignment_padding: value: (((end_offset - offset)+3) & ~3) - (end_offset - offset) len_alignment_padding_auth: - value: (((end_offset_auth - offset)+3) & ~3) - (end_offset - offset) + value: (((end_offset_auth - offset)+3) & ~3) - (end_offset_auth - offset) is_valid: value: state == 0x7F or state == 0x3F is_auth: diff --git a/common/ksy/insyde_fdm.ksy b/common/ksy/insyde_fdm.ksy new file mode 100644 index 0000000..406704f --- /dev/null +++ b/common/ksy/insyde_fdm.ksy @@ -0,0 +1,91 @@ +meta: + id: insyde_fdm + title: Insyde Flash Device + application: Insyde-based UEFI firmware + file-extension: fdm + tags: + - firmware + license: CC0-1.0 + ks-version: 0.9 + endian: le + +seq: +- id: signature + type: u4 + valid: 0x4D444648 # HFDM +- id: store_size + type: u4 +- id: data_offset + type: u4 +- id: entry_size + type: u4 +- id: entry_format + type: u1 +- id: revision + type: u1 +- id: num_extensions + type: u1 +- id: checksum + type: u1 +- id: fd_base_address + type: u8 +- id: extensions + type: fdm_extensions + size: num_extensions * sizeof + if: revision == 3 +- id: board_ids + type: fdm_board_ids + if: revision == 3 +- id: entries + type: fdm_entries + size: store_size - data_offset + +types: + fdm_extensions: + seq: + - id: extensions + type: fdm_extension + repeat: eos + + fdm_extension: + seq: + - id: offset + type: u2 + - id: count + type: u2 + + fdm_board_ids: + seq: + - id: region_index + type: u4 + - id: num_board_ids + type: u4 + - id: board_ids + type: u8 + repeat: expr + repeat-expr: num_board_ids + + fdm_entries: + seq: + - id: entries + type: fdm_entry + repeat: eos + + fdm_entry: + seq: + - id: guid + size: 16 + - id: region_id + size: 16 + - id: region_offset + type: u8 + - id: region_size + type: u8 + - id: attributes + type: u4 + - id: hash + size: _parent._parent.entry_size - 16 - 16 - 8 - 8 - 4 + instances: + region_base: + value: _root.fd_base_address.as + region_offset.as + diff --git a/common/ksy/phoenix_evsa.ksy b/common/ksy/phoenix_evsa.ksy index d680ebd..2264b17 100644 --- a/common/ksy/phoenix_evsa.ksy +++ b/common/ksy/phoenix_evsa.ksy @@ -15,22 +15,22 @@ seq: valid: 0xEC - id: checksum type: u1 -- id: size +- id: len_evsa_store_header type: u2 valid: 20 - id: signature type: u4 - valid: 0x41535645 + valid: 0x41535645 #EVSA - id: attributes type: u4 -- id: store_size +- id: len_evsa_store type: u4 - id: reserved type: u4 - id: body type: evsa_body - size: store_size - 20 - + size: len_evsa_store - len_evsa_store_header + types: evsa_guid: seq: @@ -38,14 +38,39 @@ types: type: u2 - id: guid size: 16 + valid: + expr: _parent.len_evsa_entry == 22 evsa_name: seq: - id: var_id type: u2 - id: name - size: _parent.size - 6 + size: _parent.len_evsa_entry - 6 + evsa_variable_attributes: + seq: + - id: non_volatile + type: b1le + - id: boot_service + type: b1le + - id: runtime + type: b1le + - id: hw_error_record + type: b1le + - id: auth_write + type: b1le + - id: time_based_auth + type: b1le + - id: append_write + type: b1le + - id: reserved + type: b21le + - id: extended_header + type: b1le + - id: reserved1 + type: b3le + evsa_data: seq: - id: guid_id @@ -53,33 +78,47 @@ types: - id: var_id type: u2 - id: attributes + type: evsa_variable_attributes + - id: len_data_ext type: u4 - - id: data_size - type: u4 - if: (attributes & 0x10000000) != 0x10000000 + if: attributes.extended_header - id: data - size: _parent.size - 12 - if: (attributes & 0x10000000) == 0x10000000 + size: _parent.len_evsa_entry - 12 + if: not attributes.extended_header - id: data_ext - size: data_size - if: (attributes & 0x10000000) != 0x10000000 + size: len_data_ext + if: attributes.extended_header evsa_unknown: seq: - - id: unknown + - id: unknown size: 0 - + evsa_entry: seq: - - id: type + - id: entry_type type: u1 - id: checksum type: u1 - - id: size + if: entry_type == 0xE1 + or entry_type == 0xE2 + or entry_type == 0xE3 + or entry_type == 0xED + or entry_type == 0xEE + or entry_type == 0xEF + or entry_type == 0x83 + - id: len_evsa_entry type: u2 + if: entry_type == 0xE1 + or entry_type == 0xE2 + or entry_type == 0xE3 + or entry_type == 0xED + or entry_type == 0xEE + or entry_type == 0xEF + or entry_type == 0x83 - id: body type: - switch-on: type + switch-on: entry_type cases: 0xED: evsa_guid 0xE1: evsa_guid @@ -88,12 +127,21 @@ types: 0xEF: evsa_data 0xE3: evsa_data 0x83: evsa_data - _: evsa_unknown + _: evsa_unknown evsa_body: seq: - id: entries type: evsa_entry + repeat: until + repeat-until: (_.entry_type != 0xED + and _.entry_type != 0xEE + and _.entry_type != 0xEF + and _.entry_type != 0xE1 + and _.entry_type != 0xE2 + and _.entry_type != 0xE3 + and _.entry_type != 0x83) + or _io.eof + - id: free_space + type: u1 repeat: eos - - \ No newline at end of file diff --git a/common/meson.build b/common/meson.build index 2e73307..13ed9fc 100644 --- a/common/meson.build +++ b/common/meson.build @@ -38,7 +38,9 @@ uefitoolcommon = static_library('uefitoolcommon', 'generated/edk2_vss2.cpp', 'generated/edk2_ftw.cpp', 'generated/insyde_fdc.cpp', + 'generated/insyde_fdm.cpp', 'generated/phoenix_flm.cpp', + 'generated/phoenix_evsa.cpp', 'generated/intel_acbp_v1.cpp', 'generated/intel_acbp_v2.cpp', 'generated/intel_keym_v1.cpp', diff --git a/common/nvram.cpp b/common/nvram.cpp index f120a10..dff01d1 100644 --- a/common/nvram.cpp +++ b/common/nvram.cpp @@ -152,7 +152,7 @@ UString efiTimeToUString(const EFI_TIME & time) time.Nanosecond); } -UString flashMapGuidToUString(const EFI_GUID & guid) +UString phoenixFlashMapGuidToUString(const EFI_GUID & guid) { const UByteArray baGuid((const char*)&guid, sizeof(EFI_GUID)); if (baGuid == NVRAM_PHOENIX_FLASH_MAP_VOLUME_HEADER) return UString("Volume header"); diff --git a/common/nvram.h b/common/nvram.h index c162435..29e1e59 100755 --- a/common/nvram.h +++ b/common/nvram.h @@ -274,7 +274,7 @@ typedef struct EVSA_STORE_ENTRY_ { UINT32 Signature; // EVSA signature UINT32 Attributes; UINT32 StoreSize; - UINT32 : 32; + UINT32 Reserved; } EVSA_STORE_ENTRY; typedef struct EVSA_GUID_ENTRY_ { @@ -347,7 +347,7 @@ typedef struct PHOENIX_FLASH_MAP_ENTRY_ { #define NVRAM_PHOENIX_FLASH_MAP_ENTRY_DATA_TYPE_VOLUME 0x0000 #define NVRAM_PHOENIX_FLASH_MAP_ENTRY_DATA_TYPE_DATA_BLOCK 0x0001 -extern UString flashMapGuidToUString(const EFI_GUID & guid); +extern UString phoenixFlashMapGuidToUString(const EFI_GUID & guid); extern const UByteArray NVRAM_PHOENIX_FLASH_MAP_VOLUME_HEADER; // B091E7D2-05A0-4198-94F0-74B7B8C55459 extern const UByteArray NVRAM_PHOENIX_FLASH_MAP_MICROCODES_GUID; // FD3F690E-B4B0-4D68-89DB-19A1A3318F90 diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index 7e36c59..3db2819 100644 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -32,6 +32,7 @@ #include "generated/edk2_ftw.h" #include "generated/insyde_fdc.h" #include "generated/phoenix_flm.h" +#include "generated/phoenix_evsa.h" USTATUS NvramParser::parseNvarStore(const UModelIndex & index) { @@ -387,16 +388,15 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); // Add variables - UINT32 vssVariableOffset = storeOffset + parsed.len_vss_store_header(); + UINT32 vssVariableOffset = parsed.len_vss_store_header(); for (const auto & variable : *parsed.body()->variables()) { UINT8 subtype; // This is the terminating entry, needs special processing if (variable->_is_null_signature_last()) { // Add free space or padding after all variables, if needed - UINT32 freeSpaceOffset = vssVariableOffset - storeOffset; - if (freeSpaceOffset < storeSize) { - UByteArray freeSpace = volumeBody.mid(freeSpaceOffset, storeSize - freeSpaceOffset); + if (vssVariableOffset < storeSize) { + UByteArray freeSpace = vss.mid(vssVariableOffset, storeSize - vssVariableOffset); // Add info info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); @@ -425,7 +425,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 variableSize = (UINT32)(header.size() + body.size()); const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); name = guidToUString(variableGuid); - info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; } else if (variable->is_auth()) { // Authenticated subtype = Subtypes::AuthVssEntry; @@ -435,7 +435,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); name = guidToUString(variableGuid); text = uFromUcs2(variable->name_auth().c_str()); - info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; } else if (!variable->_is_null_apple_data_crc32()) { // Apple CRC32 subtype = Subtypes::AppleVssEntry; @@ -445,7 +445,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); name = guidToUString(variableGuid); text = uFromUcs2(variable->name().c_str()); - info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; } else { // Standard subtype = Subtypes::StandardVssEntry; @@ -455,7 +455,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); name = guidToUString(variableGuid); text = uFromUcs2(variable->name().c_str()); - info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; } // Override variable type to Invalid if needed @@ -472,6 +472,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 + (variable->attributes()->auth_write() << 4) + (variable->attributes()->time_based_auth() << 5) + (variable->attributes()->append_write() << 6) + + (UINT32)(variable->attributes()->reserved() << 7) + (variable->attributes()->apple_data_checksum() << 31); // Add generic info @@ -518,6 +519,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } UByteArray vss2 = volumeBody.mid(storeOffset); + // Check if we are here to parse a special case of FDC store with size override UINT32 originalStoreSize = 0; VSS2_VARIABLE_STORE_HEADER* vss2Header = (VSS2_VARIABLE_STORE_HEADER*)vss2.data(); @@ -527,10 +529,12 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 originalStoreSize = vss2Header->Size; vss2Header->Size = fdcStoreSizeOverride; } + umemstream is(vss2.constData(), vss2.size()); kaitai::kstream ks(&is); edk2_vss2_t parsed(&ks); UINT32 storeSize = parsed.vss2_size(); + // Restore original store size, if needed if (fdcHeaderSizeOverrideRequired) { vss2Header->Size = originalStoreSize; @@ -573,16 +577,15 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); // Add variables - UINT32 vss2VariableOffset = storeOffset + parsed.len_vss2_store_header(); + UINT32 vss2VariableOffset = parsed.len_vss2_store_header(); for (const auto & variable : *parsed.body()->variables()) { UINT8 subtype; // This is the terminating entry, needs special processing if (variable->_is_null_signature_last()) { // Add free space or padding after all variables, if needed - UINT32 freeSpaceOffset = vss2VariableOffset - storeOffset; - if (freeSpaceOffset < storeSize) { - UByteArray freeSpace = volumeBody.mid(freeSpaceOffset, storeSize - freeSpaceOffset); + if (vss2VariableOffset < storeSize) { + UByteArray freeSpace = vss2.mid(vss2VariableOffset, storeSize - vss2VariableOffset); // Add info info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); @@ -601,25 +604,28 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 // This is a normal entry UINT32 variableSize; + UINT32 alignmentSize; if (variable->is_auth()) { // Authenticated subtype = Subtypes::AuthVssEntry; header = vss2.mid(vss2VariableOffset, variable->len_auth_header() + variable->len_name_auth()); body = vss2.mid(vss2VariableOffset + header.size(), variable->len_data_auth()); variableSize = (UINT32)(header.size() + body.size()); + alignmentSize = variable->len_alignment_padding_auth(); const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); name = guidToUString(variableGuid); text = uFromUcs2(variable->name_auth().c_str()); - info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; } else { // Standard subtype = Subtypes::StandardVssEntry; header = vss2.mid(vss2VariableOffset, variable->len_standard_header() + variable->len_name()); body = vss2.mid(vss2VariableOffset + header.size(), variable->len_data()); variableSize = (UINT32)(header.size() + body.size()); + alignmentSize = variable->len_alignment_padding(); const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); name = guidToUString(variableGuid); text = uFromUcs2(variable->name().c_str()); - info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + info = UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; } // Override variable type to Invalid if needed @@ -635,7 +641,8 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 + (variable->attributes()->hw_error_record() << 3) + (variable->attributes()->auth_write() << 4) + (variable->attributes()->time_based_auth() << 5) - + (variable->attributes()->append_write() << 6); + + (variable->attributes()->append_write() << 6) + + (UINT32)(variable->attributes()->reserved() << 7); // Add generic info info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (", @@ -656,7 +663,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 // Add tree item model->addItem(vss2VariableOffset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex); - vss2VariableOffset += variableSize; + vss2VariableOffset += (variableSize + alignmentSize); } storeOffset += storeSize - 1; @@ -836,7 +843,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::SysFStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); // Add variables - UINT32 sysfVariableOffset = storeOffset + parsed.len_sysf_store_header(); + UINT32 sysfVariableOffset = parsed.len_sysf_store_header(); for (const auto & variable : *parsed.body()->variables()) { UINT8 subtype; @@ -850,11 +857,11 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } if (variable->len_name() == 3 && variable->name() == "EOF") { - header = volumeBody.mid(sysfVariableOffset, 4); + header = sysf.mid(sysfVariableOffset, 4); } else { - header = volumeBody.mid(sysfVariableOffset, sizeof(UINT8) + (UINT32)variable->len_name() + sizeof(UINT16)); - body = volumeBody.mid(sysfVariableOffset + header.size(), (UINT32)variable->len_data()); + header = sysf.mid(sysfVariableOffset, sizeof(UINT8) + (UINT32)variable->len_name() + sizeof(UINT16)); + body = sysf.mid(sysfVariableOffset + header.size(), (UINT32)variable->len_data()); } // Add generic info UINT32 variableSize = (UINT32)header.size() + (UINT32)body.size(); @@ -870,9 +877,8 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } // Add free space or padding after all variables, if needed - UINT32 freeSpaceOffset = sysfVariableOffset - storeOffset; - if (freeSpaceOffset < storeSize) { - UByteArray freeSpace = volumeBody.mid(freeSpaceOffset, storeSize - freeSpaceOffset); + if (sysfVariableOffset < storeSize) { + UByteArray freeSpace = sysf.mid(sysfVariableOffset, storeSize - sysfVariableOffset); // Add info info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); @@ -894,7 +900,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 // Parsing failed, try something else } - // Phoenix FlashMap + // Phoenix SCT FlashMap try { if (volumeBodySize - storeOffset < NVRAM_PHOENIX_FLASH_MAP_TOTAL_SIZE) { // No need to parse further, the rest of the volume is too small @@ -920,7 +926,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 body = flm.mid(header.size(), storeSize - header.size()); // Add info - name = UString("FlashMap"); + name = UString("Phoenix SCT FlashMap"); info = usprintf("Signature: _FLASH_MAP\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nEntries: %u\nReserved: %08Xh", storeSize, storeSize, (UINT32)header.size(), (UINT32)header.size(), @@ -929,10 +935,10 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 parsed.reserved()); // Add header tree item - UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::FlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); + UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::PhoenixFlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); // Add entries - UINT32 entryOffset = storeOffset + parsed.len_flm_store_header(); + UINT32 entryOffset = parsed.len_flm_store_header(); for (const auto & entry : *parsed.entries()) { UINT8 subtype; @@ -948,8 +954,8 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 const EFI_GUID guid = readUnaligned((const EFI_GUID*)entry->guid().c_str()); name = guidToUString(guid); - text = flashMapGuidToUString(guid); - header = volumeBody.mid(entryOffset, parsed.len_flm_entry()); + text = phoenixFlashMapGuidToUString(guid); + header = flm.mid(entryOffset, parsed.len_flm_entry()); // Add info UINT32 entrySize = (UINT32)header.size(); @@ -963,7 +969,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 entry->physical_address()); // Add tree item - model->addItem(entryOffset, Types::FlashMapEntry, subtype, name, text, info, header, UByteArray(), UByteArray(), Fixed, headerIndex); + model->addItem(entryOffset, Types::PhoenixFlashMapEntry, subtype, name, text, info, header, UByteArray(), UByteArray(), Fixed, headerIndex); entryOffset += entrySize; } @@ -996,7 +1002,220 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } // Phoenix EVSA - + try { + if (volumeBodySize - storeOffset < sizeof(EVSA_STORE_ENTRY)) { + // No need to parse further, the rest of the volume is too small + throw 0; + } + + UByteArray evsa = volumeBody.mid(storeOffset); + umemstream is(evsa.constData(), evsa.size()); + kaitai::kstream ks(&is); + phoenix_evsa_t parsed(&ks); + UINT32 storeSize = parsed.len_evsa_store(); + + // Phoenix EVSA store at current offset parsed correctly + // Check if we need to add a padding before it + if (!outerPadding.isEmpty()) { + info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size()); + model->addItem(previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index); + outerPadding.clear(); + } + + // Construct header and body + header = evsa.left(parsed.len_evsa_store_header()); + body = evsa.mid(header.size(), storeSize - header.size()); + + const EVSA_STORE_ENTRY* evsaStoreHeader = (const EVSA_STORE_ENTRY*)header.constData(); + UINT8 calculated = calculateChecksum8(((const UINT8*)evsaStoreHeader) + 2, evsaStoreHeader->Header.Size - 2); + + // Add info + name = UString("EVSA Store"); + info = usprintf("Signature: EVSA\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nAttributes: %08Xh\nReserved: %08Xh\nChecksum: %02Xh", + storeSize, storeSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + parsed.attributes(), + parsed.reserved(), + parsed.checksum()) + + (parsed.checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")); + + // Add header tree item + UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::EvsaStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); + + // Add entries + std::map guidMap; + std::map nameMap; + UINT32 entryOffset = parsed.len_evsa_store_header(); + for (const auto & entry : *parsed.body()->entries()) { + UINT8 subtype; + UINT32 entrySize; + + // This is the terminating entry, needs special processing + if (entry->_is_null_checksum()) { + // Add free space or padding after all variables, if needed + if (entryOffset < storeSize) { + UByteArray freeSpace = evsa.mid(entryOffset, storeSize - entryOffset); + // Add info + info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); + + // Check that remaining unparsed bytes are actually empty + if (freeSpace.count(emptyByte) == freeSpace.size()) { // Free space + // Add tree item + model->addItem(entryOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex); + } + else { + // Add tree item + model->addItem(entryOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex); + } + } + break; + } + + const EVSA_ENTRY_HEADER* entryHeader = (const EVSA_ENTRY_HEADER*)(evsa.constData() + entryOffset); + calculated = calculateChecksum8(((const UINT8*)entryHeader) + 2, entryHeader->Size - 2); + + // GUID entry + if (entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_GUID1 || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_GUID2) { + const phoenix_evsa_t::evsa_guid_t* guidEntry = (const phoenix_evsa_t::evsa_guid_t*)(entry->body()); + header = evsa.mid(entryOffset, sizeof(EVSA_GUID_ENTRY)); + body = evsa.mid(entryOffset + sizeof(EVSA_GUID_ENTRY), entry->len_evsa_entry() - header.size()); + entrySize = (UINT32)(header.size() + body.size()); + EFI_GUID guid = *(const EFI_GUID*)(guidEntry->guid().c_str()); + name = guidToUString(guid); + info = UString("GUID: ") + guidToUString(guid, false) + + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", + entrySize, entrySize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + entry->entry_type(), + entry->checksum()) + + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + + usprintf("\nGuidId: %04Xh", guidEntry->guid_id()); + subtype = Subtypes::GuidEvsaEntry; + guidMap.insert(std::pair(guidEntry->guid_id(), guid)); + } + // Name entry + else if (entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_NAME1 || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_NAME2) { + const phoenix_evsa_t::evsa_name_t* nameEntry = (const phoenix_evsa_t::evsa_name_t*)(entry->body()); + header = evsa.mid(entryOffset, sizeof(EVSA_NAME_ENTRY)); + body = evsa.mid(entryOffset + sizeof(EVSA_NAME_ENTRY), entry->len_evsa_entry() - header.size()); + entrySize = (UINT32)(header.size() + body.size()); + name = uFromUcs2(body.constData()); + info = UString("Name: ") + name + + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", + entrySize, entrySize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + entry->entry_type(), + entry->checksum()) + + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + + usprintf("\nVarId: %04Xh", nameEntry->var_id()); + subtype = Subtypes::NameEvsaEntry; + nameMap.insert(std::pair(nameEntry->var_id(), name)); + } + // Data entry + else if (entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA1 + || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA2 + || entry->entry_type() == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) { + phoenix_evsa_t::evsa_data_t* dataEntry = (phoenix_evsa_t::evsa_data_t*)(entry->body()); + if (dataEntry->_is_null_len_data_ext()) { + header = evsa.mid(entryOffset, sizeof(EVSA_DATA_ENTRY)); + body = evsa.mid(entryOffset + sizeof(EVSA_DATA_ENTRY), entry->len_evsa_entry() - header.size()); + } + else { + header = evsa.mid(entryOffset, sizeof(EVSA_DATA_ENTRY_EXTENDED)); + body = evsa.mid(entryOffset + sizeof(EVSA_DATA_ENTRY_EXTENDED), dataEntry->len_data_ext()); + } + entrySize = (UINT32)(header.size() + body.size()); + name = UString("Data"); + subtype = Subtypes::DataEvsaEntry; + + const UINT32 attributes = dataEntry->attributes()->non_volatile() + + (dataEntry->attributes()->boot_service() << 1) + + (dataEntry->attributes()->runtime() << 2) + + (dataEntry->attributes()->hw_error_record() << 3) + + (dataEntry->attributes()->auth_write() << 4) + + (dataEntry->attributes()->time_based_auth() << 5) + + (dataEntry->attributes()->append_write() << 6) + + (UINT32)(dataEntry->attributes()->reserved() << 7) + + (dataEntry->attributes()->extended_header() << 28) + + (UINT32)(dataEntry->attributes()->reserved1() << 29); + + info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", + entrySize, entrySize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + entry->entry_type(), + entry->checksum()) + + (entry->checksum() != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (", + dataEntry->var_id(), + dataEntry->guid_id(), + attributes) + + evsaAttributesToUString(attributes) + UString(")"); + } + + // Add tree item + model->addItem(entryOffset, Types::EvsaEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex); + + entryOffset += entrySize; + } + + // Reparse all data variables to detect invalid ones and assign name and test to valid ones + for (int i = 0; i < model->rowCount(headerIndex); i++) { + UModelIndex current = headerIndex.model()->index(i, 0, headerIndex); + + if (model->subtype(current) == Subtypes::DataEvsaEntry) { + UByteArray header = model->header(current); + const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)header.constData(); + UString guid; + 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); + model->setName(current, UString("Invalid")); + model->setText(current, UString()); + msg(usprintf("%s: data variable with invalid GuidId and invalid VarId", __FUNCTION__), current); + } + else if (guid.isEmpty()) { // Guid not found + model->setSubtype(current, Subtypes::InvalidEvsaEntry); + model->setName(current, UString("Invalid")); + model->setText(current, UString()); + msg(usprintf("%s: data variable with invalid GuidId", __FUNCTION__), current); + } + else if (name.isEmpty()) { // Name not found + model->setSubtype(current, Subtypes::InvalidEvsaEntry); + model->setName(current, UString("Invalid")); + model->setText(current, UString()); + msg(usprintf("%s: data variable with invalid VarId", __FUNCTION__), current); + } + else { // Variable is OK, rename it + if (dataHeader->Header.Type == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) { + model->setSubtype(current, Subtypes::InvalidEvsaEntry); + model->setName(current, UString("Invalid")); + model->setText(current, UString()); + } + else { + model->setName(current, guid); + model->setText(current, name); + model->addInfo(current, UString("GUID: ") + guid + UString("\nName: ") + name + "\n", false); + } + } + } + } + + storeOffset += storeSize - 1; + previousStoreEndOffset = storeOffset + 1; + continue; + } catch (...) { + // Parsing failed, try something else + } // Phoenix CMDB // Phoenix SLIC Pubkey/Marker diff --git a/common/types.cpp b/common/types.cpp index 8762fcd..375e7a3 100755 --- a/common/types.cpp +++ b/common/types.cpp @@ -42,45 +42,47 @@ UString regionTypeToUString(const UINT8 type) UString itemTypeToUString(const UINT8 type) { switch (type) { - case Types::Root: return UString("Root"); - case Types::Image: return UString("Image"); - case Types::Capsule: return UString("Capsule"); - case Types::Region: return UString("Region"); - case Types::Volume: return UString("Volume"); - case Types::Padding: return UString("Padding"); - case Types::File: return UString("File"); - case Types::Section: return UString("Section"); - case Types::FreeSpace: return UString("Free space"); - case Types::VssStore: return UString("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::SysFStore: return UString("SysF store"); - case Types::EvsaStore: return UString("EVSA store"); - case Types::CmdbStore: return UString("CMDB store"); - case Types::FlashMapStore: return UString("FlashMap store"); - case Types::NvarGuidStore: return UString("NVAR GUID store"); - case Types::NvarEntry: return UString("NVAR entry"); - case Types::VssEntry: return UString("VSS entry"); - case Types::SysFEntry: return UString("SysF entry"); - case Types::EvsaEntry: return UString("EVSA entry"); - case Types::FlashMapEntry: return UString("FlashMap entry"); - case Types::Microcode: return UString("Microcode"); - case Types::SlicData: return UString("SLIC data"); - case Types::FptStore: return UString("FPT store"); - case Types::FptEntry: return UString("FPT entry"); - case Types::IfwiHeader: return UString("IFWI header"); - case Types::IfwiPartition: return UString("IFWI partition"); - case Types::FptPartition: return UString("FPT partition"); - case Types::BpdtStore: return UString("BPDT store"); - case Types::BpdtEntry: return UString("BPDT entry"); - case Types::BpdtPartition: return UString("BPDT partition"); - case Types::CpdStore: return UString("CPD store"); - case Types::CpdEntry: return UString("CPD entry"); - case Types::CpdPartition: return UString("CPD partition"); - case Types::CpdExtension: return UString("CPD extension"); - case Types::CpdSpiEntry: return UString("CPD SPI entry"); - case Types::StartupApDataEntry: return UString("Startup AP data"); + case Types::Root: return UString("Root"); + case Types::Image: return UString("Image"); + case Types::Capsule: return UString("Capsule"); + case Types::Region: return UString("Region"); + case Types::Volume: return UString("Volume"); + case Types::Padding: return UString("Padding"); + case Types::File: return UString("File"); + case Types::Section: return UString("Section"); + case Types::FreeSpace: return UString("Free space"); + case Types::VssStore: return UString("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::SysFStore: return UString("SysF store"); + case Types::EvsaStore: return UString("EVSA store"); + case Types::CmdbStore: return UString("CMDB store"); + case Types::PhoenixFlashMapStore: return UString("FlashMap store"); + case Types::InsydeFlashDeviceMapStore: return UString("FlashDeviceMap store"); + case Types::NvarGuidStore: return UString("NVAR GUID store"); + case Types::NvarEntry: return UString("NVAR entry"); + case Types::VssEntry: return UString("VSS entry"); + case Types::SysFEntry: return UString("SysF entry"); + case Types::EvsaEntry: return UString("EVSA entry"); + case Types::PhoenixFlashMapEntry: return UString("FlashMap entry"); + case Types::InsydeFlashDeviceMapEntry: return UString("FlashDeviceMap entry"); + case Types::Microcode: return UString("Microcode"); + case Types::SlicData: return UString("SLIC data"); + case Types::FptStore: return UString("FPT store"); + case Types::FptEntry: return UString("FPT entry"); + case Types::IfwiHeader: return UString("IFWI header"); + case Types::IfwiPartition: return UString("IFWI partition"); + case Types::FptPartition: return UString("FPT partition"); + case Types::BpdtStore: return UString("BPDT store"); + case Types::BpdtEntry: return UString("BPDT entry"); + case Types::BpdtPartition: return UString("BPDT partition"); + case Types::CpdStore: return UString("CPD store"); + case Types::CpdEntry: return UString("CPD entry"); + case Types::CpdPartition: return UString("CPD partition"); + case Types::CpdExtension: return UString("CPD extension"); + case Types::CpdSpiEntry: return UString("CPD SPI entry"); + case Types::StartupApDataEntry: return UString("Startup AP data"); } return usprintf("Unknown %02Xh", type); @@ -139,7 +141,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) else if (subtype == Subtypes::NameEvsaEntry) return UString("Name"); else if (subtype == Subtypes::DataEvsaEntry) return UString("Data"); break; - case Types::FlashMapEntry: + case Types::PhoenixFlashMapEntry: if (subtype == Subtypes::VolumeFlashMapEntry) return UString("Volume"); else if (subtype == Subtypes::DataFlashMapEntry) return UString("Data"); else if (subtype == Subtypes::UnknownFlashMapEntry) return UString("Unknown"); @@ -250,3 +252,29 @@ UString hashTypeToUString(const UINT16 algorithm_id) return usprintf("Unknown %04Xh", algorithm_id); } + +UString insydeFlashDeviceMapEntryTypeGuidToUString(const EFI_GUID & guid) +{ + const UByteArray baGuid((const char*)&guid, sizeof(EFI_GUID)); + if (baGuid == INSYDE_FLASH_MAP_REGION_BOOT_FV_GUID) return UString("Boot Firmare Volume"); + if (baGuid == INSYDE_FLASH_MAP_REGION_BVDT_GUID) return UString("BIOS Version Data Table"); + if (baGuid == INSYDE_FLASH_MAP_REGION_EC_GUID) return UString("EC Firmware"); + if (baGuid == INSYDE_FLASH_MAP_REGION_FTW_BACKUP_GUID) return UString("FTW Backup"); + if (baGuid == INSYDE_FLASH_MAP_REGION_FTW_STATE_GUID) return UString("FTW State"); + if (baGuid == INSYDE_FLASH_MAP_REGION_FV_GUID) return UString("Firmare Volume"); + if (baGuid == INSYDE_FLASH_MAP_REGION_FLASH_DEVICE_MAP_GUID) return UString("Flash Device Map"); + if (baGuid == INSYDE_FLASH_MAP_REGION_LOGO_GUID) return UString("Logo"); + if (baGuid == INSYDE_FLASH_MAP_REGION_MICROCODE_GUID) return UString("Microcode"); + if (baGuid == INSYDE_FLASH_MAP_REGION_MSDM_TABLE_GUID) return UString("MSDM Table"); + if (baGuid == INSYDE_FLASH_MAP_REGION_MULTI_CONFIG_GUID) return UString("MultiConfig"); + if (baGuid == INSYDE_FLASH_MAP_REGION_VAR_DEFAULT_GUID) return UString("Variable Defaults"); + if (baGuid == INSYDE_FLASH_MAP_REGION_SMBIOS_UPDATE_GUID) return UString("SMBIOS Update"); + if (baGuid == INSYDE_FLASH_MAP_REGION_VAR_GUID) return UString("Variables"); + if (baGuid == INSYDE_FLASH_MAP_REGION_UNKNOWN_GUID) return UString("Unknown"); + if (baGuid == INSYDE_FLASH_MAP_REGION_UNUSED_GUID) return UString("Unused"); + if (baGuid == INSYDE_FLASH_MAP_REGION_USB_OPTION_ROM_GUID) return UString("USB Option ROM"); + if (baGuid == INSYDE_FLASH_MAP_REGION_DXE_FV_GUID) return UString("DXE Firmare Volume"); + if (baGuid == INSYDE_FLASH_MAP_REGION_PEI_FV_GUID) return UString("PEI Firmare Volume"); + if (baGuid == INSYDE_FLASH_MAP_REGION_UNSIGNED_FV_GUID) return UString("Unsigned Firmare Volume"); + return guidToUString(guid); +} diff --git a/common/types.h b/common/types.h index 2f0b062..0ee8247 100755 --- a/common/types.h +++ b/common/types.h @@ -49,14 +49,16 @@ namespace Types { FdcStore, SysFStore, EvsaStore, - FlashMapStore, + PhoenixFlashMapStore, + InsydeFlashDeviceMapStore, CmdbStore, NvarGuidStore, NvarEntry, VssEntry, SysFEntry, EvsaEntry, - FlashMapEntry, + PhoenixFlashMapEntry, + InsydeFlashDeviceMapEntry, Microcode, SlicData, IfwiHeader, @@ -204,5 +206,6 @@ extern UString compressionTypeToUString(const UINT8 algorithm); extern UString regionTypeToUString(const UINT8 type); extern UString fitEntryTypeToUString(const UINT8 type); extern UString hashTypeToUString(const UINT16 digest_agorithm_id); +extern UString insydeFlashDeviceMapEntryTypeGuidToUString(const EFI_GUID & guid); #endif // TYPES_H diff --git a/common/utility.cpp b/common/utility.cpp index ac809eb..612f3da 100755 --- a/common/utility.cpp +++ b/common/utility.cpp @@ -83,7 +83,8 @@ UString uniqueItemName(const UModelIndex & index) case Types::VssEntry: case Types::SysFEntry: case Types::EvsaEntry: - case Types::FlashMapEntry: + case Types::PhoenixFlashMapEntry: + case Types::InsydeFlashDeviceMapEntry: case Types::File: name = itemText.isEmpty() ? itemName : itemName + '_' + itemText; break; diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 2b70347..37c3882 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -37,7 +37,9 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/insyde_fdm.cpp ../common/generated/phoenix_flm.cpp + ../common/generated/phoenix_evsa.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp ../common/generated/intel_keym_v1.cpp