From 318fdb7fa188a81db36939164f4e94190bc761a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 19 Feb 2023 18:47:19 -0800 Subject: [PATCH] Start rewriting other NVRAM parsers in KaitaiStruct --- UEFITool/CMakeLists.txt | 1 + common/ffsparser.cpp | 2 +- common/generated/edk2_vss.cpp | 234 +++++ common/generated/edk2_vss.h | 225 +++++ common/ksy/edk2_vss.ksy | 100 +++ common/nvramparser.cpp | 1561 +-------------------------------- common/nvramparser.h | 21 - 7 files changed, 590 insertions(+), 1554 deletions(-) create mode 100644 common/generated/edk2_vss.cpp create mode 100644 common/generated/edk2_vss.h create mode 100644 common/ksy/edk2_vss.ksy diff --git a/UEFITool/CMakeLists.txt b/UEFITool/CMakeLists.txt index 8df2aa3..43b955b 100644 --- a/UEFITool/CMakeLists.txt +++ b/UEFITool/CMakeLists.txt @@ -71,6 +71,7 @@ SET(PROJECT_SOURCES ../common/digest/sha512.c ../common/digest/sm3.c ../common/generated/ami_nvar.cpp + ../common/generated/edk2_vss.cpp ../common/generated/intel_acbp_v1.cpp ../common/generated/intel_acbp_v2.cpp ../common/generated/intel_keym_v1.cpp diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 6701926..a778874 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -1428,7 +1428,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index) UByteArray volumeBody = model->body(index); UINT32 volumeHeaderSize = (UINT32)model->header(index).size(); - // Parse VSS NVRAM volumes with a dedicated function + // Parse NVRAM volumes with a dedicated function if (model->subtype(index) == Subtypes::NvramVolume) { return nvramParser->parseNvramVolumeBody(index); } diff --git a/common/generated/edk2_vss.cpp b/common/generated/edk2_vss.cpp new file mode 100644 index 0000000..87cebc4 --- /dev/null +++ b/common/generated/edk2_vss.cpp @@ -0,0 +1,234 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "edk2_vss.h" +#include "../kaitai/exceptions.h" + +edk2_vss_t::edk2_vss_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, edk2_vss_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; (void)p__root; + m_body = 0; + m__io__raw_body = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void edk2_vss_t::_read() { + m_signature = m__io->read_u4le(); + { + uint32_t _ = signature(); + if (!( ((_ == 1397970468) || (_ == 1398166308) || (_ == 1397968420)) )) { + throw kaitai::validation_expr_error(signature(), _io(), std::string("/seq/0")); + } + } + m_size = m__io->read_u4le(); + { + uint32_t _ = size(); + if (!(_ > (4 * 4))) { + throw kaitai::validation_expr_error(size(), _io(), std::string("/seq/1")); + } + } + m_format = m__io->read_u1(); + { + uint8_t _ = format(); + if (!(_ == 90)) { + throw kaitai::validation_expr_error(format(), _io(), std::string("/seq/2")); + } + } + m_state = m__io->read_u1(); + m_reserved = m__io->read_u2le(); + m_reserved1 = m__io->read_u4le(); + m__raw_body = m__io->read_bytes((size() - (4 * 4))); + m__io__raw_body = new kaitai::kstream(m__raw_body); + m_body = new vss_store_body_t(m__io__raw_body, this, m__root); +} + +edk2_vss_t::~edk2_vss_t() { + _clean_up(); +} + +void edk2_vss_t::_clean_up() { + if (m__io__raw_body) { + delete m__io__raw_body; m__io__raw_body = 0; + } + if (m_body) { + delete m_body; m_body = 0; + } +} + +edk2_vss_t::vss_store_body_t::vss_store_body_t(kaitai::kstream* p__io, edk2_vss_t* p__parent, edk2_vss_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_variables = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void edk2_vss_t::vss_store_body_t::_read() { + m_variables = new std::vector(); + { + int i = 0; + vss_variable_t* _; + do { + _ = new vss_variable_t(m__io, this, m__root); + m_variables->push_back(_); + i++; + } while (!( ((_->signature_first() != 170) || (_io()->is_eof())) )); + } +} + +edk2_vss_t::vss_store_body_t::~vss_store_body_t() { + _clean_up(); +} + +void edk2_vss_t::vss_store_body_t::_clean_up() { + if (m_variables) { + for (std::vector::iterator it = m_variables->begin(); it != m_variables->end(); ++it) { + delete *it; + } + delete m_variables; m_variables = 0; + } +} + +edk2_vss_t::vss_variable_attributes_t::vss_variable_attributes_t(kaitai::kstream* p__io, edk2_vss_t::vss_variable_t* p__parent, edk2_vss_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void edk2_vss_t::vss_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(24); + m_apple_data_checksum = m__io->read_bits_int_le(1); +} + +edk2_vss_t::vss_variable_attributes_t::~vss_variable_attributes_t() { + _clean_up(); +} + +void edk2_vss_t::vss_variable_attributes_t::_clean_up() { +} + +edk2_vss_t::vss_variable_t::vss_variable_t(kaitai::kstream* p__io, edk2_vss_t::vss_store_body_t* p__parent, edk2_vss_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_attributes = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void edk2_vss_t::vss_variable_t::_read() { + m_signature_first = m__io->read_u1(); + n_signature_last = true; + if (signature_first() == 170) { + n_signature_last = false; + m_signature_last = m__io->read_u1(); + { + uint8_t _ = signature_last(); + if (!(_ == 85)) { + throw kaitai::validation_expr_error(signature_last(), _io(), std::string("/types/vss_variable/seq/1")); + } + } + } + n_state = true; + if (signature_first() == 170) { + n_state = false; + m_state = m__io->read_u1(); + } + n_reserved = true; + if (signature_first() == 170) { + n_reserved = false; + m_reserved = m__io->read_u1(); + } + n_attributes = true; + if (signature_first() == 170) { + n_attributes = false; + m_attributes = new vss_variable_attributes_t(m__io, this, m__root); + } + n_len_name = true; + if (signature_first() == 170) { + n_len_name = false; + m_len_name = m__io->read_u4le(); + } + n_len_data = true; + if (signature_first() == 170) { + n_len_data = false; + m_len_data = m__io->read_u4le(); + } + n_vendor_guid = true; + if (signature_first() == 170) { + n_vendor_guid = false; + m_vendor_guid = m__io->read_bytes(16); + } + n_apple_data_crc32 = true; + if ( ((signature_first() == 170) && (attributes()->apple_data_checksum())) ) { + n_apple_data_crc32 = false; + m_apple_data_crc32 = m__io->read_u4le(); + } + n_name = true; + if (signature_first() == 170) { + n_name = false; + m_name = m__io->read_bytes(len_name()); + } + n_data = true; + if (signature_first() == 170) { + n_data = false; + m_data = m__io->read_bytes(len_data()); + } +} + +edk2_vss_t::vss_variable_t::~vss_variable_t() { + _clean_up(); +} + +void edk2_vss_t::vss_variable_t::_clean_up() { + if (!n_signature_last) { + } + if (!n_state) { + } + if (!n_reserved) { + } + if (!n_attributes) { + if (m_attributes) { + delete m_attributes; m_attributes = 0; + } + } + if (!n_len_name) { + } + if (!n_len_data) { + } + if (!n_vendor_guid) { + } + if (!n_apple_data_crc32) { + } + if (!n_name) { + } + if (!n_data) { + } +} diff --git a/common/generated/edk2_vss.h b/common/generated/edk2_vss.h new file mode 100644 index 0000000..f893fb2 --- /dev/null +++ b/common/generated/edk2_vss.h @@ -0,0 +1,225 @@ +#ifndef EDK2_VSS_H_ +#define EDK2_VSS_H_ + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "../kaitai/kaitaistruct.h" +#include +#include + +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" +#endif + +class edk2_vss_t : public kaitai::kstruct { + +public: + class vss_store_body_t; + class vss_variable_attributes_t; + class vss_variable_t; + + edk2_vss_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, edk2_vss_t* p__root = 0); + +private: + void _read(); + void _clean_up(); + +public: + ~edk2_vss_t(); + + class vss_store_body_t : public kaitai::kstruct { + + public: + + vss_store_body_t(kaitai::kstream* p__io, edk2_vss_t* p__parent = 0, edk2_vss_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~vss_store_body_t(); + + private: + std::vector* m_variables; + edk2_vss_t* m__root; + edk2_vss_t* m__parent; + + public: + std::vector* variables() const { return m_variables; } + edk2_vss_t* _root() const { return m__root; } + edk2_vss_t* _parent() const { return m__parent; } + }; + + class vss_variable_attributes_t : public kaitai::kstruct { + + public: + + vss_variable_attributes_t(kaitai::kstream* p__io, edk2_vss_t::vss_variable_t* p__parent = 0, edk2_vss_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~vss_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_apple_data_checksum; + edk2_vss_t* m__root; + edk2_vss_t::vss_variable_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 apple_data_checksum() const { return m_apple_data_checksum; } + edk2_vss_t* _root() const { return m__root; } + edk2_vss_t::vss_variable_t* _parent() const { return m__parent; } + }; + + class vss_variable_t : public kaitai::kstruct { + + public: + + vss_variable_t(kaitai::kstream* p__io, edk2_vss_t::vss_store_body_t* p__parent = 0, edk2_vss_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~vss_variable_t(); + + private: + uint8_t m_signature_first; + uint8_t m_signature_last; + bool n_signature_last; + + public: + bool _is_null_signature_last() { signature_last(); return n_signature_last; }; + + private: + uint8_t m_state; + bool n_state; + + public: + bool _is_null_state() { state(); return n_state; }; + + private: + uint8_t m_reserved; + bool n_reserved; + + public: + bool _is_null_reserved() { reserved(); return n_reserved; }; + + private: + vss_variable_attributes_t* m_attributes; + bool n_attributes; + + public: + bool _is_null_attributes() { attributes(); return n_attributes; }; + + private: + uint32_t m_len_name; + bool n_len_name; + + public: + bool _is_null_len_name() { len_name(); return n_len_name; }; + + private: + uint32_t m_len_data; + bool n_len_data; + + public: + bool _is_null_len_data() { len_data(); return n_len_data; }; + + private: + std::string m_vendor_guid; + bool n_vendor_guid; + + public: + bool _is_null_vendor_guid() { vendor_guid(); return n_vendor_guid; }; + + private: + uint32_t m_apple_data_crc32; + bool n_apple_data_crc32; + + public: + bool _is_null_apple_data_crc32() { apple_data_crc32(); return n_apple_data_crc32; }; + + private: + std::string m_name; + bool n_name; + + public: + bool _is_null_name() { name(); return n_name; }; + + private: + std::string m_data; + bool n_data; + + public: + bool _is_null_data() { data(); return n_data; }; + + private: + edk2_vss_t* m__root; + edk2_vss_t::vss_store_body_t* m__parent; + + public: + uint8_t signature_first() const { return m_signature_first; } + uint8_t signature_last() const { return m_signature_last; } + uint8_t state() const { return m_state; } + uint8_t reserved() const { return m_reserved; } + vss_variable_attributes_t* attributes() const { return m_attributes; } + uint32_t len_name() const { return m_len_name; } + uint32_t len_data() const { return m_len_data; } + std::string vendor_guid() const { return m_vendor_guid; } + uint32_t apple_data_crc32() const { return m_apple_data_crc32; } + std::string name() const { return m_name; } + std::string data() const { return m_data; } + edk2_vss_t* _root() const { return m__root; } + edk2_vss_t::vss_store_body_t* _parent() const { return m__parent; } + }; + +private: + uint32_t m_signature; + uint32_t m_size; + uint8_t m_format; + uint8_t m_state; + uint16_t m_reserved; + uint32_t m_reserved1; + vss_store_body_t* m_body; + edk2_vss_t* m__root; + kaitai::kstruct* m__parent; + std::string m__raw_body; + kaitai::kstream* m__io__raw_body; + +public: + uint32_t signature() const { return m_signature; } + uint32_t size() const { return m_size; } + uint8_t format() const { return m_format; } + uint8_t state() const { return m_state; } + uint16_t reserved() const { return m_reserved; } + uint32_t reserved1() const { return m_reserved1; } + vss_store_body_t* body() const { return m_body; } + edk2_vss_t* _root() const { return m__root; } + kaitai::kstruct* _parent() const { return m__parent; } + std::string _raw_body() const { return m__raw_body; } + kaitai::kstream* _io__raw_body() const { return m__io__raw_body; } +}; + +#endif // EDK2_VSS_H_ diff --git a/common/ksy/edk2_vss.ksy b/common/ksy/edk2_vss.ksy new file mode 100644 index 0000000..473fdde --- /dev/null +++ b/common/ksy/edk2_vss.ksy @@ -0,0 +1,100 @@ +meta: + id: edk2_vss + title: EDK2 VSS storage + application: EDK2-based UEFI firmware + file-extension: vss + tags: + - firmware + license: CC0-1.0 + ks-version: 0.9 + endian: le + +seq: +- id: signature + type: u4 + valid: + expr: _ == 0x53535624 or _ == 0x53565324 or _ == 0x53534E24 # $VSS/$SVS/$NSS +- id: size + type: u4 + valid: + expr: _ > 4 * sizeof +- id: format + type: u1 + valid: + expr: _ == 0x5a # Formatted +- id: state + type: u1 +- id: reserved + type: u2 +- id: reserved1 + type: u4 +- id: body + type: vss_store_body + size: size - 4 * sizeof + +types: + vss_store_body: + seq: + - id: variables + type: vss_variable + repeat: until + repeat-until: _.signature_first != 0xAA or _io.eof + + vss_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: b24le + - id: apple_data_checksum + type: b1le + + vss_variable: + seq: + - id: signature_first + type: u1 + - id: signature_last + type: u1 + valid: + expr: _ == 0x55 + if: signature_first == 0xAA + - id: state + type: u1 + if: signature_first == 0xAA + - id: reserved + type: u1 + if: signature_first == 0xAA + - id: attributes + type: vss_variable_attributes + if: signature_first == 0xAA + #TODO: add Intel legacy total_size variant + - id: len_name + type: u4 + if: signature_first == 0xAA + - id: len_data + type: u4 + if: signature_first == 0xAA + - id: vendor_guid + size: 16 + if: signature_first == 0xAA + - id: apple_data_crc32 + type: u4 + if: signature_first == 0xAA and attributes.apple_data_checksum + - id: name + size: len_name + if: signature_first == 0xAA + - id: data + size: len_data + if: signature_first == 0xAA diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index 2b7fbee..229fb57 100755 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -26,6 +26,7 @@ #include "umemstream.h" #include "kaitai/kaitaistream.h" #include "generated/ami_nvar.h" +#include "generated/edk2_vss.h" USTATUS NvramParser::parseNvarStore(const UModelIndex & index) { @@ -296,1548 +297,44 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) } // Get local offset - UINT32 localOffset = (UINT32)model->header(index).size(); + const UINT32 localOffset = (UINT32)model->header(index).size(); // Get item data - UByteArray data = model->body(index); - - // Search for first store - USTATUS result; - UINT32 prevStoreOffset; - result = findNextStore(index, data, localOffset, 0, prevStoreOffset); - if (result) - return result; - - // First store is not at the beginning of volume body - UString name; - UString info; - if (prevStoreOffset > 0) { - // Get info - UByteArray padding = data.left(prevStoreOffset); - name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); - - // Add tree item - model->addItem(localOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - } - - // Search for and parse all stores - UINT32 storeOffset = prevStoreOffset; - UINT32 prevStoreSize = 0; - - while (!result) { - // Padding between stores - if (storeOffset > prevStoreOffset + prevStoreSize) { - UINT32 paddingOffset = prevStoreOffset + prevStoreSize; - UINT32 paddingSize = storeOffset - paddingOffset; - UByteArray padding = data.mid(paddingOffset, paddingSize); - - // Get info - name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); - - // Add tree item - model->addItem(localOffset + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - } - - // Get store size - UINT32 storeSize = 0; - result = getStoreSize(data, storeOffset, storeSize); - if (result) { - msg(usprintf("%s: getStoreSize failed with error ", __FUNCTION__) + errorCodeToUString(result), index); - return result; - } - - // Check that current store is fully present in input - if (storeSize > (UINT32)data.size() || storeOffset + storeSize > (UINT32)data.size()) { - // Mark the rest as padding and finish parsing - UByteArray padding = data.mid(storeOffset); - - // Get info - name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); - - // Add tree item - UModelIndex paddingIndex = model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - msg(usprintf("%s: one of stores inside overlaps the end of data", __FUNCTION__), paddingIndex); - - // Update variables - prevStoreOffset = storeOffset; - prevStoreSize = (UINT32)padding.size(); - break; - } - - // Parse current store header - UModelIndex storeIndex; - UByteArray store = data.mid(storeOffset, storeSize); - result = parseStoreHeader(store, localOffset + storeOffset, index, storeIndex); - if (result) - msg(usprintf("%s: store header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index); - - // Go to next store - prevStoreOffset = storeOffset; - prevStoreSize = storeSize; - result = findNextStore(index, data, localOffset, storeOffset + prevStoreSize, storeOffset); - } - - // Padding/free space at the end - storeOffset = prevStoreOffset + prevStoreSize; - if ((UINT32)data.size() > storeOffset) { - UByteArray padding = data.mid(storeOffset); - // Add info - info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); - - if (padding.count(emptyByte) == padding.size()) { // Free space - // Add tree item - model->addItem(localOffset + storeOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - } - else { - // Nothing is parsed yet, but the file is not empty - if (!storeOffset) { - msg(usprintf("%s: can't be parsed as NVRAM volume", __FUNCTION__), index); - return U_SUCCESS; - } - - // Add tree item - model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - } - } - - // Parse bodies - for (int i = 0; i < model->rowCount(index); i++) { - UModelIndex current = index.model()->index(i, 0, index); - - switch (model->type(current)) { - case Types::FdcStore: - parseFdcStoreBody(current); - break; - case Types::VssStore: - parseVssStoreBody(current, 0); - break; - case Types::Vss2Store: - parseVssStoreBody(current, 4); - break; - case Types::FsysStore: - parseFsysStoreBody(current); - break; - case Types::EvsaStore: - parseEvsaStoreBody(current); - break; - case Types::FlashMapStore: - parseFlashMapBody(current); - break; - default: - // Ignore unknown! - break; - } - } - - return U_SUCCESS; -} + UByteArray volumeBody = model->body(index); + const UINT32 volumeBodySize = (UINT32)volumeBody.size(); -USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & volume, const UINT32 localOffset, const UINT32 storeOffset, UINT32 & nextStoreOffset) -{ - UINT32 dataSize = (UINT32)volume.size(); - - if (dataSize < sizeof(UINT32)) - return U_STORES_NOT_FOUND; - - // TODO: add checks for restSize - // TODO: remove misaligned access by doing the signature checks differently, the current way is UB is C++ - // TODO: rewrite this all as Kaitai-based parser - UINT32 offset = storeOffset; - for (; offset < dataSize - sizeof(UINT32); offset++) { - const UINT32* currentPos = (const UINT32*)(volume.constData() + offset); - if (readUnaligned(currentPos) == NVRAM_VSS_STORE_SIGNATURE - || readUnaligned(currentPos) == NVRAM_APPLE_SVS_STORE_SIGNATURE - || readUnaligned(currentPos) == NVRAM_APPLE_NSS_STORE_SIGNATURE) { // $VSS, $SVS or $NSS signatures found, perform checks - const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)currentPos; - if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) { - msg(usprintf("%s: VSS store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index); - continue; - } - if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) { - msg(usprintf("%s: VSS store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, vssHeader->Size), index); - continue; - } - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 - || readUnaligned(currentPos) == NVRAM_VSS2_STORE_GUID_PART1) { // VSS2 store signatures found, perform checks - UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); - if (guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID && guid != NVRAM_VSS2_STORE_GUID) // Check the whole signature - continue; - - const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)currentPos; - if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) { - msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index); - continue; - } - if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) { - msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, vssHeader->Size), index); - continue; - } - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == NVRAM_FDC_VOLUME_SIGNATURE) { // FDC signature found - const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)currentPos; - if (fdcHeader->Size == 0 || fdcHeader->Size == 0xFFFFFFFF) { - msg(usprintf("%s: FDC store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, fdcHeader->Size), index); - continue; - } - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == NVRAM_APPLE_FSYS_STORE_SIGNATURE - || readUnaligned(currentPos) == NVRAM_APPLE_GAID_STORE_SIGNATURE) { // Fsys or Gaid signature found - const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)currentPos; - if (fsysHeader->Size == 0 || fsysHeader->Size == 0xFFFF) { - msg(usprintf("%s: Fsys store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, fsysHeader->Size), index); - continue; - } - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found - if (offset < sizeof(UINT32)) - continue; - - const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)(currentPos - 1); - if (evsaHeader->Header.Type != NVRAM_EVSA_ENTRY_TYPE_STORE) { - msg(usprintf("%s: EVSA store candidate at offset %Xh skipped, has invalid type %02Xh", __FUNCTION__, localOffset + offset - 4, evsaHeader->Header.Type), index); - continue; - } - if (evsaHeader->StoreSize == 0 || evsaHeader->StoreSize == 0xFFFFFFFF) { - msg(usprintf("%s: EVSA store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, evsaHeader->StoreSize), index); - continue; - } - // All checks passed, store found - offset -= sizeof(UINT32); - break; - } - else if (readUnaligned(currentPos) == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 - || readUnaligned(currentPos) == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { // Possible FTW block signature found - UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); - if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != VSS2_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature - continue; - - // Detect header variant based on WriteQueueSize - const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftwHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)currentPos; - if (ftwHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize - if (ftwHeader->WriteQueueSize == 0 || ftwHeader->WriteQueueSize == 0xFFFFFFFF) { - msg(usprintf("%s: FTW block candidate at offset %Xh skipped, has invalid body size %Xh", __FUNCTION__, localOffset + offset, ftwHeader->WriteQueueSize), index); - continue; - } - } - else if (ftwHeader->WriteQueueSize % 0x10 == 0x00) { // Header with 64 bit WriteQueueSize - const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64Header = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)currentPos; - if (ftw64Header->WriteQueueSize == 0 || ftw64Header->WriteQueueSize >= 0xFFFFFFFF) { - msg(usprintf("%s: FTW block candidate at offset %Xh skipped, has invalid body size %" PRIX64 "h", __FUNCTION__, localOffset + offset, ftw64Header->WriteQueueSize), index); - continue; - } - } - else // Unknown header - continue; - - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) {// Phoenix SCT flash map - UByteArray signature = UByteArray(volume.constData() + offset, NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_LENGTH); - if (signature != NVRAM_PHOENIX_FLASH_MAP_SIGNATURE) // Check the whole signature - continue; - - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store - const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)currentPos; - - // Check size - if (cmdbHeader->HeaderSize != sizeof(PHOENIX_CMDB_HEADER)) - continue; - - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode - const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos; - - // TotalSize is greater then DataSize and is multiple of 1024 - if (FALSE == ffsParser->microcodeHeaderValid(ucodeHeader)) { - continue; - } - - // All checks passed, store found - break; - } - else if (readUnaligned(currentPos) == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey - if (offset < 4 * sizeof(UINT32)) - continue; - - const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)(currentPos - 4); - // Check type - if (pubkeyHeader->Type != OEM_ACTIVATION_PUBKEY_TYPE) - continue; - - // All checks passed, store found - offset -= 4 * sizeof(UINT32); - break; - } - else if (readUnaligned(currentPos) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG_PART1) { // SLIC marker - if (offset < 26 - || offset >= dataSize - sizeof(UINT64) - || *(const UINT64*)currentPos != OEM_ACTIVATION_MARKER_WINDOWS_FLAG) // Check full windows flag and structure size - continue; - - const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)(volume.constData() + offset - 26); - // Check reserved bytes - bool reservedBytesValid = true; - for (UINT32 i = 0; i < sizeof(markerHeader->Reserved); i++) - if (markerHeader->Reserved[i] != OEM_ACTIVATION_MARKER_RESERVED_BYTE) { - reservedBytesValid = false; - break; - } - if (!reservedBytesValid) - continue; - - // All checks passed, store found - offset -= 26; - break; - } - } - // No more stores found - if (offset >= dataSize - sizeof(UINT32)) - return U_STORES_NOT_FOUND; - - nextStoreOffset = offset; - - return U_SUCCESS; -} + // Iterate over all bytes inside the volume body, trying to parse every next byte offset by one of the known parsers + UByteArray padding; + for (UINT32 offset = 0; + offset < volumeBodySize; + offset++) { + bool storeFound = false; + // Try parsing as VSS store + try { + UByteArray vss = volumeBody.mid(offset); + umemstream is(vss.constData(), vss.size()); + kaitai::kstream ks(&is); + edk2_vss_t parsed(&ks); -USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOffset, UINT32 & storeSize) -{ - const UINT32* signature = (const UINT32*)(data.constData() + storeOffset); - if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE || *signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) { - const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature; - storeSize = vssHeader->Size; - } - else if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1) { - const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)signature; - storeSize = vssHeader->Size; - } - else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) { - const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)signature; - storeSize = fdcHeader->Size; - } - else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) { - const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)signature; - storeSize = fsysHeader->Size; - } - else if (*(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE) { - const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)signature; - storeSize = evsaHeader->StoreSize; - } - else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { - const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftwHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)signature; - if (ftwHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize - storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) + ftwHeader->WriteQueueSize; - } - else { // Header with 64 bit WriteQueueSize - const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64Header = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)signature; - storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + (UINT32)ftw64Header->WriteQueueSize; - } - } - else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) { // Phoenix SCT flash map - const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)signature; - storeSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + sizeof(PHOENIX_FLASH_MAP_ENTRY) * flashMapHeader->NumEntries; - } - else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store - storeSize = NVRAM_PHOENIX_CMDB_SIZE; // It's a predefined max size, no need to calculate - } - else if (*(signature + 4) == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey - const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)signature; - storeSize = pubkeyHeader->Size; - } - else if (*(const UINT64*)(data.constData() + storeOffset + 26) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG) { // SLIC marker - const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)signature; - storeSize = markerHeader->Size; - } - else if (*signature == INTEL_MICROCODE_HEADER_VERSION_1) { // Intel microcode, must be checked after SLIC marker because of the same *signature values - const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)signature; - storeSize = ucodeHeader->TotalSize; - } else { - return U_INVALID_PARAMETER; // Unreachable - } - return U_SUCCESS; -} + // VSS store at current offset parsed correctly + msg(usprintf("%s: VSS store found at offset: %Xh, paddingSize: %Xh", __FUNCTION__, localOffset + offset, (UINT32)padding.size()), index); -USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check store size - if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) { - msg(usprintf("%s: volume body is too small even for VSS store header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get VSS store header - const VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS_VARIABLE_STORE_HEADER*)store.constData(); - - // Check for size override - UINT32 storeSize = vssStoreHeader->Size; - if (sizeOverride) { - storeSize = dataSize; - } - - // Check store size - if (dataSize < storeSize) { - msg(usprintf("%s: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - storeSize, storeSize, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(VSS_VARIABLE_STORE_HEADER)); - UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS_VARIABLE_STORE_HEADER)); - - // Add info - UString name; - if (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) { - name = UString("SVS store"); - } - else if (vssStoreHeader->Signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) { - name = UString("NSS store"); - } - else { - name = UString("VSS store"); - } - - UString info = usprintf("Signature: %Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", - vssStoreHeader->Signature, - storeSize, storeSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - vssStoreHeader->Format, - vssStoreHeader->State, - vssStoreHeader->Unknown); - - // Add tree item - index = model->addItem(localOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} + storeFound = true; + padding.clear(); -USTATUS NvramParser::parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check store size - if (dataSize < sizeof(VSS2_VARIABLE_STORE_HEADER)) { - msg(usprintf("%s: volume body is too small even for VSS2 store header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get VSS2 store header - const VSS2_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS2_VARIABLE_STORE_HEADER*)store.constData(); - - // Check for size override - UINT32 storeSize = vssStoreHeader->Size; - if (sizeOverride) { - storeSize = dataSize; - } - - // Check store size - if (dataSize < storeSize) { - msg(usprintf("%s: VSS2 store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - storeSize, storeSize, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(VSS2_VARIABLE_STORE_HEADER)); - UByteArray body = store.mid(sizeof(VSS2_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS2_VARIABLE_STORE_HEADER)); - - // Add info - UString name = UString("VSS2 store"); - UString info = UString("Signature: ") + guidToUString(vssStoreHeader->Signature, false) + - usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", - storeSize, storeSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - vssStoreHeader->Format, - vssStoreHeader->State, - vssStoreHeader->Unknown); - - // Add tree item - index = model->addItem(localOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} + offset += parsed.size() - 1; + } catch (...) { + // Parsing failed try something else + } -USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check store size - if (dataSize < sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64)) { - msg(usprintf("%s: volume body is too small even for FTW store header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Obtain required information from parent volume - UINT8 emptyByte = 0xFF; - UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); - if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) { - UByteArray data = model->parsingData(parentVolumeIndex); - const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); - emptyByte = pdata->emptyByte; - } - - // Get FTW block headers - const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftw32BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)store.constData(); - const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)store.constData(); - - // Check store size - UINT32 ftwBlockSize; - bool has32bitHeader; - if (ftw32BlockHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize - ftwBlockSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) + ftw32BlockHeader->WriteQueueSize; - has32bitHeader = true; - } - else { // Header with 64 bit WriteQueueSize - ftwBlockSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + (UINT32)ftw64BlockHeader->WriteQueueSize; - has32bitHeader = false; - } - if (dataSize < ftwBlockSize) { - msg(usprintf("%s: FTW store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - ftwBlockSize, ftwBlockSize, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UINT32 headerSize = has32bitHeader ? sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) : sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64); - UByteArray header = store.left(headerSize); - UByteArray body = store.mid(headerSize, ftwBlockSize - headerSize); - - // Check block header checksum - UByteArray crcHeader = header; - EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)header.data(); - crcFtwBlockHeader->Crc = emptyByte ? 0xFFFFFFFF : 0; - crcFtwBlockHeader->State = emptyByte ? 0xFF : 0; - UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)crcFtwBlockHeader, headerSize); - - // Add info - UString name("FTW store"); - UString info = UString("Signature: ") + guidToUString(ftw32BlockHeader->Signature, false) + - usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh", - ftwBlockSize, ftwBlockSize, - headerSize, headerSize, - (UINT32)body.size(), (UINT32)body.size(), - ftw32BlockHeader->State, - ftw32BlockHeader->Crc) + - (ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); - - // Add tree item - index = model->addItem(localOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} + //TODO: all other kinds of stores + // if (!storeFound && ...) -USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check store size - if (dataSize < sizeof(FDC_VOLUME_HEADER)) { - msg(usprintf("%s: volume body is too small even for FDC store header", __FUNCTION__), parent); - return U_SUCCESS; + // This byte had not been parsed as anything + if (!storeFound) + padding += volumeBody.at(offset); } - - // Get Fdc store header - const FDC_VOLUME_HEADER* fdcStoreHeader = (const FDC_VOLUME_HEADER*)store.constData(); - - // Check store size - if (dataSize < fdcStoreHeader->Size) { - msg(usprintf("%s: FDC store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - fdcStoreHeader->Size, fdcStoreHeader->Size, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(FDC_VOLUME_HEADER)); - UByteArray body = store.mid(sizeof(FDC_VOLUME_HEADER), fdcStoreHeader->Size - sizeof(FDC_VOLUME_HEADER)); - - // Add info - UString name("FDC store"); - UString info = usprintf("Signature: _FDC\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - fdcStoreHeader->Size, fdcStoreHeader->Size, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size()); - - // Add tree item - index = model->addItem(localOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} -USTATUS NvramParser::parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check store size - if (dataSize < sizeof(APPLE_FSYS_STORE_HEADER)) { - msg(usprintf("%s: volume body is too small even for Fsys store header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get Fsys store header - const APPLE_FSYS_STORE_HEADER* fsysStoreHeader = (const APPLE_FSYS_STORE_HEADER*)store.constData(); - - // Check store size - if (dataSize < fsysStoreHeader->Size) { - msg(usprintf("%s: Fsys store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - fsysStoreHeader->Size, fsysStoreHeader->Size, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(APPLE_FSYS_STORE_HEADER)); - UByteArray body = store.mid(sizeof(APPLE_FSYS_STORE_HEADER), fsysStoreHeader->Size - sizeof(APPLE_FSYS_STORE_HEADER) - sizeof(UINT32)); - - // Check store checksum - UINT32 storedCrc = *(UINT32*)store.right(sizeof(UINT32)).constData(); - UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)store.constData(), (UINT32)store.size() - sizeof(UINT32)); - - // Add info - bool isGaidStore = (fsysStoreHeader->Signature == NVRAM_APPLE_GAID_STORE_SIGNATURE); - UString name = isGaidStore ? UString("Gaid store") : UString("Fsys store"); - UString info = usprintf("Signature: %s\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nUnknown0: %02Xh\nUnknown1: %08Xh\nCRC32: %08Xh", - isGaidStore ? "Gaid" : "Fsys", - fsysStoreHeader->Size, fsysStoreHeader->Size, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - fsysStoreHeader->Unknown0, - fsysStoreHeader->Unknown1, - storedCrc) - + (storedCrc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); - - // Add tree item - index = model->addItem(localOffset, Types::FsysStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} - -USTATUS NvramParser::parseEvsaStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check dataSize - if (dataSize < sizeof(EVSA_STORE_ENTRY)) { - msg(usprintf("%s: volume body is too small even for EVSA store header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get EVSA store header - const EVSA_STORE_ENTRY* evsaStoreHeader = (const EVSA_STORE_ENTRY*)store.constData(); - - // Check store size - if (dataSize < evsaStoreHeader->StoreSize) { - msg(usprintf("%s: EVSA store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(evsaStoreHeader->Header.Size); - UByteArray body = store.mid(evsaStoreHeader->Header.Size, evsaStoreHeader->StoreSize - evsaStoreHeader->Header.Size); - - // Recalculate checksum - UINT8 calculated = calculateChecksum8(((const UINT8*)evsaStoreHeader) + 2, evsaStoreHeader->Header.Size - 2); - - // Add info - UString name("EVSA store"); - UString info = usprintf("Signature: EVSA\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nAttributes: %08Xh\nChecksum: %02Xh", - evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - evsaStoreHeader->Header.Type, - evsaStoreHeader->Attributes, - evsaStoreHeader->Header.Checksum) + - (evsaStoreHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")); - - // Add tree item - index = model->addItem(localOffset, Types::EvsaStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} - -USTATUS NvramParser::parseFlashMapStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check data size - if (dataSize < sizeof(PHOENIX_FLASH_MAP_HEADER)) { - msg(usprintf("%s: volume body is too small even for FlashMap block header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get FlashMap block header - const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)store.constData(); - - // Check store size - UINT32 flashMapSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + flashMapHeader->NumEntries * sizeof(PHOENIX_FLASH_MAP_ENTRY); - if (dataSize < flashMapSize) { - msg(usprintf("%s: FlashMap block size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - flashMapSize, flashMapSize, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(PHOENIX_FLASH_MAP_HEADER)); - UByteArray body = store.mid(sizeof(PHOENIX_FLASH_MAP_HEADER), flashMapSize - sizeof(PHOENIX_FLASH_MAP_HEADER)); - - // Add info - UString name("Phoenix SCT flash map"); - UString info = usprintf("Signature: _FLASH_MAP\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u", - flashMapSize, flashMapSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - flashMapHeader->NumEntries); - - // Add tree item - index = model->addItem(localOffset, Types::FlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} - -USTATUS NvramParser::parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check store size - if (dataSize < sizeof(PHOENIX_CMDB_HEADER)) { - msg(usprintf("%s: volume body is too small even for CMDB store header", __FUNCTION__), parent); - return U_SUCCESS; - } - - UINT32 cmdbSize = NVRAM_PHOENIX_CMDB_SIZE; - if (dataSize < cmdbSize) { - msg(usprintf("%s: CMDB store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - cmdbSize, cmdbSize, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Get store header - const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)store.constData(); - - // Construct header and body - UByteArray header = store.left(cmdbHeader->TotalSize); - UByteArray body = store.mid(cmdbHeader->TotalSize, cmdbSize - cmdbHeader->TotalSize); - - // Add info - UString name("CMDB store"); - UString info = usprintf("Signature: CMDB\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - cmdbSize, cmdbSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size()); - - // Add tree item - index = model->addItem(localOffset, Types::CmdbStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - - return U_SUCCESS; -} - -USTATUS NvramParser::parseSlicPubkeyHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check data size - if (dataSize < sizeof(OEM_ACTIVATION_PUBKEY)) { - msg(usprintf("%s: volume body is too small even for SLIC pubkey header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get SLIC pubkey header - const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)store.constData(); - - // Check store size - if (dataSize < pubkeyHeader->Size) { - msg(usprintf("%s: SLIC pubkey size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - pubkeyHeader->Size, pubkeyHeader->Size, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(OEM_ACTIVATION_PUBKEY)); - - // Add info - UString name("SLIC pubkey"); - UString info = usprintf("Type: 0h\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\n" - "Key type: %02Xh\nVersion: %02Xh\nAlgorithm: %08Xh\nMagic: RSA1\nBit length: %08Xh\nExponent: %08Xh", - pubkeyHeader->Size, pubkeyHeader->Size, - (UINT32)header.size(), (UINT32)header.size(), - pubkeyHeader->KeyType, - pubkeyHeader->Version, - pubkeyHeader->Algorithm, - pubkeyHeader->BitLength, - pubkeyHeader->Exponent); - - // Add tree item - index = model->addItem(localOffset, Types::SlicData, Subtypes::PubkeySlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent); - - return U_SUCCESS; -} - -USTATUS NvramParser::parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - - // Check data size - if (dataSize < sizeof(OEM_ACTIVATION_MARKER)) { - msg(usprintf("%s: volume body is too small even for SLIC marker header", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Get SLIC marker header - const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)store.constData(); - - // Check store size - if (dataSize < markerHeader->Size) { - msg(usprintf("%s: SLIC marker size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - markerHeader->Size, markerHeader->Size, - dataSize, dataSize), parent); - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = store.left(sizeof(OEM_ACTIVATION_MARKER)); - - // Add info - UString name("SLIC marker"); - UString info = usprintf("Type: 1h\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\n" - "Version: %08Xh\nOEM ID: %s\nOEM table ID: %s\nWindows flag: WINDOWS\nSLIC version: %08Xh", - markerHeader->Size, markerHeader->Size, - (UINT32)header.size(), (UINT32)header.size(), - markerHeader->Version, - (const char*)UString((const char*)&(markerHeader->OemId)).left(6).toLocal8Bit(), - (const char*)UString((const char*)&(markerHeader->OemTableId)).left(8).toLocal8Bit(), - markerHeader->SlicVersion); - - - // Add tree item - index = model->addItem(localOffset, Types::SlicData, Subtypes::MarkerSlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent); - - return U_SUCCESS; -} - -USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) -{ - const UINT32 dataSize = (UINT32)store.size(); - const UINT32* signature = (const UINT32*)store.constData(); - // Check store size - if (dataSize < sizeof(UINT32)) { - msg(usprintf("%s: volume body is too small even for a store signature", __FUNCTION__), parent); - return U_SUCCESS; - } - - // Check signature and run parser function needed - // VSS/SVS/NSS store - if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE || *signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) - return parseVssStoreHeader(store, localOffset, false, parent, index); - // VSS2 store - if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1) - return parseVss2StoreHeader(store, localOffset, false, parent, index); - // FTW store - else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) - return parseFtwStoreHeader(store, localOffset, parent, index); - // FDC store - else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) - return parseFdcStoreHeader(store, localOffset, parent, index); - // Apple Fsys/Gaid store - else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) - return parseFsysStoreHeader(store, localOffset, parent, index); - // EVSA store - else if (dataSize >= 2 * sizeof(UINT32) && *(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE) - return parseEvsaStoreHeader(store, localOffset, parent, index); - // Phoenix SCT flash map - else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) - return parseFlashMapStoreHeader(store, localOffset, parent, index); - // Phoenix CMDB store - else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) - return parseCmdbStoreHeader(store, localOffset, parent, index); - // SLIC pubkey - else if (dataSize >= 5 * sizeof(UINT32) && *(signature + 4) == OEM_ACTIVATION_PUBKEY_MAGIC) - return parseSlicPubkeyHeader(store, localOffset, parent, index); - // SLIC marker - else if (dataSize >= 34 && *(const UINT64*)(store.constData() + 26) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG) - return parseSlicMarkerHeader(store, localOffset, parent, index); - // Intel microcode - // Must be checked after SLIC marker because of the same *signature values - else if (*signature == INTEL_MICROCODE_HEADER_VERSION_1) - return ffsParser->parseIntelMicrocodeHeader(store, localOffset, parent, index); - - msg(usprintf("parseStoreHeader: don't know how to parse a header with signature %08Xh", *signature), parent); - return U_SUCCESS; -} - -USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index) -{ - // Sanity check - if (!index.isValid()) - return U_INVALID_PARAMETER; - - // Get item data - const UByteArray data = model->body(index); - - // Get local offset - UINT32 localOffset = (UINT32)model->header(index).size(); - - // The body is a firmware volume with either a VSS or VSS2 store - UModelIndex volumeIndex; - USTATUS status = ffsParser->parseVolumeHeader(data, localOffset, index, volumeIndex); - if (status || !volumeIndex.isValid()) { - msg(usprintf("%s: store can't be parsed as FDC store", __FUNCTION__), index); - return U_SUCCESS; - } - - // Determine if it's a VSS or VSS2 store inside - UByteArray store = model->body(volumeIndex); - if ((UINT32)store.size() >= sizeof(UINT32) && *(const UINT32*)store.constData() == NVRAM_VSS_STORE_SIGNATURE) { - UModelIndex vssIndex; - status = parseVssStoreHeader(store, (UINT32)(localOffset + model->header(volumeIndex).size()), true, volumeIndex, vssIndex); - if (status) - return status; - return parseVssStoreBody(vssIndex, 0); - } - else if ((UINT32)store.size() >= sizeof(EFI_GUID) && store.left(sizeof(EFI_GUID)) == NVRAM_FDC_STORE_GUID) { - UModelIndex vss2Index; - status = parseVss2StoreHeader(store, (UINT32)(localOffset + model->header(volumeIndex).size()), true, volumeIndex, vss2Index); - if (status) - return status; - return parseVssStoreBody(vss2Index, 0); - } - else { - msg(usprintf("%s: internal volume can't be parsed as VSS/VSS2 store", __FUNCTION__), index); - return U_SUCCESS; - } - -} - -USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment) -{ - // Sanity check - if (!index.isValid()) - return U_INVALID_PARAMETER; - - // Obtain required information from parent volume - UINT8 emptyByte = 0xFF; - UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume); - if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) { - UByteArray data = model->parsingData(parentVolumeIndex); - const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); - emptyByte = pdata->emptyByte; - } - - // Get local offset - UINT32 localOffset = (UINT32)model->header(index).size(); - - // Get item data - const UByteArray data = model->body(index); - - // Check that the is enough space for variable header - const UINT32 dataSize = (UINT32)data.size(); - if (dataSize < sizeof(VSS_VARIABLE_HEADER)) { - msg(usprintf("%s: store body is too small even for VSS variable header", __FUNCTION__), index); - return U_SUCCESS; - } - - UINT32 offset = 0; - - // Parse all variables - while (1) { - bool isInvalid = true; - bool isAuthenticated = false; - bool isAppleCrc32 = false; - bool isIntelSpecial = false; - - UINT32 storedCrc32 = 0; - UINT32 calculatedCrc32 = 0; - UINT64 monotonicCounter = 0; - EFI_TIME timestamp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - UINT32 pubKeyIndex = 0; - - UINT8 subtype = 0; - UString name; - UString text; - EFI_GUID* variableGuid = NULL; - CHAR16* variableName = (CHAR16*)L""; - UByteArray header; - UByteArray body; - - UINT32 unparsedSize = dataSize - offset; - - // Get variable header - const VSS_VARIABLE_HEADER* variableHeader = (const VSS_VARIABLE_HEADER*)(data.constData() + offset); - - // Check variable header to fit in still unparsed data - UINT32 variableSize = 0; - if (unparsedSize >= sizeof(VSS_VARIABLE_HEADER) - && variableHeader->StartId == NVRAM_VSS_VARIABLE_START_ID) { - // Apple VSS variable with CRC32 of the data - if (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM) { - isAppleCrc32 = true; - if (unparsedSize < sizeof(VSS_APPLE_VARIABLE_HEADER)) { - variableSize = 0; - } - else { - const VSS_APPLE_VARIABLE_HEADER* appleVariableHeader = (const VSS_APPLE_VARIABLE_HEADER*)variableHeader; - variableSize = sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize + appleVariableHeader->DataSize; - variableGuid = (EFI_GUID*)&appleVariableHeader->VendorGuid; - variableName = (CHAR16*)(appleVariableHeader + 1); - - header = data.mid(offset, sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize); - body = data.mid(offset + header.size(), appleVariableHeader->DataSize); - - // Calculate CRC32 of the variable data - storedCrc32 = appleVariableHeader->DataCrc32; - calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)body.constData(), (uInt)body.size()); - } - } - - // Authenticated variable - else if ((variableHeader->Attributes & NVRAM_VSS_VARIABLE_AUTHENTICATED_WRITE_ACCESS) - || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) - || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPEND_WRITE) - || (variableHeader->NameSize == 0 && variableHeader->DataSize == 0)) { // If both NameSize and DataSize are zeros, it's auth variable with zero montonic counter - isAuthenticated = true; - if (unparsedSize < sizeof(VSS_AUTH_VARIABLE_HEADER)) { - variableSize = 0; - } - else { - const VSS_AUTH_VARIABLE_HEADER* authVariableHeader = (const VSS_AUTH_VARIABLE_HEADER*)variableHeader; - variableSize = sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize + authVariableHeader->DataSize; - variableGuid = (EFI_GUID*)&authVariableHeader->VendorGuid; - variableName = (CHAR16*)(authVariableHeader + 1); - - header = data.mid(offset, sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize); - body = data.mid(offset + header.size(), authVariableHeader->DataSize); - - monotonicCounter = authVariableHeader->MonotonicCounter; - timestamp = authVariableHeader->Timestamp; - pubKeyIndex = authVariableHeader->PubKeyIndex; - } - } - - // Intel special variable - else if (variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_VALID - || variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_INVALID) { - isIntelSpecial = true; - const VSS_INTEL_VARIABLE_HEADER* intelVariableHeader = (const VSS_INTEL_VARIABLE_HEADER*)variableHeader; - variableSize = intelVariableHeader->TotalSize; - variableGuid = (EFI_GUID*)&intelVariableHeader->VendorGuid; - variableName = (CHAR16*)(intelVariableHeader + 1); - - UINT32 i = 0; - while (variableName[i] != 0) ++i; - - i = sizeof(VSS_INTEL_VARIABLE_HEADER) + 2 * (i + 1); - i = i < variableSize ? i : variableSize; - - header = data.mid(offset, i); - body = data.mid(offset + header.size(), variableSize - i); - } - - // Normal VSS variable - else { - variableSize = sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize + variableHeader->DataSize; - variableGuid = (EFI_GUID*)&variableHeader->VendorGuid; - variableName = (CHAR16*)(variableHeader + 1); - - header = data.mid(offset, sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize); - body = data.mid(offset + header.size(), variableHeader->DataSize); - } - - // Check variable state - if (variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_VALID - || variableHeader->State == NVRAM_VSS_VARIABLE_ADDED - || variableHeader->State == NVRAM_VSS_VARIABLE_HEADER_VALID) { - isInvalid = false; - } - - // Check variable size - if (variableSize > unparsedSize) { - variableSize = 0; - } - } - - // Can't parse further, add the last element and break the loop - if (!variableSize) { - // Check if the data left is a free space or a padding - UByteArray padding = data.mid(offset, unparsedSize); - // Get info - UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); - - if (padding.count(emptyByte) == padding.size()) { // Free space - // Add tree item - model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - } - else { // Padding - // Nothing is parsed yet, but the store is not empty - if (!offset) { - msg(usprintf("%s: store can't be parsed as VSS store", __FUNCTION__), index); - return U_SUCCESS; - } - - // Add tree item - model->addItem(localOffset + offset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - } - - return U_SUCCESS; - } - - UString info; - - // Rename invalid variables - if (isInvalid || !variableGuid) { - isInvalid = true; - name = UString("Invalid"); - } - else { // Add GUID and text for valid variables - name = guidToUString(readUnaligned(variableGuid)); - info += UString("Variable GUID: ") + guidToUString(readUnaligned(variableGuid), false) + "\n"; - text = uFromUcs2((const char*)variableName); - } - - // Add info - info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (", - variableSize, variableSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - variableHeader->State, - variableHeader->Reserved, - variableHeader->Attributes) + vssAttributesToUString(variableHeader->Attributes) + UString(")"); - - // Set subtype and add related info - if (isInvalid) - subtype = Subtypes::InvalidVssEntry; - else if (isAuthenticated) { - subtype = Subtypes::AuthVssEntry; - info += usprintf("\nMonotonic counter: %" PRIX64 "h\nTimestamp: ", monotonicCounter) + efiTimeToUString(timestamp) - + usprintf("\nPubKey index: %u", pubKeyIndex); - } - else if (isAppleCrc32) { - subtype = Subtypes::AppleVssEntry; - info += usprintf("\nData checksum: %08Xh", storedCrc32) + - (storedCrc32 != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid")); - } - else if (isIntelSpecial) { - subtype = Subtypes::IntelVssEntry; - } - else { - subtype = Subtypes::StandardVssEntry; - } - - // Add tree item - model->addItem(localOffset + offset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, index); - - // Apply alignment, if needed - if (alignment) { - variableSize = ((variableSize + alignment - 1) & (~(alignment - 1))); - } - - // Move to next variable - offset += variableSize; - } - - return U_SUCCESS; -} - -USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) -{ - // Sanity check - if (!index.isValid()) - return U_INVALID_PARAMETER; - - // Get local offset - UINT32 localOffset = (UINT32)model->header(index).size(); - - // Get item data - const UByteArray data = model->body(index); - - // Check that the is enough space for variable header - const UINT32 storeDataSize = (UINT32)data.size(); - UINT32 offset = 0; - - // Parse all variables - while (1) { - UINT32 unparsedSize = storeDataSize - offset; - UINT32 variableSize = 0; - - // Get nameSize and name of the variable - UINT8 nameSize = *(UINT8*)(data.constData() + offset); - bool valid = !(nameSize & 0x80); // Last bit is a validity bit, 0 means valid - nameSize &= 0x7F; - - // Check sanity - if (unparsedSize >= nameSize + sizeof(UINT8)) { - variableSize = nameSize + sizeof(UINT8); - } - - UByteArray name; - if (variableSize) { - name = data.mid(offset + sizeof(UINT8), nameSize); - // Check for EOF variable - if (nameSize == 3 && name[0] == 'E' && name[1] == 'O' && name[2] == 'F') { - // There is no data afterward, add EOF variable and free space and return - UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize); - UString info = usprintf("Full size: %Xh (%u)", (UINT32)header.size(), (UINT32)header.size()); - - // Add EOF tree item - model->addItem(localOffset + offset, Types::FsysEntry, Subtypes::NormalFsysEntry, UString("EOF"), UString(), info, header, UByteArray(), UByteArray(), Fixed, index); - - // Add free space - offset += (UINT32)header.size(); - UByteArray body = data.mid(offset); - info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); - - // Add free space tree item - model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - - return U_SUCCESS; - } - } - - // Get dataSize and data of the variable - const UINT16 dataSize = *(UINT16*)(data.constData() + offset + sizeof(UINT8) + nameSize); - if (unparsedSize >= sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize) { - variableSize = sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize; - } - else { - // Last variable is bad, add the rest as padding and return - UByteArray body = data.mid(offset); - UString info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); - - // Add padding tree item - model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - - // Show message - msg(usprintf("%s: next variable appears too big, added as padding", __FUNCTION__), index); - - return U_SUCCESS; - } - - // Construct header and body - UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize + sizeof(UINT16)); - UByteArray body = data.mid(offset + sizeof(UINT8) + nameSize + sizeof(UINT16), dataSize); - - // Add info - UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - variableSize, variableSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size()); - - // Add tree item - model->addItem(localOffset + offset, Types::FsysEntry, valid ? Subtypes::NormalFsysEntry : Subtypes::InvalidFsysEntry, UString(name.constData()), UString(), info, header, body, UByteArray(), Fixed, index); - - // Move to next variable - offset += variableSize; - } - - return U_SUCCESS; -} - -USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) -{ - // Sanity check - if (!index.isValid()) - return U_INVALID_PARAMETER; - - // Obtain required information from parent volume - UINT8 emptyByte = 0xFF; - UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume); - if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) { - UByteArray data = model->parsingData(parentVolumeIndex); - const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); - emptyByte = pdata->emptyByte; - } - - // Get local offset - UINT32 localOffset = (UINT32)model->header(index).size(); - - // Get item data - const UByteArray data = model->body(index); - - // Check that the is enough space for entry header - const UINT32 storeDataSize = (UINT32)data.size(); - UINT32 offset = 0; - - std::map guidMap; - std::map nameMap; - - // Parse all entries - UINT32 unparsedSize = storeDataSize; - while (unparsedSize) { - UINT32 variableSize = 0; - UString name; - UString info; - UByteArray header; - UByteArray body; - UINT8 subtype; - UINT8 calculated; - - const EVSA_ENTRY_HEADER* entryHeader = (const EVSA_ENTRY_HEADER*)(data.constData() + offset); - - // Check entry size - variableSize = sizeof(EVSA_ENTRY_HEADER); - if (unparsedSize < variableSize || unparsedSize < entryHeader->Size || entryHeader->Size < 2) { - body = data.mid(offset); - info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); - - if (body.count(emptyByte) == body.size()) { // Free space - // Add free space tree item - model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - } - else { - // Add padding tree item - UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - - // Show message - msg(usprintf("%s: variable parsing failed, the rest of unparsed store added as padding", __FUNCTION__), itemIndex); - } - break; - } - variableSize = entryHeader->Size; - - // Recalculate entry checksum - calculated = calculateChecksum8(((const UINT8*)entryHeader) + 2, entryHeader->Size - 2); - - // GUID entry - if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID1 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID2) { - const EVSA_GUID_ENTRY* guidHeader = (const EVSA_GUID_ENTRY*)entryHeader; - header = data.mid(offset, sizeof(EVSA_GUID_ENTRY)); - body = data.mid(offset + sizeof(EVSA_GUID_ENTRY), guidHeader->Header.Size - sizeof(EVSA_GUID_ENTRY)); - EFI_GUID guid = *(EFI_GUID*)body.constData(); - 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", - variableSize, variableSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - guidHeader->Header.Type, - guidHeader->Header.Checksum) - + (guidHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) - + usprintf("\nGuidId: %04Xh", guidHeader->GuidId); - subtype = Subtypes::GuidEvsaEntry; - guidMap.insert(std::pair(guidHeader->GuidId, guid)); - } - // Name entry - else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME1 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME2) { - const EVSA_NAME_ENTRY* nameHeader = (const EVSA_NAME_ENTRY*)entryHeader; - header = data.mid(offset, sizeof(EVSA_NAME_ENTRY)); - body = data.mid(offset + sizeof(EVSA_NAME_ENTRY), nameHeader->Header.Size - sizeof(EVSA_NAME_ENTRY)); - 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", - variableSize, variableSize, - (UINT32)header.size(), (UINT32)header.size(), - (UINT32)body.size(), (UINT32)body.size(), - nameHeader->Header.Type, - nameHeader->Header.Checksum) - + (nameHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) - + usprintf("\nVarId: %04Xh", nameHeader->VarId); - subtype = Subtypes::NameEvsaEntry; - nameMap.insert(std::pair(nameHeader->VarId, name)); - } - // Data entry - else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA1 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA2 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) { - const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)entryHeader; - // Check for extended header - UINT32 headerSize = sizeof(EVSA_DATA_ENTRY); - UINT32 dataSize = dataHeader->Header.Size - sizeof(EVSA_DATA_ENTRY); - if (dataHeader->Attributes & NVRAM_EVSA_DATA_EXTENDED_HEADER) { - const EVSA_DATA_ENTRY_EXTENDED* dataHeaderExtended = (const EVSA_DATA_ENTRY_EXTENDED*)entryHeader; - headerSize = sizeof(EVSA_DATA_ENTRY_EXTENDED); - dataSize = dataHeaderExtended->DataSize; - variableSize = headerSize + dataSize; - } - - header = data.mid(offset, headerSize); - body = data.mid(offset + headerSize, dataSize); - name = UString("Data"); - info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", - variableSize, variableSize, - headerSize, headerSize, - dataSize, dataSize, - dataHeader->Header.Type, - dataHeader->Header.Checksum) - + (dataHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) - + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (", - dataHeader->VarId, - dataHeader->GuidId, - dataHeader->Attributes) - + evsaAttributesToUString(dataHeader->Attributes) + UString(")"); - subtype = Subtypes::DataEvsaEntry; - } - // Unknown entry or free space - else { - body = data.mid(offset); - info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); - - if (body.count(emptyByte) == body.size()) { // Free space - // Add free space tree item - model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - } - else { - // Add padding tree item - UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - - // Show message - msg(usprintf("%s: unknown variable of type %02Xh found at offset %Xh, the rest of unparsed store added as padding", __FUNCTION__, entryHeader->Type, offset), itemIndex); - } - break; - } - - // Add tree item - model->addItem(localOffset + offset, Types::EvsaEntry, subtype, name, UString(), info, header, body, UByteArray(), Fixed, index); - - // Move to next variable - offset += variableSize; - unparsedSize = storeDataSize - offset; - } - - // Reparse all data variables to detect invalid ones and assign name and test to valid ones - for (int i = 0; i < model->rowCount(index); i++) { - UModelIndex current = index.model()->index(i, 0, index); - - 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")); - 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")); - 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")); - 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")); - } - else { - model->setName(current, guid); - } - model->setText(current, name); - model->addInfo(current, UString("GUID: ") + guid + UString("\nName: ") + name + "\n", false); - } - } - } - - return U_SUCCESS; -} - - -USTATUS NvramParser::parseFlashMapBody(const UModelIndex & index) -{ - // Sanity check - if (!index.isValid()) - return U_INVALID_PARAMETER; - - // Get parsing data for the current item - UINT32 localOffset = (UINT32)model->header(index).size(); - const UByteArray data = model->body(index); - - - const UINT32 dataSize = (UINT32)data.size(); - UINT32 offset = 0; - UINT32 unparsedSize = dataSize; - // Parse all entries - while (unparsedSize) { - const PHOENIX_FLASH_MAP_ENTRY* entryHeader = (const PHOENIX_FLASH_MAP_ENTRY*)(data.constData() + offset); - - // Check entry size - if (unparsedSize < sizeof(PHOENIX_FLASH_MAP_ENTRY)) { - // Last variable is bad, add the rest as padding and return - UByteArray body = data.mid(offset); - UString info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); - - // Add padding tree item - model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - - // Show message - if (unparsedSize < entryHeader->Size) - msg(usprintf("%s: next entry appears too big, added as padding", __FUNCTION__), index); - - break; - } - - UString name = guidToUString(entryHeader->Guid); - - // Construct header - UByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY)); - - // Add info - UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) + - usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n" - "Entry type: %04Xh\nData type: %04Xh\nMemory address: %08Xh\nSize: %08Xh\nOffset: %08Xh", - entryHeader->EntryType, - entryHeader->DataType, - (UINT32)entryHeader->PhysicalAddress, - entryHeader->Size, - entryHeader->Offset); - - // Determine subtype - UINT8 subtype = 0; - switch (entryHeader->DataType) { - case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_VOLUME: - subtype = Subtypes::VolumeFlashMapEntry; - break; - case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_DATA_BLOCK: - subtype = Subtypes::DataFlashMapEntry; - break; - } - - // Add tree item - model->addItem(localOffset + offset, Types::FlashMapEntry, subtype, name, flashMapGuidToUString(entryHeader->Guid), info, header, UByteArray(), UByteArray(), Fixed, index); - - // Move to next variable - offset += sizeof(PHOENIX_FLASH_MAP_ENTRY); - unparsedSize = dataSize - offset; - } - return U_SUCCESS; } #endif // U_ENABLE_NVRAM_PARSING_SUPPORT diff --git a/common/nvramparser.h b/common/nvramparser.h index 3a50c5d..a53862d 100644 --- a/common/nvramparser.h +++ b/common/nvramparser.h @@ -47,27 +47,6 @@ private: void msg(const UString & message, const UModelIndex & index = UModelIndex()) { messagesVector.push_back(std::pair(message, index)); }; - - USTATUS findNextStore(const UModelIndex & index, const UByteArray & volume, const UINT32 localOffset, const UINT32 storeOffset, UINT32 & nextStoreOffset); - USTATUS getStoreSize(const UByteArray & data, const UINT32 storeOffset, UINT32 & storeSize); - USTATUS parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - - USTATUS parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index); - USTATUS parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index); - USTATUS parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseEvsaStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseFlashMapStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseSlicPubkeyHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - - USTATUS parseFdcStoreBody(const UModelIndex & index); - USTATUS parseVssStoreBody(const UModelIndex & index, const UINT8 alignment); - USTATUS parseFsysStoreBody(const UModelIndex & index); - USTATUS parseEvsaStoreBody(const UModelIndex & index); - USTATUS parseFlashMapBody(const UModelIndex & index); }; #else class NvramParser