diff --git a/UEFIExtract/CMakeLists.txt b/UEFIExtract/CMakeLists.txt index 2c5842f..e27c748 100644 --- a/UEFIExtract/CMakeLists.txt +++ b/UEFIExtract/CMakeLists.txt @@ -40,6 +40,7 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/phoenix_flm.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 07d27f8..fcfeece 100644 --- a/UEFIFind/CMakeLists.txt +++ b/UEFIFind/CMakeLists.txt @@ -37,6 +37,7 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/phoenix_flm.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 711b073..3228960 100644 --- a/UEFITool/CMakeLists.txt +++ b/UEFITool/CMakeLists.txt @@ -73,6 +73,7 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/phoenix_flm.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp ../common/generated/intel_keym_v1.cpp diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro index 411b3df..39e6d28 100644 --- a/UEFITool/uefitool.pro +++ b/UEFITool/uefitool.pro @@ -56,6 +56,7 @@ HEADERS += uefitool.h \ ../common/generated/edk2_vss2.h \ ../common/generated/edk2_ftw.h \ ../common/generated/insyde_fdc.h \ + ../common/generated/phoenix_flm.h \ ../common/generated/intel_acbp_v1.h \ ../common/generated/intel_acbp_v2.h \ ../common/generated/intel_keym_v1.h \ @@ -128,6 +129,7 @@ SOURCES += uefitool_main.cpp \ ../common/generated/edk2_vss2.cpp \ ../common/generated/edk2_ftw.cpp \ ../common/generated/insyde_fdc.cpp \ + ../common/generated/phoenix_flm.cpp \ ../common/generated/intel_acbp_v1.cpp \ ../common/generated/intel_acbp_v2.cpp \ ../common/generated/intel_keym_v1.cpp \ diff --git a/common/generated/edk2_vss.cpp b/common/generated/edk2_vss.cpp index d21701a..9c5ecac 100644 --- a/common/generated/edk2_vss.cpp +++ b/common/generated/edk2_vss.cpp @@ -23,7 +23,7 @@ void edk2_vss_t::_read() { m_vss_size = m__io->read_u4le(); { uint32_t _ = vss_size(); - if (!( ((_ > len_vss_store_header()) && (_ < 4294967295UL)) )) { + if (!( ((_ > static_cast(len_vss_store_header())) && (_ < 4294967295UL)) )) { throw kaitai::validation_expr_error(vss_size(), _io(), std::string("/seq/1")); } } @@ -149,7 +149,7 @@ void edk2_vss_t::vss_variable_t::_read() { m_len_total = m__io->read_u4le(); { uint32_t _ = len_total(); - if (!(_ >= ((len_intel_legacy_header() + 4) + 1))) { + if (!(_ >= ((static_cast(len_intel_legacy_header()) + 4) + 1))) { throw kaitai::validation_expr_error(len_total(), _io(), std::string("/types/vss_variable/seq/5")); } } diff --git a/common/generated/edk2_vss2.cpp b/common/generated/edk2_vss2.cpp index 848d472..763c7f2 100644 --- a/common/generated/edk2_vss2.cpp +++ b/common/generated/edk2_vss2.cpp @@ -47,7 +47,7 @@ void edk2_vss2_t::_read() { m_vss2_size = m__io->read_u4le(); { uint32_t _ = vss2_size(); - if (!( ((_ > len_vss2_store_header()) && (_ < 4294967295UL)) )) { + if (!( ((_ > static_cast(len_vss2_store_header())) && (_ < 4294967295UL)) )) { throw kaitai::validation_expr_error(vss2_size(), _io(), std::string("/seq/4")); } } diff --git a/common/generated/insyde_fdc.cpp b/common/generated/insyde_fdc.cpp index 003f157..2312547 100644 --- a/common/generated/insyde_fdc.cpp +++ b/common/generated/insyde_fdc.cpp @@ -21,7 +21,7 @@ void insyde_fdc_t::_read() { m_fdc_size = m__io->read_u4le(); { uint32_t _ = fdc_size(); - if (!( ((_ > len_fdc_store_header()) && (_ < 4294967295UL)) )) { + if (!( ((_ > static_cast(len_fdc_store_header())) && (_ < 4294967295UL)) )) { throw kaitai::validation_expr_error(fdc_size(), _io(), std::string("/seq/1")); } } diff --git a/common/generated/phoenix_flm.cpp b/common/generated/phoenix_flm.cpp new file mode 100644 index 0000000..c1d9228 --- /dev/null +++ b/common/generated/phoenix_flm.cpp @@ -0,0 +1,93 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "phoenix_flm.h" +#include "../kaitai/exceptions.h" + +phoenix_flm_t::phoenix_flm_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, phoenix_flm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; (void)p__root; + m_entries = nullptr; + m_free_space = nullptr; + f_len_flm_store = false; + f_len_flm_store_header = false; + f_len_flm_entry = false; + _read(); +} + +void phoenix_flm_t::_read() { + m_signature = m__io->read_bytes(10); + if (!(signature() == std::string("\x5F\x46\x4C\x41\x53\x48\x5F\x4D\x41\x50", 10))) { + throw kaitai::validation_not_equal_error(std::string("\x5F\x46\x4C\x41\x53\x48\x5F\x4D\x41\x50", 10), signature(), _io(), std::string("/seq/0")); + } + m_num_entries = m__io->read_u2le(); + { + uint16_t _ = num_entries(); + if (!(_ <= 113)) { + throw kaitai::validation_expr_error(num_entries(), _io(), std::string("/seq/1")); + } + } + m_reserved = m__io->read_u4le(); + m_entries = std::unique_ptr>>(new std::vector>()); + const int l_entries = num_entries(); + for (int i = 0; i < l_entries; i++) { + m_entries->push_back(std::move(std::unique_ptr(new flm_entry_t(m__io, this, m__root)))); + } + m_free_space = std::unique_ptr>(new std::vector()); + const int l_free_space = ((len_flm_store() - len_flm_store_header()) - (len_flm_entry() * num_entries())); + for (int i = 0; i < l_free_space; i++) { + m_free_space->push_back(std::move(m__io->read_u1())); + } +} + +phoenix_flm_t::~phoenix_flm_t() { + _clean_up(); +} + +void phoenix_flm_t::_clean_up() { +} + +phoenix_flm_t::flm_entry_t::flm_entry_t(kaitai::kstream* p__io, phoenix_flm_t* p__parent, phoenix_flm_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void phoenix_flm_t::flm_entry_t::_read() { + m_guid = m__io->read_bytes(16); + m_data_type = m__io->read_u2le(); + m_entry_type = m__io->read_u2le(); + m_physical_address = m__io->read_u8le(); + m_size = m__io->read_u4le(); + m_offset = m__io->read_u4le(); +} + +phoenix_flm_t::flm_entry_t::~flm_entry_t() { + _clean_up(); +} + +void phoenix_flm_t::flm_entry_t::_clean_up() { +} + +int32_t phoenix_flm_t::len_flm_store() { + if (f_len_flm_store) + return m_len_flm_store; + m_len_flm_store = 4096; + f_len_flm_store = true; + return m_len_flm_store; +} + +int8_t phoenix_flm_t::len_flm_store_header() { + if (f_len_flm_store_header) + return m_len_flm_store_header; + m_len_flm_store_header = 16; + f_len_flm_store_header = true; + return m_len_flm_store_header; +} + +int8_t phoenix_flm_t::len_flm_entry() { + if (f_len_flm_entry) + return m_len_flm_entry; + m_len_flm_entry = 36; + f_len_flm_entry = true; + return m_len_flm_entry; +} diff --git a/common/generated/phoenix_flm.h b/common/generated/phoenix_flm.h new file mode 100644 index 0000000..a42b9c6 --- /dev/null +++ b/common/generated/phoenix_flm.h @@ -0,0 +1,100 @@ +#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 phoenix_flm_t : public kaitai::kstruct { + +public: + class flm_entry_t; + + phoenix_flm_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, phoenix_flm_t* p__root = nullptr); + +private: + void _read(); + void _clean_up(); + +public: + ~phoenix_flm_t(); + + class flm_entry_t : public kaitai::kstruct { + + public: + + flm_entry_t(kaitai::kstream* p__io, phoenix_flm_t* p__parent = nullptr, phoenix_flm_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~flm_entry_t(); + + private: + std::string m_guid; + uint16_t m_data_type; + uint16_t m_entry_type; + uint64_t m_physical_address; + uint32_t m_size; + uint32_t m_offset; + phoenix_flm_t* m__root; + phoenix_flm_t* m__parent; + + public: + std::string guid() const { return m_guid; } + uint16_t data_type() const { return m_data_type; } + uint16_t entry_type() const { return m_entry_type; } + uint64_t physical_address() const { return m_physical_address; } + uint32_t size() const { return m_size; } + uint32_t offset() const { return m_offset; } + phoenix_flm_t* _root() const { return m__root; } + phoenix_flm_t* _parent() const { return m__parent; } + }; + +private: + bool f_len_flm_store; + int32_t m_len_flm_store; + +public: + int32_t len_flm_store(); + +private: + bool f_len_flm_store_header; + int8_t m_len_flm_store_header; + +public: + int8_t len_flm_store_header(); + +private: + bool f_len_flm_entry; + int8_t m_len_flm_entry; + +public: + int8_t len_flm_entry(); + +private: + std::string m_signature; + uint16_t m_num_entries; + uint32_t m_reserved; + std::unique_ptr>> m_entries; + std::unique_ptr> m_free_space; + phoenix_flm_t* m__root; + kaitai::kstruct* m__parent; + +public: + std::string signature() const { return m_signature; } + uint16_t num_entries() const { return m_num_entries; } + uint32_t reserved() const { return m_reserved; } + std::vector>* entries() const { return m_entries.get(); } + std::vector* free_space() const { return m_free_space.get(); } + phoenix_flm_t* _root() const { return m__root; } + kaitai::kstruct* _parent() const { return m__parent; } +}; diff --git a/common/ksy/edk2_vss.ksy b/common/ksy/edk2_vss.ksy index ed478c1..a36c5df 100644 --- a/common/ksy/edk2_vss.ksy +++ b/common/ksy/edk2_vss.ksy @@ -17,7 +17,7 @@ seq: - id: vss_size type: u4 valid: - expr: _ > len_vss_store_header and _ < 0xFFFFFFFF + expr: _ > len_vss_store_header.as and _ < 0xFFFFFFFF - id: format type: u1 valid: @@ -87,7 +87,7 @@ types: type: u4 if: signature_first == 0xAA and is_intel_legacy valid: - expr: _ >= len_intel_legacy_header + 4 + 1 # Header size + at least one UCS2 character for the name + UCS2 null terminator + at least one byte of data + expr: _ >= len_intel_legacy_header.as + 4 + 1 # Header size + at least one UCS2 character for the name + UCS2 null terminator + at least one byte of data # ^^^ Intel legacy # Next 2 fields can be of any value for an authenticated variable due to them being a combined value of MonothonicCounter - id: len_name diff --git a/common/ksy/edk2_vss2.ksy b/common/ksy/edk2_vss2.ksy index 07903ee..0a79273 100644 --- a/common/ksy/edk2_vss2.ksy +++ b/common/ksy/edk2_vss2.ksy @@ -26,7 +26,7 @@ seq: - id: vss2_size type: u4 valid: - expr: _ > len_vss2_store_header and _ < 0xFFFFFFFF + expr: _ > len_vss2_store_header.as and _ < 0xFFFFFFFF - id: format type: u1 valid: diff --git a/common/ksy/insyde_fdc.ksy b/common/ksy/insyde_fdc.ksy index 038721a..1d6ec93 100644 --- a/common/ksy/insyde_fdc.ksy +++ b/common/ksy/insyde_fdc.ksy @@ -17,7 +17,7 @@ seq: - id: fdc_size type: u4 valid: - expr: _ > len_fdc_store_header and _ < 0xFFFFFFFF + expr: _ > len_fdc_store_header.as and _ < 0xFFFFFFFF - id: body size: fdc_size - len_fdc_store_header instances: diff --git a/common/ksy/phoenix_flm.ksy b/common/ksy/phoenix_flm.ksy new file mode 100644 index 0000000..d46acee --- /dev/null +++ b/common/ksy/phoenix_flm.ksy @@ -0,0 +1,54 @@ +meta: + id: phoenix_flm + title: Phoenix flash map + application: Phoenix-based UEFI firmware + file-extension: flm + tags: + - firmware + license: CC0-1.0 + ks-version: 0.9 + endian: le + +seq: +- id: signature + contents: [0x5F, 0x46, 0x4C, 0x41, 0x53, 0x48, 0x5F, 0x4D, 0x41, 0x50] # _FLASH_MAP +- id: num_entries + type: u2 + valid: + expr: _ <= 113 # Needs to fit into the last 0x1000 bytes of the NVRAM volume +- id: reserved + type: u4 +- id: entries + type: flm_entry + repeat: expr + repeat-expr: num_entries +- id: free_space + type: u1 + repeat: expr + repeat-expr: len_flm_store - len_flm_store_header - len_flm_entry * num_entries + +instances: + len_flm_store: + value: 0x1000 + len_flm_store_header: + value: 16 + len_flm_entry: + value: 36 + +types: + flm_entry: + seq: + - id: guid + size: 16 + - id: data_type + type: u2 + - id: entry_type + type: u2 + - id: physical_address + type: u8 + - id: size + type: u4 + - id: offset + type: u4 + + diff --git a/common/meson.build b/common/meson.build index de04cb9..2e73307 100644 --- a/common/meson.build +++ b/common/meson.build @@ -38,6 +38,7 @@ uefitoolcommon = static_library('uefitoolcommon', 'generated/edk2_vss2.cpp', 'generated/edk2_ftw.cpp', 'generated/insyde_fdc.cpp', + 'generated/phoenix_flm.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 93bf7a9..f120a10 100644 --- a/common/nvram.cpp +++ b/common/nvram.cpp @@ -17,6 +17,8 @@ // // GUIDs mentioned in by nvram.h // +extern const UByteArray ZERO_GUID // 00000000-0000-0000-0000-000000000000 +("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); extern const UByteArray NVRAM_NVAR_STORE_FILE_GUID // CEF5B9A3-476D-497F-9FDC-E98143E0422C ("\xA3\xB9\xF5\xCE\x6D\x47\x7F\x49\x9F\xDC\xE9\x81\x43\xE0\x42\x2C", 16); extern const UByteArray NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID // 9221315B-30BB-46B5-813E-1B1BF4712BD3 @@ -168,6 +170,7 @@ UString flashMapGuidToUString(const EFI_GUID & guid) || baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA6_GUID || baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA7_GUID) return UString("EVSA store"); if (baGuid == NVRAM_PHOENIX_FLASH_MAP_SELF_GUID) return UString("Flash map"); + if (baGuid == ZERO_GUID) return UString(); return UString("Unknown"); } diff --git a/common/nvram.h b/common/nvram.h index 598aa47..c162435 100755 --- a/common/nvram.h +++ b/common/nvram.h @@ -332,7 +332,7 @@ extern const UByteArray NVRAM_PHOENIX_FLASH_MAP_SIGNATURE; typedef struct PHOENIX_FLASH_MAP_HEADER_ { UINT8 Signature[10]; // _FLASH_MAP signature UINT16 NumEntries; // Number of entries in the map - UINT32 : 32; // Reserved field + UINT32 Reserved; // Reserved field } PHOENIX_FLASH_MAP_HEADER; typedef struct PHOENIX_FLASH_MAP_ENTRY_ { @@ -343,9 +343,9 @@ typedef struct PHOENIX_FLASH_MAP_ENTRY_ { UINT32 Size; UINT32 Offset; } PHOENIX_FLASH_MAP_ENTRY; - -#define NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_VOLUME 0x0000 -#define NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_DATA_BLOCK 0x0001 +#define NVRAM_PHOENIX_FLASH_MAP_TOTAL_SIZE 0x1000 +#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); @@ -416,6 +416,9 @@ typedef struct PHOENIX_CMDB_HEADER_ { #define NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE 0x42444D43 #define NVRAM_PHOENIX_CMDB_SIZE 0x100; +// Zero GUID +extern const UByteArray ZERO_GUID; + // Restore previous packing rules #pragma pack(pop) diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index cb1369b..ab48b9d 100644 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -31,6 +31,7 @@ #include "generated/edk2_vss2.h" #include "generated/edk2_ftw.h" #include "generated/insyde_fdc.h" +#include "generated/phoenix_flm.h" USTATUS NvramParser::parseNvarStore(const UModelIndex & index) { @@ -44,6 +45,14 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) if (nvar.isEmpty()) return U_SUCCESS; + // Obtain required fields from parsing data + UINT8 emptyByte = 0xFF; + if (model->hasEmptyParsingData(index) == false) { + UByteArray data = model->parsingData(index); + const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); + emptyByte = pdata->emptyByte; + } + try { const UINT32 localOffset = (UINT32)model->header(index).size(); umemstream is(nvar.constData(), nvar.size()); @@ -73,7 +82,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Get info UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); - if ((UINT32)padding.count('\'xFF') == unparsedSize) { // Free space + if ((UINT32)padding.count(emptyByte) == unparsedSize) { // Free space // Add tree item model->addItem(localOffset + entry->offset(), Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } @@ -106,7 +115,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Set default next to predefined last value NVAR_ENTRY_PARSING_DATA pdata = {}; - pdata.emptyByte = 0xFF; + pdata.emptyByte = emptyByte; pdata.next = 0xFFFFFF; pdata.isValid = TRUE; @@ -313,6 +322,9 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 for (UINT32 storeOffset = 0; storeOffset < volumeBodySize; storeOffset++) { + UString name, text, info; + UByteArray header, body; + // VSS try { if (volumeBodySize - storeOffset < sizeof(VSS_VARIABLE_STORE_HEADER)) { @@ -347,11 +359,10 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } // Construct header and body - UByteArray header = vss.left(parsed.len_vss_store_header()); - UByteArray body = vss.mid(header.size(), storeSize - header.size()); + header = vss.left(parsed.len_vss_store_header()); + body = vss.mid(header.size(), storeSize - header.size()); // Add info - UString name; if (parsed.signature() == NVRAM_APPLE_SVS_STORE_SIGNATURE) { name = UString("SVS store"); } @@ -361,7 +372,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 else { name = UString("VSS store"); } - UString info = usprintf("Signature: %Xh (", parsed.signature()) + fourCC(parsed.signature()) + UString(")\n"); + info = usprintf("Signature: %Xh (", parsed.signature()) + fourCC(parsed.signature()) + UString(")\n"); info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nReserved: %02Xh\nReserved1: %04Xh", storeSize , storeSize, @@ -379,7 +390,6 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 UINT32 vssVariableOffset = storeOffset + parsed.len_vss_store_header(); for (const auto & variable : *parsed.body()->variables()) { UINT8 subtype; - UString text; // This is the terminating entry, needs special processing if (variable->_is_null_signature_last()) { @@ -529,18 +539,17 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 // VSS2 store at current offset parsed correctly // Check if we need to add a padding before it if (!outerPadding.isEmpty()) { - UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size()); + 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 - UByteArray header = vss2.left(parsed.len_vss2_store_header()); - UByteArray body = vss2.mid(header.size(), storeSize - header.size()); + header = vss2.left(parsed.len_vss2_store_header()); + body = vss2.mid(header.size(), storeSize - header.size()); // Add info - UString name = UString("VSS2 store"); - UString info; + name = UString("VSS2 store"); if (parsed.signature() == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1) { info = UString("Signature: AAF32C78-947B-439A-A180-2E144EC37792\n"); } @@ -567,7 +576,6 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 UINT32 vss2VariableOffset = storeOffset + parsed.len_vss2_store_header(); for (const auto & variable : *parsed.body()->variables()) { UINT8 subtype; - UString text; // This is the terminating entry, needs special processing if (variable->_is_null_signature_last()) { @@ -662,6 +670,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 if (fdcStoreSizeOverride != 0) { continue; } + // FTW try { if (volumeBodySize - storeOffset < sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32)) { @@ -676,7 +685,6 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 UINT64 storeSize; UINT64 headerSize; UINT32 calculatedCrc; - UByteArray header; if (parsed._is_null_len_write_queue_64()) { headerSize = parsed.len_ftw_store_header_32(); storeSize = headerSize + parsed.len_write_queue_32(); @@ -711,12 +719,12 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } // Construct header and body - UByteArray body = ftw.mid(header.size(), storeSize - header.size()); + body = ftw.mid(header.size(), storeSize - header.size()); // Add info const EFI_GUID* guid = (const EFI_GUID*)header.constData(); - UString name = UString("FTW store"); - UString info = UString("Signature: ") + guidToUString(*guid, false); + name = UString("FTW store"); + info = UString("Signature: ") + guidToUString(*guid, false); info += usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh", (UINT32)storeSize, (UINT32)storeSize, (UINT32)header.size(), (UINT32)header.size(), @@ -733,6 +741,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } catch (...) { // Parsing failed, try something else } + // Insyde FDC try { if (volumeBodySize - storeOffset < sizeof(FDC_VOLUME_HEADER)) { @@ -755,12 +764,12 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 } // Construct header and body - UByteArray header = fdc.left(parsed.len_fdc_store_header()); - UByteArray body = fdc.mid(header.size(),storeSize - header.size()); + header = fdc.left(parsed.len_fdc_store_header()); + body = fdc.mid(header.size(),storeSize - header.size()); // Add info - UString name = UString("FDC store"); - UString info = usprintf("Signature: _FDC\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", + name = UString("FDC store"); + info = usprintf("Signature: _FDC\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", storeSize, storeSize, (UINT32)header.size(), (UINT32)header.size(), (UINT32)body.size(), (UINT32)body.size()); @@ -794,21 +803,19 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 // Apple SysF store at current offset parsed correctly // Check if we need to add a padding before it if (!outerPadding.isEmpty()) { - UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size()); + 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 - UByteArray header = sysf.left(parsed.len_sysf_store_header()); - UByteArray body = sysf.mid(header.size(), storeSize - header.size()); + header = sysf.left(parsed.len_sysf_store_header()); + body = sysf.mid(header.size(), storeSize - header.size()); // Check store checksum UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)sysf.constData(), storeSize - sizeof(UINT32)); // Add info - UString name; - UString info; if (parsed.signature() == NVRAM_APPLE_SYSF_STORE_SIGNATURE) { name = UString("SysF store"); info = UString("Signature: Fsys\n"); @@ -841,6 +848,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 subtype = Subtypes::NormalSysFEntry; name = usprintf("%s", variable->name().c_str()); } + if (variable->len_name() == 3 && variable->name() == "EOF") { header = volumeBody.mid(sysfVariableOffset, 4); } @@ -886,10 +894,113 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index,const UINT32 // Parsing failed, try something else } - // Phoenix EVSA // Phoenix FlashMap + try { + if (volumeBodySize - storeOffset < NVRAM_PHOENIX_FLASH_MAP_TOTAL_SIZE) { + // No need to parse further, the rest of the volume is too small + throw 0; + } + + UByteArray flm = volumeBody.mid(storeOffset); + umemstream is(flm.constData(), flm.size()); + kaitai::kstream ks(&is); + phoenix_flm_t parsed(&ks); + UINT32 storeSize = parsed.len_flm_store(); + + // Phoenix FlashMap 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 = flm.left(parsed.len_flm_store_header()); + body = flm.mid(header.size(), storeSize - header.size()); + + // Add info + name = UString("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(), + (UINT32)body.size(), (UINT32)body.size(), + parsed.num_entries(), + parsed.reserved()); + + // Add header tree item + UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::FlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); + + // Add entries + UINT32 entryOffset = storeOffset + parsed.len_flm_store_header(); + for (const auto & entry : *parsed.entries()) { + UINT8 subtype; + + if (entry->data_type() == NVRAM_PHOENIX_FLASH_MAP_ENTRY_DATA_TYPE_VOLUME) { + subtype = Subtypes::VolumeFlashMapEntry; + } + else if (entry->data_type() == NVRAM_PHOENIX_FLASH_MAP_ENTRY_DATA_TYPE_DATA_BLOCK) { + subtype = Subtypes::DataFlashMapEntry; + } + else { + subtype = Subtypes::UnknownFlashMapEntry; + } + + 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()); + + // Add info + UINT32 entrySize = (UINT32)header.size(); + info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\nData type: %04Xh\nEntry type: %04Xh\nSize: %08Xh\nOffset: %08Xh\nPhysical address: %" PRIX64 "h", + entrySize, entrySize, + (UINT32)header.size(), (UINT32)header.size(), + entry->data_type(), + entry->entry_type(), + entry->size(), + entry->offset(), + entry->physical_address()); + + // Add tree item + model->addItem(entryOffset, Types::FlashMapEntry, subtype, name, text, info, header, UByteArray(), UByteArray(), Fixed, headerIndex); + + entryOffset += entrySize; + } + + // Add free space, if needed + UByteArray freeSpace; + for (const auto & byte : *parsed.free_space()) { + freeSpace += (const char)byte; + } + if (freeSpace.size() > 0) { + // Add info + info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); + + // Check that remaining unparsed bytes are actually zeroes + 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); + } + } + + storeOffset += storeSize - 1; + previousStoreEndOffset = storeOffset + 1; + continue; + } catch (...) { + // Parsing failed, try something else + } + + // Phoenix EVSA + // Phoenix CMDB + // Phoenix SLIC Pubkey/Marker + // Intel uCode // Padding diff --git a/common/types.cpp b/common/types.cpp index 9b51628..8762fcd 100755 --- a/common/types.cpp +++ b/common/types.cpp @@ -142,6 +142,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) case Types::FlashMapEntry: if (subtype == Subtypes::VolumeFlashMapEntry) return UString("Volume"); else if (subtype == Subtypes::DataFlashMapEntry) return UString("Data"); + else if (subtype == Subtypes::UnknownFlashMapEntry) return UString("Unknown"); break; case Types::Microcode: if (subtype == Subtypes::IntelMicrocode) return UString("Intel"); diff --git a/common/types.h b/common/types.h index fde5e11..2f0b062 100755 --- a/common/types.h +++ b/common/types.h @@ -154,6 +154,7 @@ namespace Subtypes { enum FlashMapEntrySubtypes { VolumeFlashMapEntry = 170, DataFlashMapEntry, + UnknownFlashMapEntry, }; enum MicrocodeSubtypes { diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 2fba14c..2b70347 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -37,6 +37,7 @@ SET(PROJECT_SOURCES ../common/generated/edk2_vss2.cpp ../common/generated/edk2_ftw.cpp ../common/generated/insyde_fdc.cpp + ../common/generated/phoenix_flm.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp ../common/generated/intel_keym_v1.cpp