mirror of
https://github.com/LongSoft/UEFITool.git
synced 2025-05-13 14:44:47 -04:00
Add Insyde Flash Device Map parser
This commit is contained in:
parent
0b66c5c7ff
commit
b3c68b7006
28 changed files with 1361 additions and 230 deletions
|
@ -35,6 +35,10 @@
|
|||
#include "digest/sha2.h"
|
||||
#include "digest/sm3.h"
|
||||
|
||||
#include "umemstream.h"
|
||||
#include "kaitai/kaitaistream.h"
|
||||
#include "generated/insyde_fdm.h"
|
||||
|
||||
// Constructor
|
||||
FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel),
|
||||
imageBase(0), addressDiff(0x100000000ULL), protectedRegionsBase(0) {
|
||||
|
@ -948,6 +952,114 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
|
|||
msg(usprintf("%s: BPDT store parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
|
||||
}
|
||||
}
|
||||
else if (itemType == Types::InsydeFlashDeviceMapStore) {
|
||||
UByteArray fdm = data.mid(itemOffset, itemSize);
|
||||
umemstream is(fdm.constData(), fdm.size());
|
||||
kaitai::kstream ks(&is);
|
||||
insyde_fdm_t parsed(&ks);
|
||||
UINT32 storeSize = (UINT32)fdm.size();
|
||||
|
||||
// Construct header and body
|
||||
UByteArray header = fdm.left(parsed.data_offset());
|
||||
UByteArray body = fdm.mid(header.size(), storeSize - header.size());
|
||||
|
||||
// Add info
|
||||
UString name = UString("Insyde H2O FlashDeviceMap");
|
||||
UString info = usprintf("Signature: HFDM\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nData offset: %Xh\nEntry size: %Xh (%u)\nEntry format: %02Xh\nRevision: %02Xh\nExtension count: %u\nFlash descriptor base address: %08Xh\nChecksum: %02Xh",
|
||||
storeSize, storeSize,
|
||||
(UINT32)header.size(), (UINT32)header.size(),
|
||||
(UINT32)body.size(), (UINT32)body.size(),
|
||||
parsed.data_offset(),
|
||||
parsed.entry_size(), parsed.entry_size(),
|
||||
parsed.entry_format(),
|
||||
parsed.revision(),
|
||||
parsed.num_extensions(),
|
||||
(UINT32)parsed.fd_base_address(),
|
||||
parsed.checksum());
|
||||
|
||||
// Check header checksum
|
||||
{
|
||||
UByteArray tempHeader = data.mid(itemOffset, sizeof(INSYDE_FLASH_DEVICE_MAP_HEADER));
|
||||
INSYDE_FLASH_DEVICE_MAP_HEADER* tempFdmHeader = (INSYDE_FLASH_DEVICE_MAP_HEADER*)tempHeader.data();
|
||||
tempFdmHeader->Checksum = 0;
|
||||
UINT8 calculated = calculateChecksum8((const UINT8*)tempFdmHeader, (UINT32)tempHeader.size());
|
||||
if (calculated == parsed.checksum()) {
|
||||
info += UString(", valid");
|
||||
}
|
||||
else {
|
||||
info += usprintf(", invalid, should be %02Xh", calculated);
|
||||
}
|
||||
}
|
||||
|
||||
// Add board IDs
|
||||
if (parsed.revision() == 3) {
|
||||
info += usprintf("\nRegion index: %Xh\nBoardId Count: %u",
|
||||
parsed.board_ids()->region_index(),
|
||||
parsed.board_ids()->num_board_ids());
|
||||
UINT32 i = 0;
|
||||
for (const auto & boardId : *parsed.board_ids()->board_ids()) {
|
||||
info += usprintf("\nBoardId #%u: %" PRIX64 "\n", i++, boardId);
|
||||
}
|
||||
}
|
||||
|
||||
// Add header tree item
|
||||
UModelIndex headerIndex = model->addItem(headerSize + itemOffset, Types::InsydeFlashDeviceMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, index);
|
||||
|
||||
// Add entries
|
||||
UINT32 entryOffset = parsed.data_offset();
|
||||
bool protectedRangeFound = false;
|
||||
for (const auto & entry : *parsed.entries()->entries()) {
|
||||
const EFI_GUID guid = readUnaligned((const EFI_GUID*)entry->guid().c_str());
|
||||
name = insydeFlashDeviceMapEntryTypeGuidToUString(guid);
|
||||
UString text;
|
||||
header = data.mid(itemOffset + entryOffset, sizeof(INSYDE_FLASH_DEVICE_MAP_ENTRY));
|
||||
body = data.mid(itemOffset + entryOffset + header.size(), parsed.entry_size() - header.size());
|
||||
|
||||
// Add info
|
||||
UINT32 entrySize = (UINT32)header.size() + (UINT32)body.size();
|
||||
info = UString("Region type: ") + guidToUString(guid, false) + "\n";
|
||||
info += UString("Region id: ");
|
||||
for (UINT8 i = 0; i < 16; i++) {
|
||||
info += usprintf("%02X", *(const UINT8*)(entry->region_id().c_str() + i));
|
||||
}
|
||||
info += usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nRegion address: %08Xh\nRegion size: %08Xh\nAttributes: %08Xh",
|
||||
entrySize, entrySize,
|
||||
(UINT32)header.size(), (UINT32)header.size(),
|
||||
(UINT32)body.size(), (UINT32)body.size(),
|
||||
(UINT32)entry->region_base(),
|
||||
(UINT32)entry->region_size(),
|
||||
entry->attributes());
|
||||
|
||||
if ((entry->attributes() & INSYDE_FLASH_DEVICE_MAP_ENTRY_ATTRIBUTE_MODIFIABLE) == 0) {
|
||||
if (!protectedRangeFound) {
|
||||
securityInfo += usprintf("Insyde Flash Device Map found at base %08Xh\nProtected ranges:\n", model->base(headerIndex));
|
||||
protectedRangeFound = true;
|
||||
}
|
||||
|
||||
// TODO: make sure that the only hash possible here is SHA256
|
||||
|
||||
// Add this region to the list of Insyde protected regions
|
||||
PROTECTED_RANGE range = {};
|
||||
range.Offset = (UINT32)entry->region_base();
|
||||
range.Size = (UINT32)entry->region_size();
|
||||
range.AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256;
|
||||
range.Type = PROTECTED_RANGE_VENDOR_HASH_INSYDE;
|
||||
range.Hash = body;
|
||||
protectedRanges.push_back(range);
|
||||
|
||||
securityInfo += usprintf("Address: %08Xh Size: %Xh\nHash: ", range.Offset, range.Size) + UString(body.toHex().constData()) + "\n";
|
||||
}
|
||||
|
||||
// Add tree item
|
||||
model->addItem(entryOffset, Types::InsydeFlashDeviceMapEntry, 0, name, text, info, header, body, UByteArray(), Fixed, headerIndex);
|
||||
|
||||
entryOffset += entrySize;
|
||||
}
|
||||
|
||||
if (protectedRangeFound) {
|
||||
securityInfo += "\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
return U_UNKNOWN_ITEM_TYPE;
|
||||
}
|
||||
|
@ -992,6 +1104,9 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
|
|||
case Types::BpdtPartition:
|
||||
// Parsing already done
|
||||
break;
|
||||
case Types::InsydeFlashDeviceMapStore:
|
||||
// Parsing already done
|
||||
break;
|
||||
case Types::Padding:
|
||||
// No parsing required
|
||||
break;
|
||||
|
@ -1293,7 +1408,7 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
|
|||
for (; offset < dataSize - sizeof(UINT32); offset++) {
|
||||
const UINT32* currentPos = (const UINT32*)(data.constData() + offset);
|
||||
UINT32 restSize = dataSize - offset;
|
||||
if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
|
||||
if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) { // Intel microcode
|
||||
// Check data size
|
||||
if (restSize < sizeof(INTEL_MICROCODE_HEADER)) {
|
||||
continue;
|
||||
|
@ -1415,6 +1530,28 @@ continue_searching: {}
|
|||
nextItemOffset = offset;
|
||||
break;
|
||||
}
|
||||
else if (readUnaligned(currentPos) == INSYDE_FLASH_DEVICE_MAP_SIGNATURE) {
|
||||
// Check data size
|
||||
if (restSize < sizeof(INSYDE_FLASH_DEVICE_MAP_HEADER))
|
||||
continue;
|
||||
|
||||
const INSYDE_FLASH_DEVICE_MAP_HEADER *fdmHeader = (const INSYDE_FLASH_DEVICE_MAP_HEADER *)currentPos;
|
||||
|
||||
if (restSize < fdmHeader->Size)
|
||||
continue;
|
||||
|
||||
if (fdmHeader->Revision > 3) {
|
||||
msg(usprintf("%s: Insyde Flash Device Map candidate with unknown revision %u", __FUNCTION__, fdmHeader->Revision), index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// All checks passed, FDM found
|
||||
nextItemType = Types::InsydeFlashDeviceMapStore;
|
||||
nextItemSize = fdmHeader->Size;
|
||||
nextItemAlternativeSize = fdmHeader->Size;
|
||||
nextItemOffset = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No more stores found
|
||||
|
@ -3764,6 +3901,26 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
|
|||
// Do nothing, this range is likely not found in the image
|
||||
}
|
||||
}
|
||||
else if (protectedRanges[i].Type == PROTECTED_RANGE_VENDOR_HASH_INSYDE) {
|
||||
try {
|
||||
protectedRanges[i].Offset -= (UINT32)addressDiff;
|
||||
protectedParts = openedImage.mid(protectedRanges[i].Offset, protectedRanges[i].Size);
|
||||
|
||||
UByteArray digest(SHA256_HASH_SIZE, '\x00');
|
||||
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
|
||||
|
||||
if (digest != protectedRanges[i].Hash) {
|
||||
msg(usprintf("%s: Insyde protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__,
|
||||
protectedRanges[i].Offset, protectedRanges[i].Offset + protectedRanges[i].Size),
|
||||
model->findByBase(protectedRanges[i].Offset));
|
||||
}
|
||||
|
||||
markProtectedRangeRecursive(index, protectedRanges[i]);
|
||||
}
|
||||
catch(...) {
|
||||
// Do nothing, this range is likely not found in the image
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue