UEFITool/common/nvramparser.cpp

1843 lines
85 KiB
C++
Raw Normal View History

/* nvramparser.cpp
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
2023-02-20 04:24:20 +08:00
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
2016-11-03 03:40:38 +08:00
#include <map>
#include "nvramparser.h"
#include "parsingdata.h"
2023-02-20 04:24:20 +08:00
#include "ustring.h"
#include "utility.h"
#include "nvram.h"
#include "ffs.h"
#include "intel_microcode.h"
2023-02-20 04:24:20 +08:00
#include "umemstream.h"
#include "kaitai/kaitaistream.h"
#include "generated/ami_nvar.h"
USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
{
// Sanity check
if (!index.isValid())
return U_INVALID_PARAMETER;
2023-02-20 04:24:20 +08:00
UByteArray nvar = model->body(index);
// Nothing to parse in an empty store
if (nvar.isEmpty())
return U_SUCCESS;
try {
const UINT32 localOffset = (UINT32)model->header(index).size();
umemstream is(nvar.constData(), nvar.size());
kaitai::kstream ks(&is);
ami_nvar_t parsed(&ks);
UINT16 guidsInStore = 0;
UINT32 currentEntryIndex = 0;
for (const auto & entry : *parsed.entries()) {
UINT8 subtype = Subtypes::FullNvarEntry;
UString name;
UString text;
UString info;
UString guid;
UByteArray header;
UByteArray body;
UByteArray tail;
// This is a terminating entry, needs special processing
if (entry->_is_null_signature_rest()) {
UINT32 guidAreaSize = guidsInStore * sizeof(EFI_GUID);
UINT32 unparsedSize = (UINT32)nvar.size() - entry->offset() - guidAreaSize;
// Check if the data left is a free space or a padding
UByteArray padding = nvar.mid(entry->offset(), unparsedSize);
// Get info
UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
if ((UINT32)padding.count(0xFF) == unparsedSize) { // Free space
// Add tree item
model->addItem(localOffset + entry->offset(), Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
}
2023-02-20 04:24:20 +08:00
else {
// Nothing is parsed yet, but the file is not empty
if (entry->offset() == 0) {
msg(usprintf("%s: file can't be parsed as NVAR variable store", __FUNCTION__), index);
return U_SUCCESS;
}
// Add tree item
model->addItem(localOffset + entry->offset(), Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
}
// Add GUID store area
UByteArray guidArea = nvar.right(guidAreaSize);
// Get info
name = UString("GUID store");
info = usprintf("Full size: %Xh (%u)\nGUIDs in store: %u",
(UINT32)guidArea.size(), (UINT32)guidArea.size(),
guidsInStore);
2016-10-28 00:31:15 +08:00
// Add tree item
2023-02-20 04:24:20 +08:00
model->addItem((UINT32)(localOffset + entry->offset() + padding.size()), Types::NvarGuidStore, 0, name, UString(), info, UByteArray(), guidArea, UByteArray(), Fixed, index);
return U_SUCCESS;
}
2023-02-20 04:24:20 +08:00
// This is a normal entry
const auto entry_body = entry->body();
// Set default next to predefined last value
NVAR_ENTRY_PARSING_DATA pdata = {};
pdata.emptyByte = 0xFF;
pdata.next = 0xFFFFFF;
pdata.isValid = TRUE;
// Check for invalid entry
if (!entry->attributes()->valid()) {
subtype = Subtypes::InvalidNvarEntry;
name = UString("Invalid");
pdata.isValid = FALSE;
goto processing_done;
}
2023-02-20 04:24:20 +08:00
// Check for link entry
if (entry->next() != 0xFFFFFF) {
subtype = Subtypes::LinkNvarEntry;
pdata.next = (UINT32)entry->next();
}
2023-02-20 04:24:20 +08:00
// Check for data-only entry (nameless and GUIDless entry or link)
if (entry->attributes()->data_only()) {
// Search backwards for a previous entry with a link to this variable
UModelIndex prevEntryIndex;
if (currentEntryIndex > 0) {
for (UINT32 i = currentEntryIndex - 1; i > 0; i--) {
const auto & previousEntry = parsed.entries()->at(i);
2023-02-20 04:24:20 +08:00
if (previousEntry == entry)
break;
2023-02-20 04:38:35 +08:00
if ((UINT32)previousEntry->next() + (UINT32)previousEntry->offset() == (UINT32)entry->offset()) { // Previous link is present and valid
2023-02-20 04:24:20 +08:00
prevEntryIndex = index.model()->index(i, 0, index);
// Make sure that we are linking to a valid entry
NVAR_ENTRY_PARSING_DATA pd = readUnaligned((NVAR_ENTRY_PARSING_DATA*)model->parsingData(prevEntryIndex).constData());
if (!pd.isValid) {
prevEntryIndex = UModelIndex();
}
break;
}
}
}
2023-02-20 04:24:20 +08:00
// Check if the link is valid
if (prevEntryIndex.isValid()) {
// Use the name and text of the previous entry
name = model->name(prevEntryIndex);
text = model->text(prevEntryIndex);
if (entry->next() == 0xFFFFFF)
subtype = Subtypes::DataNvarEntry;
}
2023-02-20 04:24:20 +08:00
else {
subtype = Subtypes::InvalidLinkNvarEntry;
name = UString("InvalidLink");
pdata.isValid = FALSE;
}
2023-02-20 04:24:20 +08:00
goto processing_done;
}
2023-02-20 04:24:20 +08:00
// Obtain text
if (!entry_body->_is_null_ascii_name()) {
text = entry_body->ascii_name().c_str();
}
2023-02-20 04:24:20 +08:00
else if (!entry_body->_is_null_ucs2_name()) {
UByteArray temp;
for (const auto & ch : *entry_body->ucs2_name()->ucs2_chars()) {
temp += UByteArray((const char*)&ch, sizeof(ch));
}
text = uFromUcs2(temp.constData());
}
2023-02-20 04:24:20 +08:00
// Obtain GUID
if (!entry_body->_is_null_guid()) { // GUID is stored in the entry itself
name = guidToUString(entry_body->guid().c_str());
guid = guidToUString(entry_body->guid().c_str(), false);
}
2023-02-20 04:24:20 +08:00
else { // GUID is stored in GUID store at the end of the NVAR store
// Grow the GUID store if needed
if (guidsInStore < entry_body->guid_index() + 1)
guidsInStore = entry_body->guid_index() + 1;
// The list begins at the end of the store and goes backwards
const char *g = (nvar.constData() + nvar.size()) - (entry_body->guid_index() + 1);
2023-02-20 04:24:20 +08:00
name = guidToUString(g);
guid = guidToUString(g, false);
}
2023-02-20 04:24:20 +08:00
processing_done:
// This feels hacky, but I haven't found a way to ask Kaitai for raw bytes
header = nvar.mid(entry->offset(), sizeof(NVAR_ENTRY_HEADER) + entry_body->data_start_offset());
body = nvar.mid(entry->offset() + sizeof(NVAR_ENTRY_HEADER) + entry_body->data_start_offset(), entry_body->data_size());
tail = nvar.mid(entry->end_offset() - entry_body->extended_header_size(), entry_body->extended_header_size());
// Add GUID info for valid entries
if (!guid.isEmpty())
info += UString("Variable GUID: ") + guid + "\n";
// Add GUID index information
if (!entry_body->_is_null_guid_index())
info += usprintf("GUID index: %u\n", entry_body->guid_index());
// Add header, body and extended data info
info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)",
entry->size(), entry->size(),
(UINT32)header.size(), (UINT32)header.size(),
(UINT32)body.size(), (UINT32)body.size(),
(UINT32)tail.size(), (UINT32)tail.size());
// Add attributes info
const NVAR_ENTRY_HEADER entryHeader = readUnaligned((NVAR_ENTRY_HEADER*)header.constData());
info += usprintf("\nAttributes: %02Xh", entryHeader.Attributes);
// Translate attributes to text
if (entryHeader.Attributes != 0x00 && entryHeader.Attributes != 0xFF)
info += UString(" (") + nvarAttributesToUString(entryHeader.Attributes) + UString(")");
// Add next node info
if (entry->next() != 0xFFFFFF)
info += usprintf("\nNext node at offset: %Xh", localOffset + entry->offset() + (UINT32)entry->next());
// Add extended header info
if (entry_body->extended_header_size() > 0) {
info += usprintf("\nExtended header size: %Xh (%u)",
entry_body->extended_header_size(), entry_body->extended_header_size());
const UINT8 extendedAttributes = *tail.constData();
info += usprintf("\nExtended attributes: %02Xh (", extendedAttributes) + nvarExtendedAttributesToUString(extendedAttributes) + UString(")");
// Add checksum
if (!entry_body->_is_null_extended_header_checksum()) {
UINT8 calculatedChecksum = 0;
UByteArray wholeBody = body + tail;
// Include entry body
UINT8* start = (UINT8*)wholeBody.constData();
for (UINT8* p = start; p < start + wholeBody.size(); p++) {
calculatedChecksum += *p;
}
// Include entry size and flags
start = (UINT8*)&entryHeader.Size;
for (UINT8*p = start; p < start + sizeof(UINT16); p++) {
calculatedChecksum += *p;
}
// Include entry attributes
calculatedChecksum += entryHeader.Attributes;
info += usprintf("\nChecksum: %02Xh, ", entry_body->extended_header_checksum())
+ (calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid"));
}
// Add timestamp
if (!entry_body->_is_null_extended_header_timestamp())
info += usprintf("\nTimestamp: %" PRIX64 "h", entry_body->extended_header_timestamp());
// Add hash
if (!entry_body->_is_null_extended_header_hash()) {
UByteArray hash = UByteArray(entry_body->extended_header_hash().c_str(), entry_body->extended_header_hash().size());
info += UString("\nHash: ") + UString(hash.toHex().constData());
}
}
// Add tree item
UModelIndex varIndex = model->addItem(localOffset + entry->offset(), Types::NvarEntry, subtype, name, text, info, header, body, tail, Fixed, index);
currentEntryIndex++;
// Set parsing data
model->setParsingData(varIndex, UByteArray((const char*)&pdata, sizeof(pdata)));
// Try parsing the entry data as NVAR storage if it begins with NVAR signature
if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry)
&& body.size() >= 4 && readUnaligned((const UINT32*)body.constData()) == NVRAM_NVAR_ENTRY_SIGNATURE)
(void)parseNvarStore(varIndex);
}
}
2023-02-20 04:24:20 +08:00
catch (...) {
msg(usprintf("%s: unable to parse AMI NVAR storage", __FUNCTION__), index);
return U_INVALID_STORE;
}
return U_SUCCESS;
}
USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index)
{
// Sanity check
if (!index.isValid())
return U_INVALID_PARAMETER;
2016-10-28 00:31:15 +08:00
// Obtain required fields from parsing data
UINT8 emptyByte = 0xFF;
if (model->hasEmptyParsingData(index) == false) {
UByteArray data = model->parsingData(index);
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
emptyByte = pdata->emptyByte;
}
2016-10-28 00:31:15 +08:00
// Get local offset
UINT32 localOffset = (UINT32)model->header(index).size();
// Get item data
UByteArray data = model->body(index);
// Search for first store
USTATUS result;
UINT32 prevStoreOffset;
2016-10-28 00:31:15 +08:00
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
2016-10-28 00:31:15 +08:00
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;
2016-12-04 06:36:01 +08:00
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
2016-10-28 00:31:15 +08:00
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) {
2018-04-30 13:33:19 +08:00
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
2016-10-28 00:31:15 +08:00
UModelIndex paddingIndex = model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
2018-04-30 13:33:19 +08:00
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;
2016-10-28 00:31:15 +08:00
UByteArray store = data.mid(storeOffset, storeSize);
result = parseStoreHeader(store, localOffset + storeOffset, index, storeIndex);
if (result)
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: store header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
// Go to next store
prevStoreOffset = storeOffset;
prevStoreSize = storeSize;
2016-10-28 00:31:15 +08:00
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);
2016-10-28 00:31:15 +08:00
// Add info
info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
2016-10-28 00:31:15 +08:00
if (padding.count(emptyByte) == padding.size()) { // Free space
// Add tree item
2019-01-07 21:05:57 +08:00
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) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: can't be parsed as NVRAM volume", __FUNCTION__), index);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
// 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;
}
2016-10-28 00:31:15 +08:00
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) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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
2017-07-31 14:06:11 +08:00
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
2017-07-31 14:06:11 +08:00
continue;
const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)currentPos;
2017-07-31 14:06:11 +08:00
if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index);
2017-07-31 14:06:11 +08:00
continue;
}
if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, vssHeader->Size), index);
2017-07-31 14:06:11 +08:00
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) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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
2022-08-25 12:49:10 +08:00
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;
}
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;
2017-07-31 14:06:11 +08:00
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;
2019-02-02 00:45:39 +08:00
} else {
return U_INVALID_PARAMETER; // Unreachable
}
return U_SUCCESS;
}
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
}
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
USTATUS NvramParser::parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index)
2017-07-31 14:06:11 +08:00
{
const UINT32 dataSize = (UINT32)store.size();
2017-07-31 14:06:11 +08:00
// Check store size
if (dataSize < sizeof(VSS2_VARIABLE_STORE_HEADER)) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: volume body is too small even for VSS2 store header", __FUNCTION__), parent);
2017-07-31 14:06:11 +08:00
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;
}
2017-07-31 14:06:11 +08:00
// Check store size
if (dataSize < storeSize) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: VSS2 store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
storeSize, storeSize,
dataSize, dataSize), parent);
2017-07-31 14:06:11 +08:00
return U_SUCCESS;
}
2017-07-31 14:06:11 +08:00
// 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));
2017-07-31 14:06:11 +08:00
// Add info
UString name = UString("VSS2 store");
UString info = UString("Signature: ") + guidToUString((const char*)&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);
2017-07-31 14:06:11 +08:00
// Add tree item
index = model->addItem(localOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
2017-07-31 14:06:11 +08:00
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: volume body is too small even for FTW store header", __FUNCTION__), parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 emptyByte = 0xFF;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume);
2016-10-28 00:31:15 +08:00
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
UByteArray data = model->parsingData(parentVolumeIndex);
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
2016-12-04 06:36:01 +08:00
emptyByte = pdata->emptyByte;
2016-10-28 00:31:15 +08:00
}
// 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) {
2018-04-30 13:33:19 +08:00
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();
2016-10-28 00:31:15 +08:00
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((const char*)&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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: volume body is too small even for FDC store header", __FUNCTION__), parent);
return U_SUCCESS;
}
// Get Fdc store header
const FDC_VOLUME_HEADER* fdcStoreHeader = (const FDC_VOLUME_HEADER*)store.constData();
// Check store size
if (dataSize < fdcStoreHeader->Size) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::FsysStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::EvsaStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::FlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::CmdbStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::SlicData, Subtypes::PubkeySlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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) {
2018-04-30 13:33:19 +08:00
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");
2022-08-28 18:01:43 +08:00
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
2016-10-28 00:31:15 +08:00
index = model->addItem(localOffset, Types::SlicData, Subtypes::MarkerSlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
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)) {
2018-04-30 13:33:19 +08:00
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)
2016-10-28 00:31:15 +08:00
return parseFtwStoreHeader(store, localOffset, parent, index);
// FDC store
else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE)
2016-10-28 00:31:15 +08:00
return parseFdcStoreHeader(store, localOffset, parent, index);
// Apple Fsys/Gaid store
else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE)
2016-10-28 00:31:15 +08:00
return parseFsysStoreHeader(store, localOffset, parent, index);
// EVSA store
2018-04-30 13:33:19 +08:00
else if (dataSize >= 2 * sizeof(UINT32) && *(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE)
2016-10-28 00:31:15 +08:00
return parseEvsaStoreHeader(store, localOffset, parent, index);
// Phoenix SCT flash map
else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1)
2016-10-28 00:31:15 +08:00
return parseFlashMapStoreHeader(store, localOffset, parent, index);
// Phoenix CMDB store
else if (*signature == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE)
2016-10-28 00:31:15 +08:00
return parseCmdbStoreHeader(store, localOffset, parent, index);
// SLIC pubkey
2018-04-30 13:33:19 +08:00
else if (dataSize >= 5 * sizeof(UINT32) && *(signature + 4) == OEM_ACTIVATION_PUBKEY_MAGIC)
2016-10-28 00:31:15 +08:00
return parseSlicPubkeyHeader(store, localOffset, parent, index);
// SLIC marker
2018-04-30 13:33:19 +08:00
else if (dataSize >= 34 && *(const UINT64*)(store.constData() + 26) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG)
2016-10-28 00:31:15 +08:00
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()) {
2018-04-30 13:33:19 +08:00
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);
2018-04-30 13:33:19 +08:00
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);
}
2018-04-30 13:33:19 +08:00
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 {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: internal volume can't be parsed as VSS/VSS2 store", __FUNCTION__), index);
return U_SUCCESS;
}
}
2017-07-31 14:06:11 +08:00
USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment)
{
// Sanity check
if (!index.isValid())
return U_INVALID_PARAMETER;
2016-10-28 00:31:15 +08:00
// 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();
2016-12-04 06:36:01 +08:00
emptyByte = pdata->emptyByte;
2016-10-28 00:31:15 +08:00
}
2016-10-28 00:31:15 +08:00
// Get local offset
UINT32 localOffset = (UINT32)model->header(index).size();
2016-10-28 00:31:15 +08:00
// 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)) {
2018-04-30 13:33:19 +08:00
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;
2018-05-08 01:50:56 +08:00
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) {
2017-07-23 02:43:20 +08:00
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);
2016-10-28 00:31:15 +08:00
// Get info
UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size());
2016-10-28 00:31:15 +08:00
if (padding.count(emptyByte) == padding.size()) { // Free space
// Add tree item
2019-01-07 21:05:57 +08:00
model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
}
2016-10-28 00:31:15 +08:00
else { // Padding
// Nothing is parsed yet, but the store is not empty
if (!offset) {
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: store can't be parsed as VSS store", __FUNCTION__), index);
return U_SUCCESS;
}
2016-10-28 00:31:15 +08:00
// 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
2018-05-08 01:50:56 +08:00
if (isInvalid || !variableGuid) {
2018-05-09 00:33:00 +08:00
isInvalid = true;
name = UString("Invalid");
}
else { // Add GUID and text for valid variables
name = guidToUString((const char*)variableGuid);
info += UString("Variable GUID: ") + guidToUString((const char*)variableGuid, false) + "\n";
text = uFromUcs2((const char*)variableName);
}
// Add info
2022-08-28 18:01:43 +08:00
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
2019-01-07 21:05:57 +08:00
model->addItem(localOffset + offset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, index);
2017-07-31 14:06:11 +08:00
// 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;
2016-10-28 00:31:15 +08:00
// Get local offset
UINT32 localOffset = (UINT32)model->header(index).size();
2016-10-28 00:31:15 +08:00
// 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
2016-12-23 06:34:24 +08:00
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
2016-12-23 06:34:24 +08:00
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
2019-01-07 21:05:57 +08:00
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());
2016-10-28 00:31:15 +08:00
// Add padding tree item
model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
// Show message
2018-04-30 13:33:19 +08:00
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
2022-08-28 18:01:43 +08:00
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
2019-01-07 21:05:57 +08:00
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;
2016-10-28 00:31:15 +08:00
// 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();
2016-12-04 06:36:01 +08:00
emptyByte = pdata->emptyByte;
2016-10-28 00:31:15 +08:00
}
2016-10-28 00:31:15 +08:00
// Get local offset
UINT32 localOffset = (UINT32)model->header(index).size();
2016-10-28 00:31:15 +08:00
// 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<UINT16, EFI_GUID> guidMap;
std::map<UINT16, UString> 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());
2016-10-28 00:31:15 +08:00
if (body.count(emptyByte) == body.size()) { // Free space
// Add free space tree item
2019-01-07 21:05:57 +08:00
model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
}
2016-10-28 00:31:15 +08:00
else {
// Add padding tree item
UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
2016-10-28 00:31:15 +08:00
// Show message
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: variable parsing failed, the rest of unparsed store added as padding", __FUNCTION__), itemIndex);
2016-10-28 00:31:15 +08:00
}
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 = readUnaligned((EFI_GUID*)body.constData());
name = guidToUString(body.constData());
info = UString("GUID: ") + guidToUString(body.constData(), 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<UINT16, EFI_GUID>(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<UINT16, UString>(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());
2016-10-28 00:31:15 +08:00
if (body.count(emptyByte) == body.size()) { // Free space
// Add free space tree item
2019-01-07 21:05:57 +08:00
model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
}
2016-10-28 00:31:15 +08:00
else {
// Add padding tree item
UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
2016-10-28 00:31:15 +08:00
// Show message
2018-04-30 13:33:19 +08:00
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
2019-01-07 21:05:57 +08:00
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((const char*)&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"));
2018-04-30 13:33:19 +08:00
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"));
2018-04-30 13:33:19 +08:00
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"));
2018-04-30 13:33:19 +08:00
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());
2016-10-28 00:31:15 +08:00
// 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)
2018-04-30 13:33:19 +08:00
msg(usprintf("%s: next entry appears too big, added as padding", __FUNCTION__), index);
break;
}
UString name = guidToUString((const char*)&entryHeader->Guid);
// Construct header
UByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY));
// Add info
UString info = UString("Entry GUID: ") + guidToUString((const char*)&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
2019-01-07 21:05:57 +08:00
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