Initial ME parser, improved ucode parser, reset vector info

This commit is contained in:
Nikolaj Schlej 2019-07-24 10:30:59 -07:00
parent f386eda430
commit 2e7aa8133a
21 changed files with 1867 additions and 166 deletions

View file

@ -192,11 +192,24 @@ void UEFITool::populateUi(const QModelIndex &current)
ui->menuVolumeActions->setEnabled(type == Types::Volume);
ui->menuFileActions->setEnabled(type == Types::File);
ui->menuSectionActions->setEnabled(type == Types::Section);
ui->menuEntryActions->setEnabled(type == Types::NvarEntry
ui->menuEntryActions->setEnabled(type == Types::Microcode
|| type == Types::SlicData
|| type == Types::NvarEntry
|| type == Types::VssEntry
|| type == Types::FsysEntry
|| type == Types::EvsaEntry
|| type == Types::FlashMapEntry);
|| type == Types::FlashMapEntry
|| type == Types::IfwiHeader
|| type == Types::IfwiPartition
|| type == Types::FptPartition
|| type == Types::FptEntry
|| type == Types::BpdtPartition
|| type == Types::BpdtEntry
|| type == Types::CpdPartition
|| type == Types::CpdEntry
|| type == Types::CpdExtension
|| type == Types::CpdSpiEntry
);
ui->menuStoreActions->setEnabled(type == Types::VssStore
|| type == Types::Vss2Store
|| type == Types::FdcStore
@ -204,9 +217,11 @@ void UEFITool::populateUi(const QModelIndex &current)
|| type == Types::EvsaStore
|| type == Types::FtwStore
|| type == Types::FlashMapStore
|| type == Types::CmdbStore
|| type == Types::Microcode
|| type == Types::SlicData);
|| type == Types::CmdbStore
|| type == Types::FptStore
|| type == Types::BpdtStore
|| type == Types::CpdStore
);
// Enable actions
ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
@ -481,7 +496,7 @@ void UEFITool::extract(const UINT8 mode)
if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey to file"), name + ".spk", tr("SLIC pubkey files (*.spk *.bin);;All files (*)"));
else path = QFileDialog::getSaveFileName(this, tr("Save SLIC marker to file"), name + ".smk", tr("SLIC marker files (*.smk *.bin);;All files (*)"));
break;
default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)"));
default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)"));
}
}
else if (mode == EXTRACT_MODE_BODY || mode == EXTRACT_MODE_BODY_UNCOMPRESSED) {
@ -553,7 +568,7 @@ void UEFITool::remove()
void UEFITool::about()
{
QMessageBox::about(this, tr("About UEFITool"), tr(
"Copyright (c) 2018, LongSoft.<br>"
"Copyright (c) 2019, Nikolaj Schlej.<br>"
"Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br>"
"The program uses QHexEdit2 library made by <a href=https://github.com/Simsys/>Simsys</a>.<br>"
"Qt-less engine is using Bstrlib made by <a href=https://github.com/websnarf/>Paul Hsieh</a>.<br><br>"
@ -858,8 +873,11 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
case Types::EvsaStore:
case Types::FtwStore:
case Types::FlashMapStore:
case Types::CmdbStore: ui->menuStoreActions->exec(event->globalPos()); break;
case Types::FreeSpace: break;
case Types::CmdbStore:
case Types::FptStore:
case Types::CpdStore:
case Types::BpdtStore: ui->menuStoreActions->exec(event->globalPos()); break;
case Types::FreeSpace: break; // No menu needed for FreeSpace item
default: ui->menuEntryActions->exec(event->globalPos()); break;
}
}

View file

@ -5,6 +5,7 @@ TARGET = UEFITool
TEMPLATE = app
DEFINES += "U_ENABLE_FIT_PARSING_SUPPORT"
DEFINES += "U_ENABLE_NVRAM_PARSING_SUPPORT"
DEFINES += "U_ENABLE_ME_PARSING_SUPPORT"
DEFINES += "U_ENABLE_GUID_DATABASE_SUPPORT"
HEADERS += uefitool.h \
@ -70,6 +71,7 @@ SOURCES += uefitool_main.cpp \
../common/guiddatabase.cpp \
../common/nvram.cpp \
../common/nvramparser.cpp \
../common/meparser.cpp \
../common/ffsops.cpp \
../common/types.cpp \
../common/descriptor.cpp \

View file

@ -711,10 +711,6 @@ Decode (
UINT32 DataIdx;
UINT16 CharC;
BytesRemain = (UINT16)(-1);
DataIdx = 0;
for (;;) {
//
// Get one code from mBitBuf

View file

@ -68,6 +68,19 @@ typedef size_t USTATUS;
#define U_INVALID_BG_BOOT_POLICY 46
#define U_INVALID_TXT_CONF 47
#define U_ELEMENTS_NOT_FOUND 48
#define U_PEI_CORE_ENTRY_POINT_NOT_FOUND 49
#define U_INVALID_STORE_SIZE 50
#define U_UNKNOWN_COMPRESSION_ALGORITHM 51
#define U_NOTHING_TO_PATCH 52
#define U_UNKNOWN_PATCH_TYPE 53
#define U_PATCH_OFFSET_OUT_OF_BOUNDS 54
#define U_INVALID_SYMBOL 55
#define U_INVALID_MANIFEST 251
#define U_UNKNOWN_MANIFEST_HEADER_VERSION 252
#define U_INVALID_ME_PARTITION_TABLE 253
#define U_INVALID_ME_PARTITION 254
#define U_NOT_IMPLEMENTED 0xFF
// EDK2 porting definitions

View file

@ -39,16 +39,16 @@ const UINT8 ffsAlignment2Table[] =
VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
{
ffsSize[2] = (UINT8)((size) >> 16);
ffsSize[1] = (UINT8)((size) >> 8);
ffsSize[2] = (UINT8)((size) >> 16U);
ffsSize[1] = (UINT8)((size) >> 8U);
ffsSize[0] = (UINT8)((size));
}
UINT32 uint24ToUint32(const UINT8* ffsSize)
{
return (UINT32) ffsSize[0]
+ ((UINT32) ffsSize[1] << 8U)
+ ((UINT32) ffsSize[2] << 16U);
+ ((UINT32) ffsSize[1] << 8U)
+ ((UINT32) ffsSize[2] << 16U);
}
UString guidToUString(const EFI_GUID & guid, bool convertToString)
@ -84,17 +84,17 @@ bool ustringToGuid(const UString & str, EFI_GUID & guid)
if (err == 0)
return false;
guid.Data1 = p0;
guid.Data2 = p1;
guid.Data3 = p2;
guid.Data4[0] = p3;
guid.Data4[1] = p4;
guid.Data4[2] = p5;
guid.Data4[3] = p6;
guid.Data4[4] = p7;
guid.Data4[5] = p8;
guid.Data4[6] = p9;
guid.Data4[7] = p10;
guid.Data1 = (UINT32)p0;
guid.Data2 = (UINT16)p1;
guid.Data3 = (UINT16)p2;
guid.Data4[0] = (UINT8)p3;
guid.Data4[1] = (UINT8)p4;
guid.Data4[2] = (UINT8)p5;
guid.Data4[3] = (UINT8)p6;
guid.Data4[4] = (UINT8)p7;
guid.Data4[5] = (UINT8)p8;
guid.Data4[6] = (UINT8)p9;
guid.Data4[7] = (UINT8)p10;
return true;
}

View file

@ -571,6 +571,21 @@ typedef struct POSTCODE_SECTION_ {
///
#define EFI_DEP_SOR 0x09
//*****************************************************************************
// X86 Reset Vector Data
//*****************************************************************************
typedef struct X86_RESET_VECTOR_DATA_ {
UINT8 ApEntryVector[8]; // Base: 0xffffffd0
UINT8 Reserved0[8];
UINT32 PeiCoreEntryPoint; // Base: 0xffffffe0
UINT8 Reserved1[12];
UINT8 ResetVector[8]; // Base: 0xfffffff0
UINT32 ApStartupSegment; // Base: 0xfffffff8
UINT32 BootFvBaseAddress; // Base: 0xfffffffc
} X86_RESET_VECTOR_DATA;
#define X86_RESET_VECTOR_DATA_UNPOPULATED 0x12345678
// Restore previous packing rules
#pragma pack(pop)

View file

@ -120,7 +120,7 @@ USTATUS FfsParser::parse(const UByteArray & buffer)
USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & index)
{
// Sanity check
// Sanity check
if (buffer.isEmpty()) {
return EFI_INVALID_PARAMETER;
}
@ -756,7 +756,7 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs
// Parse PDR region as BIOS space
USTATUS result = parseRawArea(index);
if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME)
if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME && result != U_STORES_NOT_FOUND)
return result;
return U_SUCCESS;
@ -910,8 +910,8 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
prevItemType = itemType;
result = findNextRawAreaItem(index, itemOffset + prevItemSize, itemType, itemOffset, itemSize, itemAltSize);
// Silence value not used after assignment warning
(void)prevItemType;
// Silence value not used after assignment warning
(void)prevItemType;
}
// Padding at the end of RAW area
@ -1058,7 +1058,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
UINT32 usedSpace = *(UINT32*)(volume.constData() + 12);
if (appleCrc32 != 0) {
// Calculate CRC32 of the volume body
UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
UINT32 crc = (UINT32)crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
if (crc == appleCrc32) {
hasAppleCrc32 = true;
}
@ -1161,26 +1161,34 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
for (; offset < dataSize - sizeof(UINT32); offset++) {
const UINT32* currentPos = (const UINT32*)(data.constData() + offset);
const UINT32 restSize = dataSize - offset;
if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION) {// Intel microcode
if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
// Check data size
if (restSize < sizeof(INTEL_MICROCODE_HEADER))
continue;
// Check microcode size
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
if (!INTEL_MICROCODE_HEADER_SIZES_VALID(currentPos) || restSize < ucodeHeader->TotalSize) //TODO: needs a separate checking function
continue;
// Check reserved bytes
bool reservedBytesValid = true;
for (UINT32 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
if (ucodeHeader->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
if (ucodeHeader->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
if (!reservedBytesValid)
continue;
// Data size is multiple of 4
if (ucodeHeader->DataSize % 4 != 0) {
continue;
}
// TotalSize is greater then DataSize and is multiple of 1024
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
continue;
}
// All checks passed, microcode found
nextItemType = Types::Microcode;
nextItemSize = ucodeHeader->TotalSize;
@ -1442,7 +1450,6 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
if (file.isEmpty()) {
return U_INVALID_PARAMETER;
}
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER)) {
return U_INVALID_FILE;
}
@ -1480,14 +1487,16 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
}
UINT32 alignment = (UINT32)(1UL << alignmentPower);
if ((localOffset + header.size()) % alignment)
if ((localOffset + header.size()) % alignment) {
msgUnalignedFile = true;
}
// Check file alignment agains volume alignment
bool msgFileAlignmentIsGreaterThanVolumeAlignment = false;
if (!isWeakAligned && volumeAlignment < alignment)
if (!isWeakAligned && volumeAlignment < alignment) {
msgFileAlignmentIsGreaterThanVolumeAlignment = true;
}
// Get file body
UByteArray body = file.mid(header.size());
@ -1508,9 +1517,10 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
// Check header checksum
UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
bool msgInvalidHeaderChecksum = false;
if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader)
if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader) {
msgInvalidHeaderChecksum = true;
}
// Check data checksum
// Data checksum must be calculated
bool msgInvalidDataChecksum = false;
@ -1526,9 +1536,10 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
calculatedData = FFS_FIXED_CHECKSUM2;
}
if (fileHeader->IntegrityCheck.Checksum.File != calculatedData)
if (fileHeader->IntegrityCheck.Checksum.File != calculatedData) {
msgInvalidDataChecksum = true;
}
// Check file type
bool msgUnknownType = false;
if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) {
@ -1663,19 +1674,16 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index)
model->setText(index, UString("NVAR store"));
return nvramParser->parseNvarStore(index);
}
if (fileGuid == NVRAM_NVAR_PEI_EXTERNAL_DEFAULTS_FILE_GUID) {
else if (fileGuid == NVRAM_NVAR_PEI_EXTERNAL_DEFAULTS_FILE_GUID) {
model->setText(index, UString("NVRAM external defaults"));
return nvramParser->parseNvarStore(index);
}
if (fileGuid == NVRAM_NVAR_BB_DEFAULTS_FILE_GUID) {
else if (fileGuid == NVRAM_NVAR_BB_DEFAULTS_FILE_GUID) {
model->setText(index, UString("NVAR bb defaults"));
return nvramParser->parseNvarStore(index);
}
// Parse vendor hash file
if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) {
else if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) {
return parseVendorHashFile(fileGuid, index);
}
@ -2081,7 +2089,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI
UINT32 crc = *(UINT32*)(section.constData() + headerSize);
additionalInfo += UString("\nChecksum type: CRC32");
// Calculate CRC32 of section data
UINT32 calculated = crc32(0, (const UINT8*)section.constData() + dataOffset, section.size() - dataOffset);
UINT32 calculated = (UINT32)crc32(0, (const UINT8*)section.constData() + dataOffset, section.size() - dataOffset);
if (crc == calculated) {
additionalInfo += usprintf("\nChecksum: %08Xh, valid", crc);
}
@ -2995,6 +3003,9 @@ USTATUS FfsParser::performSecondPass(const UModelIndex & index)
const UINT32 vtfSize = model->header(lastVtf).size() + model->body(lastVtf).size() + model->tail(lastVtf).size();
addressDiff = 0xFFFFFFFFULL - model->base(lastVtf) - vtfSize + 1;
// Parse reset vector data
parseResetVectorData();
// Find and parse FIT
parseFit(index);
@ -3007,6 +3018,37 @@ USTATUS FfsParser::performSecondPass(const UModelIndex & index)
return U_SUCCESS;
}
USTATUS FfsParser::parseResetVectorData()
{
// Sanity check
if (!lastVtf.isValid())
return U_SUCCESS;
// Check VTF to have enough space at the end to fit Reset Vector Data
UByteArray vtf = model->header(lastVtf) + model->body(lastVtf) + model->tail(lastVtf);
if ((UINT32)vtf.size() < sizeof(X86_RESET_VECTOR_DATA))
return U_SUCCESS;
const X86_RESET_VECTOR_DATA* resetVectorData = (const X86_RESET_VECTOR_DATA*)(vtf.constData() + vtf.size() - sizeof(X86_RESET_VECTOR_DATA));
// Add info
UString info = usprintf("\nAP entry vector: %02X %02X %02X %02X %02X %02X %02X %02X\n"
"Reset vector: %02X %02X %02X %02X %02X %02X %02X %02X\n"
"PEI core entry point: %08Xh\n"
"AP startup segment: %08X\n"
"BootFV base address: %08X\n",
resetVectorData->ApEntryVector[0], resetVectorData->ApEntryVector[1], resetVectorData->ApEntryVector[2], resetVectorData->ApEntryVector[3],
resetVectorData->ApEntryVector[4], resetVectorData->ApEntryVector[5], resetVectorData->ApEntryVector[6], resetVectorData->ApEntryVector[7],
resetVectorData->ResetVector[0], resetVectorData->ResetVector[1], resetVectorData->ResetVector[2], resetVectorData->ResetVector[3],
resetVectorData->ResetVector[4], resetVectorData->ResetVector[5], resetVectorData->ResetVector[6], resetVectorData->ResetVector[7],
resetVectorData->PeiCoreEntryPoint,
resetVectorData->ApStartupSegment,
resetVectorData->BootFvBaseAddress);
model->addInfo(lastVtf, info);
return U_SUCCESS;
}
USTATUS FfsParser::checkTeImageBase(const UModelIndex & index)
{
// Sanity check
@ -3618,13 +3660,13 @@ USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UI
}
const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(microcode.constData() + localOffset);
if (header->Version != INTEL_MICROCODE_HEADER_VERSION) {
if (header->Version != INTEL_MICROCODE_HEADER_VERSION_1) {
return U_INVALID_MICROCODE;
}
bool reservedBytesValid = true;
for (UINT8 i = 0; i < sizeof(header->Reserved); i++)
if (header->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
if (header->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
@ -3632,13 +3674,21 @@ USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UI
return U_INVALID_MICROCODE;
}
if (header->DataSize % 4 != 0) {
return U_INVALID_MICROCODE;
}
if (header->TotalSize <= header->DataSize || header->TotalSize % 1024 != 0) {
return U_INVALID_MICROCODE;
}
UINT32 mcSize = header->TotalSize;
if ((UINT32)microcode.size() < localOffset + mcSize) {
return U_INVALID_MICROCODE;
}
// Valid microcode found
info = usprintf("CPUID: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X",
info = usprintf("CpuSignature: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X",
header->CpuSignature,
header->Revision,
header->DateDay,
@ -3678,34 +3728,33 @@ USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOf
// Add ACM header info
UString acmInfo;
acmInfo += usprintf(
" found at base %Xh\n"
"ModuleType: %04Xh ModuleSubtype: %04Xh HeaderLength: %08Xh\n"
"HeaderVersion: %08Xh ChipsetId: %04Xh Flags: %04Xh\n"
"ModuleVendor: %04Xh Date: %02X.%02X.%04X ModuleSize: %08Xh\n"
"EntryPoint: %08Xh AcmSvn: %04Xh Unknown1: %08Xh\n"
"Unknown2: %08Xh GdtBase: %08Xh GdtMax: %08Xh\n"
"SegSel: %08Xh KeySize: %08Xh Unknown3: %08Xh",
model->base(parent) + localOffset,
header->ModuleType,
header->ModuleSubtype,
header->ModuleSize * sizeof(UINT32),
header->HeaderVersion,
header->ChipsetId,
header->Flags,
header->ModuleVendor,
header->DateDay, header->DateMonth, header->DateYear,
header->ModuleSize * sizeof(UINT32),
header->EntryPoint,
header->AcmSvn,
header->Unknown1,
header->Unknown2,
header->GdtBase,
header->GdtMax,
header->SegmentSel,
header->KeySize * sizeof(UINT32),
header->Unknown4 * sizeof(UINT32)
);
acmInfo += usprintf(" found at base %Xh\n"
"ModuleType: %04Xh ModuleSubtype: %04Xh HeaderLength: %08Xh\n"
"HeaderVersion: %08Xh ChipsetId: %04Xh Flags: %04Xh\n"
"ModuleVendor: %04Xh Date: %02X.%02X.%04X ModuleSize: %08Xh\n"
"EntryPoint: %08Xh AcmSvn: %04Xh Unknown1: %08Xh\n"
"Unknown2: %08Xh GdtBase: %08Xh GdtMax: %08Xh\n"
"SegSel: %08Xh KeySize: %08Xh Unknown3: %08Xh",
model->base(parent) + localOffset,
header->ModuleType,
header->ModuleSubtype,
header->ModuleSize * sizeof(UINT32),
header->HeaderVersion,
header->ChipsetId,
header->Flags,
header->ModuleVendor,
header->DateDay, header->DateMonth, header->DateYear,
header->ModuleSize * sizeof(UINT32),
header->EntryPoint,
header->AcmSvn,
header->Unknown1,
header->Unknown2,
header->GdtBase,
header->GdtMax,
header->SegmentSel,
header->KeySize * sizeof(UINT32),
header->Unknown4 * sizeof(UINT32)
);
// Add PubKey
acmInfo += usprintf("\n\nACM RSA Public Key (Exponent: %Xh):", header->RsaPubExp);
for (UINT16 i = 0; i < sizeof(header->RsaPubKey); i++) {
@ -4071,66 +4120,134 @@ USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index)
USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
{
const UINT32 dataSize = (const UINT32)microcode.size();
if (dataSize < sizeof(INTEL_MICROCODE_HEADER)) {
//msg(usprintf("%s: input is too small even for Intel microcode header", __FUNCTION__), parent);
// We have enough data to fit the header
if ((UINT32)microcode.size() < sizeof(INTEL_MICROCODE_HEADER)) {
return U_INVALID_MICROCODE;
}
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)microcode.constData();
if (ucodeHeader->Version != INTEL_MICROCODE_HEADER_VERSION) {
//msg(usprintf("%s: input has invalid Intel microcode header", __FUNCTION__), parent);
return U_INVALID_MICROCODE;
}
if (!INTEL_MICROCODE_HEADER_SIZES_VALID(ucodeHeader)) {
//msg(usprintf("%s: input has invalid Intel microcode header", __FUNCTION__), parent);
// Header version is 1
if (ucodeHeader->Version != INTEL_MICROCODE_HEADER_VERSION_1) {
return U_INVALID_MICROCODE;
}
// Reserved bytes are all zeroes
bool reservedBytesValid = true;
for (UINT8 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
if (ucodeHeader->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
for (UINT8 i = 0; i < sizeof(ucodeHeader->Reserved); i++) {
if (ucodeHeader->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
}
if (!reservedBytesValid) {
//msg(usprintf("%s: input has invalid Intel microcode header", __FUNCTION__), parent);
return U_INVALID_MICROCODE;
}
if (dataSize < ucodeHeader->TotalSize) {
//msg(usprintf("%s: input is too small for the whole Intel microcode", __FUNCTION__), parent);
// Data size is multiple of 4
if (ucodeHeader->DataSize % 4 != 0) {
return U_INVALID_MICROCODE;
}
// TotalSize is greater then DataSize and is multiple of 1024
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
return U_INVALID_MICROCODE;
}
// We have enough data to fit the whole TotalSize
if ((UINT32)microcode.size() < ucodeHeader->TotalSize) {
return U_INVALID_MICROCODE;
}
// Valid microcode found
// Construct header and body
UINT32 dataSize = ucodeHeader->DataSize;
if (dataSize == 0)
dataSize = INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO;
// Recalculate the whole microcode checksum
UByteArray tempMicrocode = microcode;
INTEL_MICROCODE_HEADER* tempUcodeHeader = (INTEL_MICROCODE_HEADER*)(tempMicrocode.data());
tempUcodeHeader->Checksum = 0;
UINT32 calculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), tempUcodeHeader->TotalSize);
bool msgInvalidChecksum = (ucodeHeader->Checksum != calculated);
// Construct header, body and tail
UByteArray header = microcode.left(sizeof(INTEL_MICROCODE_HEADER));
UByteArray body = microcode.mid(sizeof(INTEL_MICROCODE_HEADER), ucodeHeader->DataSize);
//TODO: recalculate microcode checksum
UByteArray body = microcode.mid(sizeof(INTEL_MICROCODE_HEADER), dataSize);
UByteArray tail = microcode.mid(sizeof(INTEL_MICROCODE_HEADER) + dataSize);
// Check if we have extended header in the tail
UString extendedHeaderInfo;
if ((UINT32)tail.size() >= sizeof(INTEL_MICROCODE_EXTENDED_HEADER)) {
const INTEL_MICROCODE_EXTENDED_HEADER* extendedHeader = (const INTEL_MICROCODE_EXTENDED_HEADER*)tail.constData();
// Reserved bytes are all zeroes
bool extendedReservedBytesValid = true;
for (UINT8 i = 0; i < sizeof(extendedHeader->Reserved); i++) {
if (extendedHeader->Reserved[i] != 0x00) {
extendedReservedBytesValid = false;
break;
}
}
// We have more than 0 entries and they are all in the tail
if (extendedReservedBytesValid
&& extendedHeader->EntryCount > 0
&& (UINT32)tail.size() >= sizeof(INTEL_MICROCODE_EXTENDED_HEADER) + extendedHeader->EntryCount * sizeof(INTEL_MICROCODE_EXTENDED_HEADER_ENTRY)) {
// Recalculate extended header checksum
INTEL_MICROCODE_EXTENDED_HEADER* tempExtendedHeader = (INTEL_MICROCODE_EXTENDED_HEADER*)(tempMicrocode.data() + sizeof(INTEL_MICROCODE_HEADER) + dataSize);
tempExtendedHeader->Checksum = 0;
UINT32 extendedCalculated = calculateChecksum32((const UINT32*)tempExtendedHeader, sizeof(INTEL_MICROCODE_EXTENDED_HEADER) + extendedHeader->EntryCount * sizeof(INTEL_MICROCODE_EXTENDED_HEADER_ENTRY));
extendedHeaderInfo = usprintf("\nExtended header entries: %u\nExtended header checksum: %08Xh, ",
extendedHeader->EntryCount,
extendedHeader->Checksum)
+ (extendedHeader->Checksum == extendedCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", extendedCalculated));
const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY* firstEntry = (const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY*)(extendedHeader + 1);
for (UINT8 i = 0; i < extendedHeader->EntryCount; i++) {
const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY* entry = (const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY*)(firstEntry + i);
// Recalculate checksum after patching
tempUcodeHeader->Checksum = 0;
tempUcodeHeader->CpuFlags = entry->CpuFlags;
tempUcodeHeader->CpuSignature = entry->CpuSignature;
UINT32 entryCalculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), sizeof(INTEL_MICROCODE_HEADER) + dataSize);
extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU flags #%u: %08Xh\nChecksum #%u: %08Xh, ",
i + 1, entry->CpuSignature,
i + 1, entry->CpuFlags,
i + 1, entry->Checksum)
+ (entry->Checksum == entryCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", entryCalculated));
}
}
}
// Add info
UString name("Intel microcode");
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\n"
"Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nChecksum: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh",
ucodeHeader->TotalSize, ucodeHeader->TotalSize,
header.size(), header.size(),
body.size(), body.size(),
ucodeHeader->DateDay,
ucodeHeader->DateMonth,
ucodeHeader->DateYear,
ucodeHeader->CpuSignature,
ucodeHeader->Revision,
ucodeHeader->Checksum,
ucodeHeader->LoaderRevision,
ucodeHeader->CpuFlags);
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)\n"
"Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh\nChecksum: %08Xh, ",
dataSize, dataSize,
header.size(), header.size(),
body.size(), body.size(),
tail.size(), tail.size(),
ucodeHeader->DateDay,
ucodeHeader->DateMonth,
ucodeHeader->DateYear,
ucodeHeader->CpuSignature,
ucodeHeader->Revision,
ucodeHeader->LoaderRevision,
ucodeHeader->CpuFlags,
ucodeHeader->Checksum)
+ (ucodeHeader->Checksum == calculated ? UString("valid") : usprintf("invalid, should be %08Xh", calculated))
+ extendedHeaderInfo;
// Add tree item
index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, header, body, UByteArray(), Fixed, parent);
// No need to parse body further for now
index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, header, body, tail, Fixed, parent);
if (msgInvalidChecksum)
msg(usprintf("%s: invalid microcode checksum %08Xh, should be %08Xh", __FUNCTION__, ucodeHeader->Checksum, calculated), index);
// No need to parse the body further for now
return U_SUCCESS;
}

