diff --git a/UEFITool/CMakeLists.txt b/UEFITool/CMakeLists.txt index 1e35994..29b3371 100644 --- a/UEFITool/CMakeLists.txt +++ b/UEFITool/CMakeLists.txt @@ -69,6 +69,7 @@ SET(PROJECT_SOURCES ../common/digest/sm3.c ../common/generated/ami_nvar.cpp ../common/generated/edk2_vss.cpp + ../common/generated/phoenix_vss2.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 46181c1..9639e33 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -1453,7 +1453,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 volume 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 index 9edec83..d21701a 100644 --- a/common/generated/edk2_vss.cpp +++ b/common/generated/edk2_vss.cpp @@ -8,6 +8,7 @@ edk2_vss_t::edk2_vss_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, edk2_ m__root = this; (void)p__root; m_body = nullptr; m__io__raw_body = nullptr; + f_len_vss_store_header = false; _read(); } @@ -19,11 +20,11 @@ void edk2_vss_t::_read() { throw kaitai::validation_expr_error<uint32_t>(signature(), _io(), std::string("/seq/0")); } } - m_size = m__io->read_u4le(); + m_vss_size = m__io->read_u4le(); { - uint32_t _ = size(); - if (!(_ > (4 * 4))) { - throw kaitai::validation_expr_error<uint32_t>(size(), _io(), std::string("/seq/1")); + uint32_t _ = vss_size(); + if (!( ((_ > len_vss_store_header()) && (_ < 4294967295UL)) )) { + throw kaitai::validation_expr_error<uint32_t>(vss_size(), _io(), std::string("/seq/1")); } } m_format = m__io->read_u1(); @@ -36,7 +37,7 @@ void edk2_vss_t::_read() { 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__raw_body = m__io->read_bytes((vss_size() - len_vss_store_header())); m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body)); m_body = std::unique_ptr<vss_store_body_t>(new vss_store_body_t(m__io__raw_body.get(), this, m__root)); } @@ -104,6 +105,13 @@ edk2_vss_t::vss_variable_t::vss_variable_t(kaitai::kstream* p__io, edk2_vss_t::v m__parent = p__parent; m__root = p__root; m_attributes = nullptr; + f_is_auth = false; + f_len_standard_header = false; + f_is_intel_legacy = false; + f_len_auth_header = false; + f_len_apple_header = false; + f_len_intel_legacy_header = false; + f_is_valid = false; _read(); } @@ -135,35 +143,105 @@ void edk2_vss_t::vss_variable_t::_read() { n_attributes = false; m_attributes = std::unique_ptr<vss_variable_attributes_t>(new vss_variable_attributes_t(m__io, this, m__root)); } + n_len_total = true; + if ( ((signature_first() == 170) && (is_intel_legacy())) ) { + n_len_total = false; + m_len_total = m__io->read_u4le(); + { + uint32_t _ = len_total(); + if (!(_ >= ((len_intel_legacy_header() + 4) + 1))) { + throw kaitai::validation_expr_error<uint32_t>(len_total(), _io(), std::string("/types/vss_variable/seq/5")); + } + } + } n_len_name = true; - if (signature_first() == 170) { + if ( ((signature_first() == 170) && (!(is_intel_legacy()))) ) { n_len_name = false; m_len_name = m__io->read_u4le(); } n_len_data = true; - if (signature_first() == 170) { + if ( ((signature_first() == 170) && (!(is_intel_legacy()))) ) { n_len_data = false; m_len_data = m__io->read_u4le(); } + n_timestamp = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_timestamp = false; + m_timestamp = m__io->read_bytes(16); + } + n_pubkey_index = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_pubkey_index = false; + m_pubkey_index = m__io->read_u4le(); + } + n_len_name_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_len_name_auth = false; + m_len_name_auth = m__io->read_u4le(); + { + uint32_t _ = len_name_auth(); + if (!( ((_ >= 4) && (kaitai::kstream::mod(_, 2) == 0)) )) { + throw kaitai::validation_expr_error<uint32_t>(len_name_auth(), _io(), std::string("/types/vss_variable/seq/10")); + } + } + } + n_len_data_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_len_data_auth = false; + m_len_data_auth = m__io->read_u4le(); + { + uint32_t _ = len_data_auth(); + if (!(_ > 0)) { + throw kaitai::validation_expr_error<uint32_t>(len_data_auth(), _io(), std::string("/types/vss_variable/seq/11")); + } + } + } n_vendor_guid = true; if (signature_first() == 170) { n_vendor_guid = false; m_vendor_guid = m__io->read_bytes(16); } + n_name_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_name_auth = false; + m_name_auth = m__io->read_bytes(len_name_auth()); + } + n_data_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_data_auth = false; + m_data_auth = m__io->read_bytes(len_data_auth()); + } n_apple_data_crc32 = true; - if ( ((signature_first() == 170) && (attributes()->apple_data_checksum())) ) { + if ( ((signature_first() == 170) && (!(is_intel_legacy())) && (!(is_auth())) && (attributes()->apple_data_checksum())) ) { n_apple_data_crc32 = false; m_apple_data_crc32 = m__io->read_u4le(); } + n_intel_legacy_data = true; + if ( ((signature_first() == 170) && (is_intel_legacy())) ) { + n_intel_legacy_data = false; + m_intel_legacy_data = m__io->read_bytes((len_total() - len_intel_legacy_header())); + } n_name = true; - if (signature_first() == 170) { + if ( ((signature_first() == 170) && (!(is_intel_legacy())) && (!(is_auth()))) ) { n_name = false; m_name = m__io->read_bytes(len_name()); + { + std::string _ = name(); + if (!( ((len_name() >= 4) && (kaitai::kstream::mod(len_name(), 2) == 0)) )) { + throw kaitai::validation_expr_error<std::string>(name(), _io(), std::string("/types/vss_variable/seq/17")); + } + } } n_data = true; - if (signature_first() == 170) { + if ( ((signature_first() == 170) && (!(is_intel_legacy())) && (!(is_auth()))) ) { n_data = false; m_data = m__io->read_bytes(len_data()); + { + std::string _ = data(); + if (!(len_name() > 0)) { + throw kaitai::validation_expr_error<std::string>(data(), _io(), std::string("/types/vss_variable/seq/18")); + } + } } } @@ -180,16 +258,96 @@ void edk2_vss_t::vss_variable_t::_clean_up() { } if (!n_attributes) { } + if (!n_len_total) { + } if (!n_len_name) { } if (!n_len_data) { } + if (!n_timestamp) { + } + if (!n_pubkey_index) { + } + if (!n_len_name_auth) { + } + if (!n_len_data_auth) { + } if (!n_vendor_guid) { } + if (!n_name_auth) { + } + if (!n_data_auth) { + } if (!n_apple_data_crc32) { } + if (!n_intel_legacy_data) { + } if (!n_name) { } if (!n_data) { } } + +bool edk2_vss_t::vss_variable_t::is_auth() { + if (f_is_auth) + return m_is_auth; + m_is_auth = ((state() != 248) && (state() != 252) && ( (( ((attributes()->auth_write()) || (attributes()->time_based_auth()) || (attributes()->append_write())) ) || ( ((len_name() == 0) || (len_data() == 0)) )) )) ; + f_is_auth = true; + return m_is_auth; +} + +int8_t edk2_vss_t::vss_variable_t::len_standard_header() { + if (f_len_standard_header) + return m_len_standard_header; + m_len_standard_header = 32; + f_len_standard_header = true; + return m_len_standard_header; +} + +bool edk2_vss_t::vss_variable_t::is_intel_legacy() { + if (f_is_intel_legacy) + return m_is_intel_legacy; + m_is_intel_legacy = ((state() == 248) || (state() == 252)) ; + f_is_intel_legacy = true; + return m_is_intel_legacy; +} + +int8_t edk2_vss_t::vss_variable_t::len_auth_header() { + if (f_len_auth_header) + return m_len_auth_header; + m_len_auth_header = 60; + f_len_auth_header = true; + return m_len_auth_header; +} + +int8_t edk2_vss_t::vss_variable_t::len_apple_header() { + if (f_len_apple_header) + return m_len_apple_header; + m_len_apple_header = 36; + f_len_apple_header = true; + return m_len_apple_header; +} + +int8_t edk2_vss_t::vss_variable_t::len_intel_legacy_header() { + if (f_len_intel_legacy_header) + return m_len_intel_legacy_header; + m_len_intel_legacy_header = 28; + f_len_intel_legacy_header = true; + return m_len_intel_legacy_header; +} + +bool edk2_vss_t::vss_variable_t::is_valid() { + if (f_is_valid) + return m_is_valid; + m_is_valid = ((state() == 252) || (state() == 127) || (state() == 63)) ; + f_is_valid = true; + return m_is_valid; +} + +int8_t edk2_vss_t::len_vss_store_header() { + if (f_len_vss_store_header) + return m_len_vss_store_header; + m_len_vss_store_header = 16; + f_len_vss_store_header = true; + return m_len_vss_store_header; +} diff --git a/common/generated/edk2_vss.h b/common/generated/edk2_vss.h index b924fa6..22b9162 100644 --- a/common/generated/edk2_vss.h +++ b/common/generated/edk2_vss.h @@ -104,6 +104,55 @@ public: public: ~vss_variable_t(); + private: + bool f_is_auth; + bool m_is_auth; + + public: + bool is_auth(); + + private: + bool f_len_standard_header; + int8_t m_len_standard_header; + + public: + int8_t len_standard_header(); + + private: + bool f_is_intel_legacy; + bool m_is_intel_legacy; + + public: + bool is_intel_legacy(); + + private: + bool f_len_auth_header; + int8_t m_len_auth_header; + + public: + int8_t len_auth_header(); + + private: + bool f_len_apple_header; + int8_t m_len_apple_header; + + public: + int8_t len_apple_header(); + + private: + bool f_len_intel_legacy_header; + int8_t m_len_intel_legacy_header; + + public: + int8_t len_intel_legacy_header(); + + private: + bool f_is_valid; + bool m_is_valid; + + public: + bool is_valid(); + private: uint8_t m_signature_first; uint8_t m_signature_last; @@ -133,6 +182,13 @@ public: public: bool _is_null_attributes() { attributes(); return n_attributes; }; + private: + uint32_t m_len_total; + bool n_len_total; + + public: + bool _is_null_len_total() { len_total(); return n_len_total; }; + private: uint32_t m_len_name; bool n_len_name; @@ -147,6 +203,34 @@ public: public: bool _is_null_len_data() { len_data(); return n_len_data; }; + private: + std::string m_timestamp; + bool n_timestamp; + + public: + bool _is_null_timestamp() { timestamp(); return n_timestamp; }; + + private: + uint32_t m_pubkey_index; + bool n_pubkey_index; + + public: + bool _is_null_pubkey_index() { pubkey_index(); return n_pubkey_index; }; + + private: + uint32_t m_len_name_auth; + bool n_len_name_auth; + + public: + bool _is_null_len_name_auth() { len_name_auth(); return n_len_name_auth; }; + + private: + uint32_t m_len_data_auth; + bool n_len_data_auth; + + public: + bool _is_null_len_data_auth() { len_data_auth(); return n_len_data_auth; }; + private: std::string m_vendor_guid; bool n_vendor_guid; @@ -154,6 +238,20 @@ public: public: bool _is_null_vendor_guid() { vendor_guid(); return n_vendor_guid; }; + private: + std::string m_name_auth; + bool n_name_auth; + + public: + bool _is_null_name_auth() { name_auth(); return n_name_auth; }; + + private: + std::string m_data_auth; + bool n_data_auth; + + public: + bool _is_null_data_auth() { data_auth(); return n_data_auth; }; + private: uint32_t m_apple_data_crc32; bool n_apple_data_crc32; @@ -161,6 +259,13 @@ public: public: bool _is_null_apple_data_crc32() { apple_data_crc32(); return n_apple_data_crc32; }; + private: + std::string m_intel_legacy_data; + bool n_intel_legacy_data; + + public: + bool _is_null_intel_legacy_data() { intel_legacy_data(); return n_intel_legacy_data; }; + private: std::string m_name; bool n_name; @@ -185,19 +290,34 @@ public: uint8_t state() const { return m_state; } uint8_t reserved() const { return m_reserved; } vss_variable_attributes_t* attributes() const { return m_attributes.get(); } + uint32_t len_total() const { return m_len_total; } uint32_t len_name() const { return m_len_name; } uint32_t len_data() const { return m_len_data; } + std::string timestamp() const { return m_timestamp; } + uint32_t pubkey_index() const { return m_pubkey_index; } + uint32_t len_name_auth() const { return m_len_name_auth; } + uint32_t len_data_auth() const { return m_len_data_auth; } std::string vendor_guid() const { return m_vendor_guid; } + std::string name_auth() const { return m_name_auth; } + std::string data_auth() const { return m_data_auth; } uint32_t apple_data_crc32() const { return m_apple_data_crc32; } + std::string intel_legacy_data() const { return m_intel_legacy_data; } 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: + bool f_len_vss_store_header; + int8_t m_len_vss_store_header; + +public: + int8_t len_vss_store_header(); + private: uint32_t m_signature; - uint32_t m_size; + uint32_t m_vss_size; uint8_t m_format; uint8_t m_state; uint16_t m_reserved; @@ -210,7 +330,7 @@ private: public: uint32_t signature() const { return m_signature; } - uint32_t size() const { return m_size; } + uint32_t vss_size() const { return m_vss_size; } uint8_t format() const { return m_format; } uint8_t state() const { return m_state; } uint16_t reserved() const { return m_reserved; } diff --git a/common/generated/phoenix_vss2.cpp b/common/generated/phoenix_vss2.cpp new file mode 100644 index 0000000..f9b03bd --- /dev/null +++ b/common/generated/phoenix_vss2.cpp @@ -0,0 +1,347 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "phoenix_vss2.h" +#include "../kaitai/exceptions.h" + +phoenix_vss2_t::phoenix_vss2_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, phoenix_vss2_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; (void)p__root; + m_body = nullptr; + m__io__raw_body = nullptr; + f_header_size = false; + _read(); +} + +void phoenix_vss2_t::_read() { + m_signature = m__io->read_u4le(); + { + uint32_t _ = signature(); + if (!( ((_ == 3721344535UL) || (_ == 2868063352UL)) )) { + throw kaitai::validation_expr_error<uint32_t>(signature(), _io(), std::string("/seq/0")); + } + } + n_signature_auth_var_key_db = true; + if (signature() == 2868063352UL) { + n_signature_auth_var_key_db = false; + m_signature_auth_var_key_db = m__io->read_bytes(12); + if (!(signature_auth_var_key_db() == std::string("\x7B\x94\x9A\x43\xA1\x80\x2E\x14\x4E\xC3\x77\x92", 12))) { + throw kaitai::validation_not_equal_error<std::string>(std::string("\x7B\x94\x9A\x43\xA1\x80\x2E\x14\x4E\xC3\x77\x92", 12), signature_auth_var_key_db(), _io(), std::string("/seq/1")); + } + } + n_signature_vss2_store = true; + if (signature() == 3721344535UL) { + n_signature_vss2_store = false; + m_signature_vss2_store = m__io->read_bytes(12); + if (!(signature_vss2_store() == std::string("\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D", 12))) { + throw kaitai::validation_not_equal_error<std::string>(std::string("\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D", 12), signature_vss2_store(), _io(), std::string("/seq/2")); + } + } + m_vss2_size = m__io->read_u4le(); + { + uint32_t _ = vss2_size(); + if (!( ((_ > header_size()) && (_ < 4294967295UL)) )) { + throw kaitai::validation_expr_error<uint32_t>(vss2_size(), _io(), std::string("/seq/3")); + } + } + m_format = m__io->read_u1(); + { + uint8_t _ = format(); + if (!(_ == 90)) { + throw kaitai::validation_expr_error<uint8_t>(format(), _io(), std::string("/seq/4")); + } + } + 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((vss2_size() - header_size())); + m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body)); + m_body = std::unique_ptr<vss2_store_body_t>(new vss2_store_body_t(m__io__raw_body.get(), this, m__root)); +} + +phoenix_vss2_t::~phoenix_vss2_t() { + _clean_up(); +} + +void phoenix_vss2_t::_clean_up() { + if (!n_signature_auth_var_key_db) { + } + if (!n_signature_vss2_store) { + } +} + +phoenix_vss2_t::vss2_store_body_t::vss2_store_body_t(kaitai::kstream* p__io, phoenix_vss2_t* p__parent, phoenix_vss2_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_variables = nullptr; + _read(); +} + +void phoenix_vss2_t::vss2_store_body_t::_read() { + m_variables = std::unique_ptr<std::vector<std::unique_ptr<vss2_variable_t>>>(new std::vector<std::unique_ptr<vss2_variable_t>>()); + { + int i = 0; + vss2_variable_t* _; + do { + _ = new vss2_variable_t(m__io, this, m__root); + m_variables->push_back(std::move(std::unique_ptr<vss2_variable_t>(_))); + i++; + } while (!( ((_->signature_first() != 170) || (_io()->is_eof())) )); + } +} + +phoenix_vss2_t::vss2_store_body_t::~vss2_store_body_t() { + _clean_up(); +} + +void phoenix_vss2_t::vss2_store_body_t::_clean_up() { +} + +phoenix_vss2_t::vss2_variable_attributes_t::vss2_variable_attributes_t(kaitai::kstream* p__io, phoenix_vss2_t::vss2_variable_t* p__parent, phoenix_vss2_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + _read(); +} + +void phoenix_vss2_t::vss2_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(25); +} + +phoenix_vss2_t::vss2_variable_attributes_t::~vss2_variable_attributes_t() { + _clean_up(); +} + +void phoenix_vss2_t::vss2_variable_attributes_t::_clean_up() { +} + +phoenix_vss2_t::vss2_variable_t::vss2_variable_t(kaitai::kstream* p__io, phoenix_vss2_t::vss2_store_body_t* p__parent, phoenix_vss2_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_attributes = nullptr; + f_is_auth = false; + f_end_offset_auth = false; + f_len_alignment_padding = false; + f_end_offset = false; + f_len_alignment_padding_auth = false; + f_offset = false; + _read(); +} + +void phoenix_vss2_t::vss2_variable_t::_read() { + n_invoke_offset = true; + if (offset() >= 0) { + n_invoke_offset = false; + m_invoke_offset = m__io->read_bytes(0); + } + 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<uint8_t>(signature_last(), _io(), std::string("/types/vss2_variable/seq/2")); + } + } + } + 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 = std::unique_ptr<vss2_variable_attributes_t>(new vss2_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_timestamp = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_timestamp = false; + m_timestamp = m__io->read_bytes(16); + } + n_pubkey_index = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_pubkey_index = false; + m_pubkey_index = m__io->read_u4le(); + } + n_len_name_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_len_name_auth = false; + m_len_name_auth = m__io->read_u4le(); + } + n_len_data_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_len_data_auth = false; + m_len_data_auth = 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_name_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_name_auth = false; + m_name_auth = m__io->read_bytes(len_name_auth()); + } + n_data_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_data_auth = false; + m_data_auth = m__io->read_bytes(len_data_auth()); + } + n_invoke_end_offset_auth = true; + if ( ((signature_first() == 170) && (is_auth()) && (end_offset_auth() >= 0)) ) { + n_invoke_end_offset_auth = false; + m_invoke_end_offset_auth = m__io->read_bytes(0); + } + n_alignment_padding_auth = true; + if ( ((signature_first() == 170) && (is_auth())) ) { + n_alignment_padding_auth = false; + m_alignment_padding_auth = m__io->read_bytes(len_alignment_padding_auth()); + } + n_name = true; + if ( ((signature_first() == 170) && (!(is_auth()))) ) { + n_name = false; + m_name = m__io->read_bytes(len_name()); + } + n_data = true; + if ( ((signature_first() == 170) && (!(is_auth()))) ) { + n_data = false; + m_data = m__io->read_bytes(len_data()); + } + n_invoke_end_offset = true; + if ( ((signature_first() == 170) && (!(is_auth())) && (end_offset() >= 0)) ) { + n_invoke_end_offset = false; + m_invoke_end_offset = m__io->read_bytes(0); + } + n_alignment_padding = true; + if ( ((signature_first() == 170) && (!(is_auth()))) ) { + n_alignment_padding = false; + m_alignment_padding = m__io->read_bytes(len_alignment_padding()); + } +} + +phoenix_vss2_t::vss2_variable_t::~vss2_variable_t() { + _clean_up(); +} + +void phoenix_vss2_t::vss2_variable_t::_clean_up() { + if (!n_invoke_offset) { + } + if (!n_signature_last) { + } + if (!n_state) { + } + if (!n_reserved) { + } + if (!n_attributes) { + } + if (!n_len_name) { + } + if (!n_len_data) { + } + if (!n_timestamp) { + } + if (!n_pubkey_index) { + } + if (!n_len_name_auth) { + } + if (!n_len_data_auth) { + } + if (!n_vendor_guid) { + } + if (!n_name_auth) { + } + if (!n_data_auth) { + } + if (!n_invoke_end_offset_auth) { + } + if (!n_alignment_padding_auth) { + } + if (!n_name) { + } + if (!n_data) { + } + if (!n_invoke_end_offset) { + } + if (!n_alignment_padding) { + } +} + +bool phoenix_vss2_t::vss2_variable_t::is_auth() { + if (f_is_auth) + return m_is_auth; + m_is_auth = (( ((attributes()->auth_write()) || (attributes()->time_based_auth()) || (attributes()->append_write())) ) || ( ((len_name() == 0) || (len_data() == 0)) )) ; + f_is_auth = true; + return m_is_auth; +} + +int32_t phoenix_vss2_t::vss2_variable_t::end_offset_auth() { + if (f_end_offset_auth) + return m_end_offset_auth; + m_end_offset_auth = _io()->pos(); + f_end_offset_auth = true; + return m_end_offset_auth; +} + +int32_t phoenix_vss2_t::vss2_variable_t::len_alignment_padding() { + if (f_len_alignment_padding) + return m_len_alignment_padding; + m_len_alignment_padding = ((((end_offset() - offset()) + 3) & ~3) - (end_offset() - offset())); + f_len_alignment_padding = true; + return m_len_alignment_padding; +} + +int32_t phoenix_vss2_t::vss2_variable_t::end_offset() { + if (f_end_offset) + return m_end_offset; + m_end_offset = _io()->pos(); + f_end_offset = true; + return m_end_offset; +} + +int32_t phoenix_vss2_t::vss2_variable_t::len_alignment_padding_auth() { + if (f_len_alignment_padding_auth) + return m_len_alignment_padding_auth; + m_len_alignment_padding_auth = ((((end_offset_auth() - offset()) + 3) & ~3) - (end_offset() - offset())); + f_len_alignment_padding_auth = true; + return m_len_alignment_padding_auth; +} + +int32_t phoenix_vss2_t::vss2_variable_t::offset() { + if (f_offset) + return m_offset; + m_offset = _io()->pos(); + f_offset = true; + return m_offset; +} + +int32_t phoenix_vss2_t::header_size() { + if (f_header_size) + return m_header_size; + m_header_size = (7 * 4); + f_header_size = true; + return m_header_size; +} diff --git a/common/generated/phoenix_vss2.h b/common/generated/phoenix_vss2.h new file mode 100644 index 0000000..98667ad --- /dev/null +++ b/common/generated/phoenix_vss2.h @@ -0,0 +1,366 @@ +#pragma once + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "../kaitai/kaitaistruct.h" +#include <stdint.h> +#include <memory> +#include <vector> + +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" +#endif + +class phoenix_vss2_t : public kaitai::kstruct { + +public: + class vss2_store_body_t; + class vss2_variable_attributes_t; + class vss2_variable_t; + + phoenix_vss2_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, phoenix_vss2_t* p__root = nullptr); + +private: + void _read(); + void _clean_up(); + +public: + ~phoenix_vss2_t(); + + class vss2_store_body_t : public kaitai::kstruct { + + public: + + vss2_store_body_t(kaitai::kstream* p__io, phoenix_vss2_t* p__parent = nullptr, phoenix_vss2_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~vss2_store_body_t(); + + private: + std::unique_ptr<std::vector<std::unique_ptr<vss2_variable_t>>> m_variables; + phoenix_vss2_t* m__root; + phoenix_vss2_t* m__parent; + + public: + std::vector<std::unique_ptr<vss2_variable_t>>* variables() const { return m_variables.get(); } + phoenix_vss2_t* _root() const { return m__root; } + phoenix_vss2_t* _parent() const { return m__parent; } + }; + + class vss2_variable_attributes_t : public kaitai::kstruct { + + public: + + vss2_variable_attributes_t(kaitai::kstream* p__io, phoenix_vss2_t::vss2_variable_t* p__parent = nullptr, phoenix_vss2_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~vss2_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; + phoenix_vss2_t* m__root; + phoenix_vss2_t::vss2_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; } + phoenix_vss2_t* _root() const { return m__root; } + phoenix_vss2_t::vss2_variable_t* _parent() const { return m__parent; } + }; + + class vss2_variable_t : public kaitai::kstruct { + + public: + + vss2_variable_t(kaitai::kstream* p__io, phoenix_vss2_t::vss2_store_body_t* p__parent = nullptr, phoenix_vss2_t* p__root = nullptr); + + private: + void _read(); + void _clean_up(); + + public: + ~vss2_variable_t(); + + private: + bool f_is_auth; + bool m_is_auth; + + public: + bool is_auth(); + + private: + bool f_end_offset_auth; + int32_t m_end_offset_auth; + + public: + int32_t end_offset_auth(); + + private: + bool f_len_alignment_padding; + int32_t m_len_alignment_padding; + + public: + int32_t len_alignment_padding(); + + private: + bool f_end_offset; + int32_t m_end_offset; + + public: + int32_t end_offset(); + + private: + bool f_len_alignment_padding_auth; + int32_t m_len_alignment_padding_auth; + + public: + int32_t len_alignment_padding_auth(); + + private: + bool f_offset; + int32_t m_offset; + + public: + int32_t offset(); + + private: + std::string m_invoke_offset; + bool n_invoke_offset; + + public: + bool _is_null_invoke_offset() { invoke_offset(); return n_invoke_offset; }; + + 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: + std::unique_ptr<vss2_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_timestamp; + bool n_timestamp; + + public: + bool _is_null_timestamp() { timestamp(); return n_timestamp; }; + + private: + uint32_t m_pubkey_index; + bool n_pubkey_index; + + public: + bool _is_null_pubkey_index() { pubkey_index(); return n_pubkey_index; }; + + private: + uint32_t m_len_name_auth; + bool n_len_name_auth; + + public: + bool _is_null_len_name_auth() { len_name_auth(); return n_len_name_auth; }; + + private: + uint32_t m_len_data_auth; + bool n_len_data_auth; + + public: + bool _is_null_len_data_auth() { len_data_auth(); return n_len_data_auth; }; + + private: + std::string m_vendor_guid; + bool n_vendor_guid; + + public: + bool _is_null_vendor_guid() { vendor_guid(); return n_vendor_guid; }; + + private: + std::string m_name_auth; + bool n_name_auth; + + public: + bool _is_null_name_auth() { name_auth(); return n_name_auth; }; + + private: + std::string m_data_auth; + bool n_data_auth; + + public: + bool _is_null_data_auth() { data_auth(); return n_data_auth; }; + + private: + std::string m_invoke_end_offset_auth; + bool n_invoke_end_offset_auth; + + public: + bool _is_null_invoke_end_offset_auth() { invoke_end_offset_auth(); return n_invoke_end_offset_auth; }; + + private: + std::string m_alignment_padding_auth; + bool n_alignment_padding_auth; + + public: + bool _is_null_alignment_padding_auth() { alignment_padding_auth(); return n_alignment_padding_auth; }; + + 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: + std::string m_invoke_end_offset; + bool n_invoke_end_offset; + + public: + bool _is_null_invoke_end_offset() { invoke_end_offset(); return n_invoke_end_offset; }; + + private: + std::string m_alignment_padding; + bool n_alignment_padding; + + public: + bool _is_null_alignment_padding() { alignment_padding(); return n_alignment_padding; }; + + private: + phoenix_vss2_t* m__root; + phoenix_vss2_t::vss2_store_body_t* m__parent; + + public: + std::string invoke_offset() const { return m_invoke_offset; } + 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; } + vss2_variable_attributes_t* attributes() const { return m_attributes.get(); } + uint32_t len_name() const { return m_len_name; } + uint32_t len_data() const { return m_len_data; } + std::string timestamp() const { return m_timestamp; } + uint32_t pubkey_index() const { return m_pubkey_index; } + uint32_t len_name_auth() const { return m_len_name_auth; } + uint32_t len_data_auth() const { return m_len_data_auth; } + std::string vendor_guid() const { return m_vendor_guid; } + std::string name_auth() const { return m_name_auth; } + std::string data_auth() const { return m_data_auth; } + std::string invoke_end_offset_auth() const { return m_invoke_end_offset_auth; } + std::string alignment_padding_auth() const { return m_alignment_padding_auth; } + std::string name() const { return m_name; } + std::string data() const { return m_data; } + std::string invoke_end_offset() const { return m_invoke_end_offset; } + std::string alignment_padding() const { return m_alignment_padding; } + phoenix_vss2_t* _root() const { return m__root; } + phoenix_vss2_t::vss2_store_body_t* _parent() const { return m__parent; } + }; + +private: + bool f_header_size; + int32_t m_header_size; + +public: + int32_t header_size(); + +private: + uint32_t m_signature; + std::string m_signature_auth_var_key_db; + bool n_signature_auth_var_key_db; + +public: + bool _is_null_signature_auth_var_key_db() { signature_auth_var_key_db(); return n_signature_auth_var_key_db; }; + +private: + std::string m_signature_vss2_store; + bool n_signature_vss2_store; + +public: + bool _is_null_signature_vss2_store() { signature_vss2_store(); return n_signature_vss2_store; }; + +private: + uint32_t m_vss2_size; + uint8_t m_format; + uint8_t m_state; + uint16_t m_reserved; + uint32_t m_reserved1; + std::unique_ptr<vss2_store_body_t> m_body; + phoenix_vss2_t* m__root; + kaitai::kstruct* m__parent; + std::string m__raw_body; + std::unique_ptr<kaitai::kstream> m__io__raw_body; + +public: + uint32_t signature() const { return m_signature; } + std::string signature_auth_var_key_db() const { return m_signature_auth_var_key_db; } + std::string signature_vss2_store() const { return m_signature_vss2_store; } + uint32_t vss2_size() const { return m_vss2_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; } + vss2_store_body_t* body() const { return m_body.get(); } + phoenix_vss2_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.get(); } +}; diff --git a/common/ksy/edk2_vss.ksy b/common/ksy/edk2_vss.ksy index e24202e..ed478c1 100644 --- a/common/ksy/edk2_vss.ksy +++ b/common/ksy/edk2_vss.ksy @@ -1,6 +1,6 @@ meta: id: edk2_vss - title: EDK2 VSS storage + title: EDK2 VSS NVRAM store application: EDK2-based UEFI firmware file-extension: vss tags: @@ -14,10 +14,10 @@ seq: type: u4 valid: expr: _ == 0x53535624 or _ == 0x53565324 or _ == 0x53534E24 # $VSS/$SVS/$NSS -- id: size +- id: vss_size type: u4 valid: - expr: _ > 4 * sizeof<u4> + expr: _ > len_vss_store_header and _ < 0xFFFFFFFF - id: format type: u1 valid: @@ -30,7 +30,10 @@ seq: type: u4 - id: body type: vss_store_body - size: size - 4 * sizeof<u4> + size: vss_size - len_vss_store_header +instances: + len_vss_store_header: + value: 16 types: vss_store_body: @@ -79,22 +82,81 @@ types: - id: attributes type: vss_variable_attributes if: signature_first == 0xAA - #TODO: add Intel legacy total_size variant +# vvv Intel legacy + - id: len_total + 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 +# ^^^ 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 type: u4 - if: signature_first == 0xAA + if: signature_first == 0xAA and not is_intel_legacy - id: len_data type: u4 - if: signature_first == 0xAA + if: signature_first == 0xAA and not is_intel_legacy +# vvv Auth variable + - id: timestamp + size: 16 + if: signature_first == 0xAA and is_auth + - id: pubkey_index + type: u4 + if: signature_first == 0xAA and is_auth + - id: len_name_auth + type: u4 + if: signature_first == 0xAA and is_auth + valid: + expr: (_ >= 4) and (_ % 2 == 0) # UCS2 characters come in byte pairs + - id: len_data_auth + type: u4 + if: signature_first == 0xAA and is_auth + valid: + expr: _ > 0 +# ^^^ Auth variable - id: vendor_guid size: 16 if: signature_first == 0xAA +# vvv Auth variable + - id: name_auth + size: len_name_auth + if: signature_first == 0xAA and is_auth + - id: data_auth + size: len_data_auth + if: signature_first == 0xAA and is_auth +# ^^^ Auth variable +# vvv Apple MacEFI - id: apple_data_crc32 type: u4 - if: signature_first == 0xAA and attributes.apple_data_checksum + if: signature_first == 0xAA and not is_intel_legacy and not is_auth and attributes.apple_data_checksum +# ^^^ Apple MacEFI +# vvv Intel legacy + - id: intel_legacy_data + size: len_total - len_intel_legacy_header + if: signature_first == 0xAA and is_intel_legacy +# ^^^ Intel legacy - id: name size: len_name - if: signature_first == 0xAA + if: signature_first == 0xAA and not is_intel_legacy and not is_auth + valid: + expr: (len_name >= 4) and (len_name % 2 == 0) - id: data size: len_data - if: signature_first == 0xAA + if: signature_first == 0xAA and not is_intel_legacy and not is_auth + valid: + expr: len_name > 0 + instances: + is_valid: + value: state == 0xFC or state == 0x7F or state == 0x3F + is_intel_legacy: + value: (state == 0xF8 or state == 0xFC) # Special states indicating Intel legacy variables + is_auth: + value: state != 0xF8 and state != 0xFC and ((attributes.auth_write or attributes.time_based_auth or attributes.append_write) or (len_name == 0 or len_data == 0)) + len_intel_legacy_header: + value: 28 + len_auth_header: + value: 60 + len_standard_header: + value: 32 + len_apple_header: + value: 36 diff --git a/common/ksy/phoenix_vss2.ksy b/common/ksy/phoenix_vss2.ksy new file mode 100644 index 0000000..6d0f63f --- /dev/null +++ b/common/ksy/phoenix_vss2.ksy @@ -0,0 +1,154 @@ +meta: + id: phoenix_vss2 + title: Phoenix VSS2 NVRAM variable storage + application: Phoenix SCT-based UEFI firmware + file-extension: vss2 + tags: + - firmware + license: CC0-1.0 + ks-version: 0.9 + endian: le + +seq: +- id: signature + type: u4 + valid: + expr: _ == 0xDDCF3617 or _ == 0xAAF32C78 # Beginning of known store GUIDs for VSS2 +- id: signature_auth_var_key_db + contents: [0x7B, 0x94, 0x9A, 0x43, 0xA1, 0x80, 0x2E, 0x14, 0x4E, 0xC3, 0x77, 0x92] # AAF32C78-947B-439A-A180-2E144EC37792 + if: signature == 0xAAF32C78 +- id: signature_vss2_store + contents: [0x75, 0x32, 0x64, 0x41, 0x98, 0xB6, 0xFE, 0x85, 0x70, 0x7F, 0xFE, 0x7D] # DDCF3617-3275-4164-98B6-FE85707FFE7D + if: signature == 0xDDCF3617 +- id: vss2_size + type: u4 + valid: + expr: _ > header_size and _ < 0xFFFFFFFF +- id: format + type: u1 + valid: + expr: _ == 0x5a # Formatted +- id: state + type: u1 +- id: reserved + type: u2 +- id: reserved1 + type: u4 +- id: body + type: vss2_store_body + size: vss2_size - header_size +instances: + header_size: + value: 7 * sizeof<u4> + +types: + vss2_store_body: + seq: + - id: variables + type: vss2_variable + repeat: until + repeat-until: _.signature_first != 0xAA or _io.eof + + vss2_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: b25le + +# TODO: check if VSS2 stores can have standard VSS variables + vss2_variable: + seq: + - id: invoke_offset + size: 0 + if: offset >= 0 + - 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: vss2_variable_attributes + if: signature_first == 0xAA + - id: len_name + type: u4 + if: signature_first == 0xAA + - id: len_data + type: u4 + if: signature_first == 0xAA +# vvv Auth variable + - id: timestamp + size: 16 + if: signature_first == 0xAA and is_auth + - id: pubkey_index + type: u4 + if: signature_first == 0xAA and is_auth + - id: len_name_auth + type: u4 + if: signature_first == 0xAA and is_auth + - id: len_data_auth + type: u4 + if: signature_first == 0xAA and is_auth +# ^^^ Auth variable + - id: vendor_guid + size: 16 + if: signature_first == 0xAA +# vvv Auth variable + - id: name_auth + size: len_name_auth + if: signature_first == 0xAA and is_auth + - id: data_auth + size: len_data_auth + if: signature_first == 0xAA and is_auth + - id: invoke_end_offset_auth + size: 0 + if: signature_first == 0xAA and is_auth and end_offset_auth >= 0 + - id: alignment_padding_auth + size: len_alignment_padding_auth + if: signature_first == 0xAA and is_auth +# ^^^ Auth variable + - id: name + size: len_name + if: signature_first == 0xAA and not is_auth + - id: data + size: len_data + if: signature_first == 0xAA and not is_auth + - id: invoke_end_offset + size: 0 + if: signature_first == 0xAA and not is_auth and end_offset >= 0 + - id: alignment_padding + size: len_alignment_padding + if: signature_first == 0xAA and not is_auth + instances: + offset: + value: _io.pos + end_offset: + value: _io.pos + end_offset_auth: + value: _io.pos + len_alignment_padding: + value: (((end_offset - offset)+3) & ~3) - (end_offset - offset) + len_alignment_padding_auth: + value: (((end_offset_auth - offset)+3) & ~3) - (end_offset - offset) + is_auth: + value: (attributes.auth_write or attributes.time_based_auth or attributes.append_write) or (len_name == 0 or len_data == 0) diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index 5e9d6cc..8c157c3 100644 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -27,6 +27,7 @@ #include "kaitai/kaitaistream.h" #include "generated/ami_nvar.h" #include "generated/edk2_vss.h" +#include "generated/phoenix_vss2.h" USTATUS NvramParser::parseNvarStore(const UModelIndex & index) { @@ -304,35 +305,206 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) const UINT32 volumeBodySize = (UINT32)volumeBody.size(); // 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++) { + UByteArray outerPadding; + UINT32 previousStoreEndOffset = 0; + for (UINT32 storeOffset = 0; + storeOffset < volumeBodySize; + storeOffset++) { bool storeFound = false; // Try parsing as VSS store try { - UByteArray vss = volumeBody.mid(offset); + UByteArray vss = volumeBody.mid(storeOffset); umemstream is(vss.constData(), vss.size()); kaitai::kstream ks(&is); edk2_vss_t parsed(&ks); // 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); + // 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()); + model->addItem(previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index); + outerPadding.clear(); + } + // Construct header and body + UByteArray header = vss.left(parsed.len_vss_store_header()); + UByteArray body = vss.mid(header.size(), parsed.vss_size() - header.size()); + + // Add info + UString name; + if (parsed.signature() == NVRAM_APPLE_SVS_STORE_SIGNATURE) { + name = UString("SVS store"); + } + else if (parsed.signature() == NVRAM_APPLE_NSS_STORE_SIGNATURE) { + name = UString("NSS store"); + } + else { + name = UString("VSS store"); + } + UString 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", + parsed.vss_size() , parsed.vss_size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + parsed.format(), + parsed.state(), + parsed.reserved(), + parsed.reserved1()); + + // Add header tree item + UModelIndex headerIndex = model->addItem(localOffset + storeOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index); + + UINT32 vssVariableOffset = storeOffset + parsed.len_vss_store_header(); + for (const auto & variable : *parsed.body()->variables()) { + UINT8 subtype; + UString text; + info.clear(); + name.clear(); + + // This is thew terminating entry, needs special processing + if (variable->_is_null_signature_last()) { + // Add free space or padding after all variables, if needed + if (vssVariableOffset < parsed.vss_size()) { + UByteArray freeSpace = vss.mid(vssVariableOffset, parsed.vss_size() - vssVariableOffset); + // Add info + info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); + + // Check that remaining unparsed bytes are actually empty + if (freeSpace.count(emptyByte) == freeSpace.size()) { // Free space + // Add tree item + model->addItem(vssVariableOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex); + } + else { + // Add tree item + model->addItem(vssVariableOffset, Types::Padding, getPaddingType(freeSpace), UString("Padding"), UString(), info, UByteArray(), freeSpace, UByteArray(), Fixed, headerIndex); + } + } + break; + } + + // This is a normal entry + UINT32 variableSize; + if (variable->is_intel_legacy()) { + subtype = Subtypes::IntelVssEntry; + // Needs some additional parsing of variable->intel_legacy_data to separate the name from the value + text = uFromUcs2(variable->intel_legacy_data().c_str()); + UINT32 textLengthInBytes = (UINT32)text.length()*2+2; + header = vss.mid(vssVariableOffset, variable->len_intel_legacy_header() + textLengthInBytes); + body = vss.mid(vssVariableOffset + header.size(), variable->len_total() - variable->len_intel_legacy_header() - textLengthInBytes); + variableSize = (UINT32)(header.size() + body.size()); + const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); + name = guidToUString(variableGuid); + info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + } + else if (variable->is_auth()) { + subtype = Subtypes::AuthVssEntry; + header = vss.mid(vssVariableOffset, variable->len_auth_header() + variable->len_name_auth()); + body = vss.mid(vssVariableOffset + header.size(), variable->len_data_auth()); + variableSize = (UINT32)(header.size() + body.size()); + const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); + name = guidToUString(variableGuid); + text = uFromUcs2(variable->name_auth().c_str()); + info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + } + else if (!variable->_is_null_apple_data_crc32()) { + subtype = Subtypes::AppleVssEntry; + header = vss.mid(vssVariableOffset, variable->len_apple_header() + variable->len_name()); + body = vss.mid(vssVariableOffset + header.size(), variable->len_data()); + variableSize = (UINT32)(header.size() + body.size()); + const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); + name = guidToUString(variableGuid); + text = uFromUcs2(variable->name().c_str()); + info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + } + else { + subtype = Subtypes::StandardVssEntry; + header = vss.mid(vssVariableOffset, variable->len_standard_header() + variable->len_name()); + body = vss.mid(vssVariableOffset + header.size(), variable->len_data()); + variableSize = (UINT32)(header.size() + body.size()); + const EFI_GUID variableGuid = readUnaligned((const EFI_GUID*)(variable->vendor_guid().c_str())); + name = guidToUString(variableGuid); + text = uFromUcs2(variable->name().c_str()); + info += UString("Variable GUID: ") + guidToUString(variableGuid, false) + "\n"; + } + + // Override variable type to Invalid if needed + if (!variable->is_valid()) { + subtype = Subtypes::InvalidVssEntry; + name = UString("Invalid"); + text.clear(); + } + + const UINT32 variableAttributes = variable->attributes()->non_volatile() + + (variable->attributes()->boot_service() << 1) + + (variable->attributes()->runtime() << 2) + + (variable->attributes()->hw_error_record() << 3) + + (variable->attributes()->auth_write() << 4) + + (variable->attributes()->time_based_auth() << 5) + + (variable->attributes()->append_write() << 6) + + (variable->attributes()->apple_data_checksum() << 31); + + // Add generic info + info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02X\nAttributes: %08Xh (", + variableSize, variableSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + variable->state(), + variable->reserved(), + variableAttributes) + vssAttributesToUString(variableAttributes) + UString(")"); + + // Add specific info + if (variable->is_auth()) { + UINT64 monotonicCounter = (UINT64)variable->len_name() + ((UINT64)variable->len_data() << 32); + info += usprintf("\nMonotonic counter: %" PRIX64 "h\nTimestamp: ", monotonicCounter) + efiTimeToUString(*(const EFI_TIME*)variable->timestamp().c_str()) + + usprintf("\nPubKey index: %u", variable->pubkey_index()); + } + else if (!variable->_is_null_apple_data_crc32()) { + // Calculate CRC32 of the variable data + UINT32 calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)body.constData(), (uInt)body.size()); + + info += usprintf("\nData checksum: %08Xh", variable->apple_data_crc32()) + + (variable->apple_data_crc32() != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid")); + } + + // Add tree item + model->addItem(vssVariableOffset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, headerIndex); + + vssVariableOffset += variableSize; + } + storeFound = true; - padding.clear(); - - offset += parsed.size() - 1; + storeOffset += parsed.vss_size(); + previousStoreEndOffset = storeOffset; } catch (...) { - // Parsing failed try something else + // Parsing failed, try something else } - //TODO: all other kinds of stores - // if (!storeFound && ...) + // VSS2 - // This byte had not been parsed as anything - if (!storeFound) - padding += volumeBody.at(offset); + // FDC + + // EVSA + + // FTW + + // Apple Fsys/Gaid + + // Phoenix FlashMap + // Phoenix CMDB + // Phoenix SLIC Pubkey/Marker + // Intel uCode + + // Padding + outerPadding += volumeBody.at(storeOffset); + } + + // Add padding at the very end + if (!outerPadding.isEmpty()) { + // Add info + UString info = usprintf("Full size: %Xh (%u)", (UINT32)outerPadding.size(), (UINT32)outerPadding.size()); + // Add tree item + model->addItem(localOffset + previousStoreEndOffset, Types::Padding, getPaddingType(outerPadding), UString("Padding"), UString(), info, UByteArray(), outerPadding, UByteArray(), Fixed, index); } return U_SUCCESS; diff --git a/common/utility.cpp b/common/utility.cpp index 2152ccb..ec66bb2 100755 --- a/common/utility.cpp +++ b/common/utility.cpp @@ -369,8 +369,6 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp } } - - // 8bit sum calculation routine UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize) { @@ -573,3 +571,12 @@ USTATUS zlibDecompress(const UByteArray& input, UByteArray& output) inflateEnd(&stream); return ret == Z_STREAM_END ? U_SUCCESS : U_ZLIB_DECOMPRESSION_FAILED; } + +UString fourCC(const UINT32 value) +{ + const UINT8 byte0 = (const UINT8)(value & 0xFF); + const UINT8 byte1 = (const UINT8)((value & 0xFF00) >> 8); + const UINT8 byte2 = (const UINT8)((value & 0xFF0000) >> 16); + const UINT8 byte3 = (const UINT8)((value & 0xFF000000) >> 24); + return usprintf("%c%c%c%c", byte0, byte1, byte2, byte3); +} diff --git a/common/utility.h b/common/utility.h index 4529774..505d217 100755 --- a/common/utility.h +++ b/common/utility.h @@ -23,6 +23,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "treemodel.h" #include "parsingdata.h" +// Returns text representation of 4CC value +UString fourCC(const UINT32 value); + // Returns bytes as string when all bytes are ascii visible, hex representation otherwise UString visibleAsciiOrHex(UINT8* bytes, UINT32 length);