View file

@ -144,6 +144,7 @@ private:
USTATUS checkProtectedRanges(const UModelIndex & index);
USTATUS markProtectedRangeRecursive(const UModelIndex & index, const BG_PROTECTED_RANGE & range);
USTATUS parseResetVectorData();
USTATUS parseFit(const UModelIndex & index);
USTATUS parseVendorHashFile(const UByteArray & fileGuid, const UModelIndex & index);
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);

View file

@ -49,7 +49,7 @@ USTATUS FfsReport::generateRecursive(std::vector<UString> & report, const UModel
// Calculate item CRC32
UByteArray data = model->header(index) + model->body(index) + model->tail(index);
UINT32 crc = crc32(0, (const UINT8*)data.constData(), data.size());
UINT32 crc = (UINT32)crc32(0, (const UINT8*)data.constData(), data.size());
// Information on current item
UString text = model->text(index);

63
common/fit.h Normal file → Executable file
View file

@ -50,21 +50,6 @@ typedef struct FIT_ENTRY_ {
UINT8 Checksum;
} FIT_ENTRY;
typedef struct INTEL_MICROCODE_HEADER_ {
UINT32 Version;
UINT32 Revision;
UINT16 DateYear;
UINT8 DateDay;
UINT8 DateMonth;
UINT32 CpuSignature;
UINT32 Checksum;
UINT32 LoaderRevision;
UINT32 CpuFlags;
UINT32 DataSize;
UINT32 TotalSize;
UINT8 Reserved[12];
} INTEL_MICROCODE_HEADER;
typedef struct {
UINT16 IndexRegisterAddress;
UINT16 DataRegisterAddress;
@ -73,9 +58,51 @@ typedef struct {
UINT16 Index;
} FIT_ENTRY_VERSION_0_CONFIG_POLICY;
#define INTEL_MICROCODE_HEADER_VERSION 0x00000001
#define INTEL_MICROCODE_HEADER_RESERVED_BYTE 0x00
#define INTEL_MICROCODE_HEADER_SIZES_VALID(ptr) (((INTEL_MICROCODE_HEADER*)ptr)->TotalSize - ((INTEL_MICROCODE_HEADER*)ptr)->DataSize == sizeof(INTEL_MICROCODE_HEADER))
// This scructure is described in Section 9.11.1 of the Intel Software Developer manual Volume 3A Part 1
typedef struct INTEL_MICROCODE_HEADER_ {
UINT32 Version;
UINT32 Revision;
UINT16 DateYear;
UINT8 DateDay;
UINT8 DateMonth;
UINT32 CpuSignature;
UINT32 Checksum; // Checksum of Update Data and Header. Used to verify the integrity of the update header and data.
// Checksum is correct when the summation of all the DWORDs (including the extended Processor Signature Table)
// that comprise the microcode update result in 00000000H.
UINT32 LoaderRevision;
UINT32 CpuFlags;
UINT32 DataSize; // Specifies the size of the encrypted data in bytes, and must be a multiple of DWORDs.
// If this value is 00000000H, then the microcode update encrypted data is 2000 bytes (or 500 DWORDs).
UINT32 TotalSize;// Specifies the total size of the microcode update in bytes.
// It is the summation of the header size, the encrypted data size and the size of the optional extended signature table.
// This value is always a multiple of 1024.
UINT8 Reserved[12];
} INTEL_MICROCODE_HEADER;
#define INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO 2000
typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ {
UINT32 EntryCount;
UINT32 Checksum; // Checksum of extended processor signature table.
// Used to verify the integrity of the extended processor signature table.
// Checksum is correct when the summation of the DWORDs that comprise the extended processor signature table results in 00000000H.
UINT8 Reserved[12];
// INTEL_MICROCODE_EXTENDED_HEADER_ENTRY Entries[EntryCount];
} INTEL_MICROCODE_EXTENDED_HEADER;
typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ENTRY_ {
UINT32 CpuSignature;
UINT32 CpuFlags;
UINT32 Checksum; // To calculate the Checksum, substitute the Primary Processor Signature entry and the Processor Flags entry with the corresponding Extended Patch entry.
// Delete the Extended Processor Signature Table entries.
// Checksum is correct when the summation of all DWORDs that comprise the created Extended Processor Patch results in 00000000H.
} INTEL_MICROCODE_EXTENDED_HEADER_ENTRY;
#define INTEL_MICROCODE_HEADER_VERSION_1 0x00000001
#pragma pack(pop)

1169
common/meparser.cpp Executable file

File diff suppressed because it is too large Load diff

230
common/meparser.h Normal file → Executable file
View file

@ -21,10 +21,235 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "ustring.h"
#include "ubytearray.h"
#include "treemodel.h"
#include "me.h"
#include "sha256.h"
// TODO: implement ME region parser
#ifdef U_ENABLE_ME_PARSING_SUPPORT
// FPT
#define ME_ROM_BYPASS_VECTOR_SIZE 0x10
const UByteArray ME_FPT_HEADER_SIGNATURE("\x24\x46\x50\x54", 4); //$FPT
typedef struct ME_FPT_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion;
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 Checksum; // One bit for Redundant before IFWI
UINT16 TicksToAdd;
UINT16 TokensToAdd;
UINT32 UmaSize; // Flags in SPS
UINT32 FlashLayout; // Crc32 before IFWI
UINT16 FitcMajor;
UINT16 FitcMinor;
UINT16 FitcHotfix;
UINT16 FitcBuild;
} ME_FPT_HEADER;
typedef struct ME_FPT_ENTRY_{
CHAR8 PartitionName[4];
UINT8 Reserved1;
UINT32 Offset;
UINT32 Length;
UINT8 Reserved2[12];
UINT32 PartitionType : 7;
UINT32 CopyToDramCache : 1;
UINT32 Reserved3 : 7;
UINT32 BuiltWithLength1 : 1;
UINT32 BuiltWithLength2 : 1;
UINT32 Reserved4 : 7;
UINT32 EntryValid : 8;
} ME_FPT_ENTRY;
// IFWI
typedef struct ME_IFWI_LAYOUT_HEADER_ {
UINT8 RomBypassVector[16];
UINT32 DataPartitionOffset;
UINT32 DataPartitionSize;
UINT32 Boot1Offset;
UINT32 Boot1Size;
UINT32 Boot2Offset;
UINT32 Boot2Size;
UINT32 Boot3Offset;
UINT32 Boot3Size;
} ME_IFWI_LAYOUT_HEADER;
// BPDT
const UByteArray ME_BPDT_GREEN_SIGNATURE("\xAA\x55\x00\x00", 4); //0x000055AA
const UByteArray ME_BPDT_YELLOW_SIGNATURE("\xAA\x55\xAA\x00", 4); //0x00AA55AA
typedef struct ME_BPDT_HEADER_ {
UINT32 Signature;
UINT16 NumEntries;
UINT16 Version;
UINT32 Checksum;
UINT32 IfwiVersion;
UINT16 FitcMajor;
UINT16 FitcMinor;
UINT16 FitcHotfix;
UINT16 FitcBuild;
} ME_BPDT_HEADER ;
typedef struct ME_BPDT_ENTRY_ {
UINT32 Type : 16;
UINT32 SplitSubPartitionFirstPart : 1;
UINT32 SplitSubPartitionSecondPart : 1;
UINT32 CodeSubPartition : 1;
UINT32 UmaCachable : 1;
UINT32 Reserved: 12;
UINT32 Offset;
UINT32 Length;
} ME_BPDT_ENTRY;
// CPD
const UByteArray ME_CPD_SIGNATURE("\x24\x43\x50\x44", 4); //$CPD
typedef struct ME_CPD_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion;
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 HeaderChecksum;
UINT8 ShortName[4];
} ME_CPD_HEADER;
typedef struct ME_BPDT_CPD_ENTRY_ {
UINT8 EntryName[12];
struct {
UINT32 Offset : 25;
UINT32 HuffmanCompressed : 1;
UINT32 Reserved : 6;
} Offset;
UINT32 Length;
UINT32 Reserved;
} ME_BPDT_CPD_ENTRY;
typedef struct ME_CPD_MANIFEST_HEADER_ {
UINT32 HeaderType;
UINT32 HeaderLength;
UINT32 HeaderVersion;
UINT32 Flags;
UINT32 Vendor;
UINT32 Date;
UINT32 Size;
UINT32 HeaderId;
UINT32 Reserved1;
UINT16 VersionMajor;
UINT16 VersionMinor;
UINT16 VersionBugfix;
UINT16 VersionBuild;
UINT32 SecurityVersion;
UINT8 Reserved2[8];
UINT8 Reserved3[64];
UINT32 ModulusSize;
UINT32 ExponentSize;
//manifest_rsa_key_t public_key;
//manifest_signature_t signature;
} ME_CPD_MANIFEST_HEADER;
typedef struct ME_CPD_EXTENTION_HEADER_ {
UINT32 Type;
UINT32 Length;
} ME_CPD_EXTENTION_HEADER;
typedef struct ME_CPD_EXT_SIGNED_PACKAGE_INFO_MODULES_ {
UINT8 Name[12];
UINT8 Type;
UINT8 HashAlgorithm;
UINT16 HashSize;
UINT32 MetadataSize;
UINT8 MetadataHash[32];
} ME_CPD_EXT_SIGNED_PACKAGE_INFO_MODULES;
typedef struct ME_CPD_EXT_SIGNED_PACKAGE_INFO_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 PackageName[4];
UINT32 Vcn;
UINT8 UsageBitmap[16];
UINT32 Svn;
UINT8 Reserved[16];
// ME_EXT_SIGNED_PACKAGE_INFO_MODULES Modules[];
} ME_CPD_EXT_SIGNED_PACKAGE_INFO;
typedef struct ME_CPD_EXT_MODULE_ATTRIBUTES_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 CompressionType;
UINT8 Reserved[3];
UINT32 UncompressedSize;
UINT32 CompressedSize;
UINT32 GlobalModuleId;
UINT8 ImageHash[32];
} ME_CPD_EXT_MODULE_ATTRIBUTES;
typedef struct ME_CPD_EXT_IFWI_PARTITION_MANIFEST_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 PartitionName[4];
UINT32 CompletePartitionLength;
UINT16 PartitionVersionMinor;
UINT16 PartitionVersionMajor;
UINT32 DataFormatVersion;
UINT32 InstanceId;
UINT32 SupportMultipleInstances : 1;
UINT32 SupportApiVersionBasedUpdate : 1;
UINT32 ActionOnUpdate : 2;
UINT32 ObeyFullUpdateRules : 1;
UINT32 IfrEnableOnly : 1;
UINT32 AllowCrossPointUpdate : 1;
UINT32 AllowCrossHotfixUpdate : 1;
UINT32 PartialUpdateOnly : 1;
UINT32 ReservedFlags : 23;
UINT32 HashAlgorithm : 8;
UINT32 HashSize : 24;
UINT8 CompletePartitionHash[32];
UINT8 Reserved[20];
} ME_CPD_EXT_IFWI_PARTITION_MANIFEST;
#define ME_MODULE_COMPRESSION_TYPE_UNCOMPRESSED 0
#define ME_MODULE_COMPRESSION_TYPE_HUFFMAN 1
#define ME_MODULE_COMPRESSION_TYPE_LZMA 2
#define ME_MANIFEST_HEADER_ID 0x324E4D24 //$MN2
class MeParser
{
public:
// Default constructor and destructor
MeParser(TreeModel* treeModel) : model(treeModel) {}
~MeParser() {}
// Returns messages
std::vector<std::pair<UString, UModelIndex> > getMessages() const { return messagesVector; }
// Clears messages
void clearMessages() { messagesVector.clear(); }
// ME parsing
USTATUS parseMeRegionBody(const UModelIndex & index);
private:
TreeModel *model;
std::vector<std::pair<UString, UModelIndex> > messagesVector;
void msg(const UString message, const UModelIndex index = UModelIndex()) {
messagesVector.push_back(std::pair<UString, UModelIndex>(message, index));
}
USTATUS parseFptRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index);
USTATUS parseIfwiRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index);
USTATUS parseBpdtRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index);
USTATUS parseCodePartitionDirectory(const UByteArray & directory, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseExtensionsArea(const UModelIndex & index);
USTATUS parseSignedPackageInfoData(const UModelIndex & index);
};
#else
class MeParser
{
public:
@ -40,4 +265,5 @@ public:
// ME parsing
USTATUS parseMeRegionBody(const UModelIndex & index) { U_UNUSED_PARAMETER(index); return U_SUCCESS; }
};
#endif // U_ENABLE_ME_PARSING_SUPPORT
#endif // MEPARSER_H

1
common/nvram.h Normal file → Executable file
View file

@ -86,6 +86,7 @@ const UByteArray NVRAM_ADDITIONAL_STORE_VOLUME_GUID
#define NVRAM_VSS_STORE_SIGNATURE 0x53535624 // $VSS
#define NVRAM_APPLE_SVS_STORE_SIGNATURE 0x53565324 // $SVS
#define NVRAM_APPLE_NSS_STORE_SIGNATURE 0x53534E24 // $NSS
#define NVRAM_APPLE_FSYS_STORE_SIGNATURE 0x73797346 // Fsys
#define NVRAM_APPLE_GAID_STORE_SIGNATURE 0x64696147 // Gaid
#define NVRAM_VSS_VARIABLE_START_ID 0x55AA

52
common/nvramparser.cpp Normal file → Executable file
View file

@ -536,7 +536,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
UINT32 offset = storeOffset;
for (; offset < dataSize - sizeof(UINT32); offset++) {
const UINT32* currentPos = (const UINT32*)(volume.constData() + offset);
if (*currentPos == NVRAM_VSS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_SVS_STORE_SIGNATURE) { // $VSS or $SVS signatures found, perform checks
if (*currentPos == NVRAM_VSS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_SVS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_NSS_STORE_SIGNATURE) { // $VSS, $SVS or $NSS signatures found, perform checks
const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)currentPos;
if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) {
msg(usprintf("%s: VSS store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index);
@ -645,20 +645,27 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
// All checks passed, store found
break;
}
else if (*currentPos == INTEL_MICROCODE_HEADER_VERSION) {// Intel microcode
if (!INTEL_MICROCODE_HEADER_SIZES_VALID(currentPos)) // Check header sizes
continue;
else if (*currentPos == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
// Check reserved bytes
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
bool reservedBytesValid = true;
for (UINT32 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
if (ucodeHeader->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
if (ucodeHeader->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
if (!reservedBytesValid)
continue;
// Data size is multiple of 4
if (ucodeHeader->DataSize % 4 != 0) {
continue;
}
// TotalSize is greater then DataSize and is multiple of 1024
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
continue;
}
// All checks passed, store found
break;
@ -710,7 +717,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
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) {
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;
}
@ -755,7 +762,7 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff
const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)signature;
storeSize = markerHeader->Size;
}
else if (*signature == INTEL_MICROCODE_HEADER_VERSION) { // Intel microcode, must be checked after SLIC marker because of the same *signature values
else if (*signature == INTEL_MICROCODE_HEADER_VERSION_1) { // Intel microcode, must be checked after SLIC marker because of the same *signature values
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)signature;
storeSize = ucodeHeader->TotalSize;
} else {
@ -796,10 +803,19 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32
UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS_VARIABLE_STORE_HEADER));
// Add info
bool isSvsStore = (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE);
UString name = isSvsStore ? UString("SVS store") : UString("VSS store");
UString info = usprintf("Signature: %s\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh",
isSvsStore ? "$SVS" : "$VSS",
UString name;
if (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
name = UString("SVS store");
}
else if (vssStoreHeader->Signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) {
name = UString("NSS store");
}
else {
name = UString("VSS store");
}
UString info = usprintf("Signature: %Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh",
vssStoreHeader->Signature,
storeSize, storeSize,
header.size(), header.size(),
body.size(), body.size(),
@ -912,7 +928,7 @@ USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)header.data();
crcFtwBlockHeader->Crc = emptyByte ? 0xFFFFFFFF : 0;
crcFtwBlockHeader->State = emptyByte ? 0xFF : 0;
UINT32 calculatedCrc = crc32(0, (const UINT8*)crcFtwBlockHeader, headerSize);
UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)crcFtwBlockHeader, headerSize);
// Add info
UString name("FTW store");
@ -996,7 +1012,7 @@ USTATUS NvramParser::parseFsysStoreHeader(const UByteArray & store, const UINT32
// Check store checksum
UINT32 storedCrc = *(UINT32*)store.right(sizeof(UINT32)).constData();
UINT32 calculatedCrc = crc32(0, (const UINT8*)store.constData(), (const UINT32)store.size() - sizeof(UINT32));
UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)store.constData(), (const UINT32)store.size() - sizeof(UINT32));
// Add info
bool isGaidStore = (fsysStoreHeader->Signature == NVRAM_APPLE_GAID_STORE_SIGNATURE);
@ -1234,8 +1250,8 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc
}
// Check signature and run parser function needed
// VSS/SVS store
if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE)
// 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)
@ -1266,7 +1282,7 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc
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)
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);
@ -1393,7 +1409,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen
// Calculate CRC32 of the variable data
storedCrc32 = appleVariableHeader->DataCrc32;
calculatedCrc32 = crc32(0, (const UINT8*)body.constData(), body.size());
calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)body.constData(), body.size());
}
}

34
common/types.cpp Normal file → Executable file
View file

@ -66,6 +66,20 @@ UString itemTypeToUString(const UINT8 type)
case Types::FlashMapEntry: return UString("FlashMap entry");
case Types::Microcode: return UString("Microcode");
case Types::SlicData: return UString("SLIC data");
// ME-specific
case Types::FptStore: return UString("FPT store");
case Types::FptEntry: return UString("FPT entry");
case Types::IfwiHeader: return UString("IFWI header");
case Types::IfwiPartition: return UString("IFWI partition");
case Types::FptPartition: return UString("FPT partition");
case Types::BpdtStore: return UString("BPDT store");
case Types::BpdtEntry: return UString("BPDT entry");
case Types::BpdtPartition: return UString("BPDT partition");
case Types::CpdStore: return UString("CPD store");
case Types::CpdEntry: return UString("CPD entry");
case Types::CpdPartition: return UString("CPD partition");
case Types::CpdExtension: return UString("CPD extension");
case Types::CpdSpiEntry: return UString("CPD SPI entry");
}
return UString("Unknown");
@ -132,6 +146,26 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
if (subtype == Subtypes::IntelMicrocode) return UString("Intel");
if (subtype == Subtypes::AmdMicrocode) return UString("AMD");
break;
// ME-specific
case Types::FptEntry:
if (subtype == Subtypes::ValidFptEntry) return UString("Valid");
if (subtype == Subtypes::InvalidFptEntry) return UString("Invalid");
break;
case Types::FptPartition:
if (subtype == Subtypes::CodeFptPartition) return UString("Code");
if (subtype == Subtypes::DataFptPartition) return UString("Data");
if (subtype == Subtypes::GlutFptPartition) return UString("GLUT");
break;
case Types::IfwiPartition:
if (subtype == Subtypes::BootIfwiPartition) return UString("Boot");
if (subtype == Subtypes::DataIfwiPartition) return UString("Data");
break;
case Types::CpdPartition:
if (subtype == Subtypes::ManifestCpdPartition) return UString("Manifest");
if (subtype == Subtypes::MetadataCpdPartition) return UString("Metadata");
if (subtype == Subtypes::KeyCpdPartition) return UString("Key");
if (subtype == Subtypes::CodeCpdPartition) return UString("Code");
break;
}
return UString();

38
common/types.h Normal file → Executable file
View file

@ -58,6 +58,20 @@ namespace Types {
FlashMapEntry,
Microcode,
SlicData,
// ME-specific
IfwiHeader,
IfwiPartition,
FptStore,
FptEntry,
FptPartition,
BpdtStore,
BpdtEntry,
BpdtPartition,
CpdStore,
CpdEntry,
CpdPartition,
CpdExtension,
CpdSpiEntry
};
}
@ -150,6 +164,30 @@ namespace Subtypes {
PubkeySlicData = 190,
MarkerSlicData
};
// ME-specific
enum IfwiPartitionSubtypes {
DataIfwiPartition = 200,
BootIfwiPartition
};
enum FptEntrySubtypes {
ValidFptEntry = 210,
InvalidFptEntry
};
enum FptPartitionSubtypes {
CodeFptPartition = 220,
DataFptPartition,
GlutFptPartition
};
enum CpdPartitionSubtypes {
ManifestCpdPartition = 230,
MetadataCpdPartition,
KeyCpdPartition,
CodeCpdPartition
};
}
// *ToUString conversion routines

25
common/utility.cpp Normal file → Executable file
View file

@ -141,6 +141,7 @@ UString errorCodeToUString(USTATUS errorCode)
case U_TRUNCATED_IMAGE: return UString("Image is truncated");
case U_INVALID_CAPSULE: return UString("Invalid capsule");
case U_STORES_NOT_FOUND: return UString("Stores not found");
case U_INVALID_STORE_SIZE: return UString("Invalid store size");
default: return usprintf("Unknown error %02X", errorCode);
}
}
@ -149,12 +150,12 @@ UString errorCodeToUString(USTATUS errorCode)
USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionType, UINT8 & algorithm, UINT32 & dictionarySize, UByteArray & decompressedData, UByteArray & efiDecompressedData)
{
const UINT8* data;
UINT32 dataSize;
UINT32 dataSize;
UINT8* decompressed;
UINT8* efiDecompressed;
UINT32 decompressedSize = 0;
UINT32 decompressedSize = 0;
UINT8* scratch;
UINT32 scratchSize = 0;
UINT32 scratchSize = 0;
const EFI_TIANO_HEADER* header;
// For all but LZMA dictionary size is 0
@ -333,6 +334,24 @@ UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
return (UINT16)(0x10000 - counter);
}
// 32bit checksum calculation routine
UINT32 calculateChecksum32(const UINT32* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
UINT32 counter = 0;
UINT32 index = 0;
bufferSize /= sizeof(UINT32);
for (; index < bufferSize; index++) {
counter = (UINT32)(counter + buffer[index]);
}
return (UINT32)(0x100000000ULL - counter);
}
// Get padding type for a given padding
UINT8 getPaddingType(const UByteArray & padding)
{

3
common/utility.h Normal file → Executable file
View file

@ -44,6 +44,9 @@ UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
// 16bit checksum calculation routine
UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
// 32bit checksum calculation routine
UINT32 calculateChecksum32(const UINT32* buffer, UINT32 bufferSize);
// Return padding type from it's contents
UINT8 getPaddingType(const UByteArray & padding);

View file

@ -417,6 +417,9 @@ z_size_t ZEXPORT gzfread(buf, size, nitems, file)
z_size_t len;
gz_statep state;
if (nitems == 0 || size == 0)
return 0;
/* get internal structure */
if (file == NULL)
return 0;

View file

@ -280,6 +280,9 @@ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
z_size_t len;
gz_statep state;
if (nitems == 0 || size == 0)
return 0;
/* get internal structure */
if (file == NULL)
return 0;

View file

@ -1,6 +1,6 @@
/* version.h
Copyright (c) 2018, LongSoft. All rights reserved.
Copyright (c) 2019, 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
@ -14,6 +14,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#ifndef VERSION_H
#define VERSION_H
#define PROGRAM_VERSION "NE alpha 55" " (" __DATE__ ")"
#define PROGRAM_VERSION "NE alpha 56" " (" __DATE__ ")"
#endif // VERSION_H