diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index f7cbd08..cf0dae8 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("NE alpha 41")) +version(tr("NE alpha 42")) { clipboard = QApplication::clipboard(); diff --git a/common/basetypes.h b/common/basetypes.h index 3071ce7..bafb800 100644 --- a/common/basetypes.h +++ b/common/basetypes.h @@ -162,7 +162,7 @@ typedef struct EFI_TIME_ { UINT8 : 8; } EFI_TIME; -// Aling to 4 or 8 bytes +// Align to 4 or 8 bytes #define ALIGN4(Value) (((Value)+3) & ~3) #define ALIGN8(Value) (((Value)+7) & ~7) diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index ea67658..613604a 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -2867,7 +2867,6 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) return U_SUCCESS; // Explicitly set the item as fixed - // TODO: update info model->setFixed(fitIndex, true); // Special case of FIT header @@ -2923,30 +2922,32 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) case FIT_TYPE_MICROCODE: { //TODO: refactor into function with error reporting if (currentEntry->Address > addressDiff && currentEntry->Address < 0xFFFFFFFFUL) { - UINT32 offset = (UINT32)currentEntry->Address - addressDiff; + UINT32 offset = (UINT32)(currentEntry->Address - addressDiff); UModelIndex mcIndex = model->findByOffset(offset); - UByteArray mcFile = model->header(mcIndex) + model->body(mcIndex) + model->tail(mcIndex); - - UINT32 mcOffset = offset - model->offset(mcIndex); - if (mcOffset + sizeof(INTEL_MICROCODE_HEADER) <= (UINT32)mcFile.size()) { - const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(mcFile.constData() + mcOffset); - if (header->Version == INTEL_MICROCODE_HEADER_VERSION) { - bool reservedBytesValid = true; - for (UINT8 i = 0; i < sizeof(header->Reserved); i++) - if (header->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) { - reservedBytesValid = false; - break; - } - if (reservedBytesValid) { - UINT32 mcSize = header->TotalSize; - if (mcOffset + mcSize <= (UINT32)mcFile.size()) { - info = usprintf("LocalOffset %08Xh, CPUID %08Xh, Revision %08Xh, Date %08Xh", - mcOffset, - header->CpuSignature, - header->Revision, - header->Date); - currentEntrySize = header->TotalSize; - itemIndex = mcIndex; + if (mcIndex.isValid()) { + UByteArray mcFile = model->header(mcIndex) + model->body(mcIndex) + model->tail(mcIndex); + UINT32 mcOffset = offset - model->offset(mcIndex); + if (mcOffset + sizeof(INTEL_MICROCODE_HEADER) <= (UINT32)mcFile.size()) { + const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(mcFile.constData() + mcOffset); + if (header->Version == INTEL_MICROCODE_HEADER_VERSION) { + bool reservedBytesValid = true; + for (UINT8 i = 0; i < sizeof(header->Reserved); i++) + if (header->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) { + reservedBytesValid = false; + break; + } + if (reservedBytesValid) { + UINT32 mcSize = header->TotalSize; + if (mcOffset + mcSize <= (UINT32)mcFile.size()) { + // Valid microcode found + info = usprintf("LocalOffset %08Xh, CPUID %08Xh, Revision %08Xh, Date %08Xh", + mcOffset, + header->CpuSignature, + header->Revision, + header->Date); + currentEntrySize = header->TotalSize; + itemIndex = mcIndex; + } } } } @@ -2963,8 +2964,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) case FIT_TYPE_AC_BOOT_POLICY: default: if (currentEntry->Address > addressDiff && currentEntry->Address < 0xFFFFFFFFUL) { - UINT32 offset = (UINT32)currentEntry->Address - addressDiff; - itemIndex = model->findByOffset(offset); + itemIndex = model->findByOffset((UINT32)(currentEntry->Address - addressDiff)); } msgModifiedImageMayNotWork = true; @@ -3032,7 +3032,7 @@ USTATUS FfsParser::addMemoryAddressesRecursive(const UModelIndex & index) // Set address value for non-compressed data if (!model->compressed(index)) { // Check address sanity - UINT64 address = (const UINT64)addressDiff + model->offset(index); + UINT64 address = addressDiff + model->offset(index); if (address <= 0xFFFFFFFFUL) { // Update info UINT32 headerSize = model->header(index).size(); diff --git a/common/nvram.h b/common/nvram.h index 9b85971..8845c65 100644 --- a/common/nvram.h +++ b/common/nvram.h @@ -63,6 +63,7 @@ typedef struct NVAR_ENTRY_HEADER_ { #define NVRAM_NVAR_ENTRY_EXT_AUTH_WRITE 0x10 #define NVRAM_NVAR_ENTRY_EXT_TIME_BASED 0x20 #define NVRAM_NVAR_ENTRY_EXT_UNKNOWN_MASK 0xCE + // // TianoCore VSS store and variables // @@ -158,6 +159,31 @@ typedef struct VSS_AUTH_VARIABLE_HEADER_ { extern UString vssAttributesToUString(const UINT32 attributes); +// +// Lenovo VSS variables +// + +//aaf32c78-947b-439a-a180-2e144ec37792 +#define LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 0xaaf32c78 +const UByteArray LENOVO_AUTH_VAR_KEY_DATABASE_GUID +("\x78\x2C\xF3\xAA\x7B\x94\x9A\x43\xA1\x80\x2E\x14\x4E\xC3\x77\x92"); + +#define LENOVO_VSS_STORE_GUID_PART1 0xddcf3617 +const UByteArray LENOVO_VSS_STORE_GUID +("\x17\x36\xCF\xDD\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D"); + +// Variable store header +typedef struct LENOVO_VSS_VARIABLE_STORE_HEADER_ { + EFI_GUID Signature; + UINT32 Size; // Size of variable store, including store header + UINT8 Format; // Store format state + UINT8 State; // Store health state + UINT16 Unknown; + UINT32 : 32; +} LENOVO_VSS_VARIABLE_STORE_HEADER; + +// VSS entries are 4-bytes aligned in Lenovo stores + // // _FDC region // @@ -182,6 +208,10 @@ typedef struct FDC_VOLUME_HEADER_ { const UByteArray EDKII_WORKING_BLOCK_SIGNATURE_GUID ("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 16); +// 9E58292B-7C68-497D-A0CE6500FD9F1B95 +const UByteArray LENOVO_WORKING_BLOCK_SIGNATURE_GUID +("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\xA0\xCE\x65\x00\xFD\x9F\x1B\x95", 16); + #define NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 0xFFF12B8D #define EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1 0x9E58292B diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index d468a9c..05db593 100644 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -497,10 +497,11 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) UModelIndex current = index.child(i, 0); switch (model->type(current)) { case Types::VssStore: - case Types::FdcStore: parseVssStoreBody(current); break; - case Types::FsysStore: parseFsysStoreBody(current); break; - case Types::EvsaStore: parseEvsaStoreBody(current); break; - case Types::FlashMapStore: parseFlashMapBody(current); break; + case Types::FdcStore: parseVssStoreBody(current, 0); break; + case Types::LenovoVssStore: parseVssStoreBody(current, 4); break; + case Types::FsysStore: parseFsysStoreBody(current); break; + case Types::EvsaStore: parseEvsaStoreBody(current); break; + case Types::FlashMapStore: parseFlashMapBody(current); break; } } @@ -530,6 +531,23 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } + else if (*currentPos == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == LENOVO_VSS_STORE_GUID_PART1) { //Lenovo VSS store signatures found, perform checks + UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); + if (guid != LENOVO_AUTH_VAR_KEY_DATABASE_GUID && guid != LENOVO_VSS_STORE_GUID) // Check the whole signature + continue; + + const LENOVO_VSS_VARIABLE_STORE_HEADER* vssHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)currentPos; + if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) { + msg(usprintf("findNextStore: Lenovo VSS store candidate at offset %Xh skipped, has invalid format %02Xh", localOffset + offset, vssHeader->Format), index); + continue; + } + if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) { + msg(usprintf("findNextStore: Lenovo VSS store candidate at offset %Xh skipped, has invalid size %Xh", localOffset + offset, vssHeader->Size), index); + continue; + } + // All checks passed, store found + break; + } else if (*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) { @@ -567,7 +585,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & } else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *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) // Check the whole signature + if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != LENOVO_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature continue; // Detect header variant based on WriteQueueSize @@ -678,6 +696,10 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature; storeSize = vssHeader->Size; } + else if (*signature == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == LENOVO_VSS_STORE_GUID_PART1) { + const LENOVO_VSS_VARIABLE_STORE_HEADER* vssHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)signature; + storeSize = vssHeader->Size; + } else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) { const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)signature; storeSize = fdcHeader->Size; @@ -765,6 +787,48 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 return U_SUCCESS; } +USTATUS NvramParser::parseLenovoVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) +{ + const UINT32 dataSize = (const UINT32)store.size(); + + // Check store size + if (dataSize < sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)) { + msg(UString("parseLenovoVssStoreHeader: volume body is too small even for VSS store header"), parent); + return U_SUCCESS; + } + + // Get VSS store header + const LENOVO_VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)store.constData(); + + // Check store size + if (dataSize < vssStoreHeader->Size) { + msg(usprintf("parseLenovoVssStoreHeader: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)", + vssStoreHeader->Size, vssStoreHeader->Size, + dataSize, dataSize), parent); + return U_SUCCESS; + } + + // Construct header and body + UByteArray header = store.left(sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)); + UByteArray body = store.mid(sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER), vssStoreHeader->Size - sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)); + + // Add info + UString name = UString("Lenovo VSS store"); + UString info = UString("Signature: ") + guidToUString(vssStoreHeader->Signature, false) + + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", + vssStoreHeader->Size, vssStoreHeader->Size, + header.size(), header.size(), + body.size(), body.size(), + vssStoreHeader->Format, + vssStoreHeader->State, + vssStoreHeader->Unknown); + + // Add tree item + index = model->addItem(localOffset, Types::LenovoVssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); + + return U_SUCCESS; +} + USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (const UINT32)store.size(); @@ -1217,6 +1281,9 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc // VSS/SVS store if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) return parseVssStoreHeader(store, localOffset, parent, index); + // Lenovo VSS store + if (*signature == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == LENOVO_VSS_STORE_GUID_PART1) + return parseLenovoVssStoreHeader(store, localOffset, parent, index); // FTW store else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) return parseFtwStoreHeader(store, localOffset, parent, index); @@ -1250,7 +1317,7 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc return U_SUCCESS; } -USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index) +USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment) { // Sanity check if (!index.isValid()) @@ -1365,8 +1432,6 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index) body = data.mid(offset + header.size(), variableHeader->DataSize); } - // There is also a case of authenticated Apple variables, but I haven't seen one yet - // Check variable state if (variableHeader->State != NVRAM_VSS_VARIABLE_ADDED && variableHeader->State != NVRAM_VSS_VARIABLE_HEADER_VALID) { isInvalid = true; @@ -1442,6 +1507,11 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index) // Add tree item model->addItem(localOffset + offset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Movable, index); + // Apply alignment, if needed + if (alignment) { + variableSize = ((variableSize + alignment - 1) & (~(alignment - 1))); + } + // Move to next variable offset += variableSize; } diff --git a/common/nvramparser.h b/common/nvramparser.h index f8de4c1..fed1f13 100644 --- a/common/nvramparser.h +++ b/common/nvramparser.h @@ -51,6 +51,7 @@ private: USTATUS parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); + USTATUS parseLenovoVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); @@ -61,7 +62,7 @@ private: USTATUS parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); - USTATUS parseVssStoreBody(const UModelIndex & index); + USTATUS parseVssStoreBody(const UModelIndex & index, const UINT8 alignment); USTATUS parseFsysStoreBody(const UModelIndex & index); USTATUS parseEvsaStoreBody(const UModelIndex & index); USTATUS parseFlashMapBody(const UModelIndex & index); diff --git a/common/types.cpp b/common/types.cpp index d856509..6d2fa39 100644 --- a/common/types.cpp +++ b/common/types.cpp @@ -36,29 +36,30 @@ UString regionTypeToUString(const UINT8 type) UString itemTypeToUString(const UINT8 type) { switch (type) { - case Types::Root: return UString("Root"); - case Types::Image: return UString("Image"); - case Types::Capsule: return UString("Capsule"); - case Types::Region: return UString("Region"); - case Types::Volume: return UString("Volume"); - case Types::Padding: return UString("Padding"); - case Types::File: return UString("File"); - case Types::Section: return UString("Section"); - case Types::FreeSpace: return UString("Free space"); - case Types::VssStore: return UString("VSS store"); - case Types::FtwStore: return UString("FTW store"); - case Types::FdcStore: return UString("FDC store"); - case Types::FsysStore: return UString("Fsys store"); - case Types::EvsaStore: return UString("EVSA store"); - case Types::CmdbStore: return UString("CMDB store"); - case Types::FlashMapStore: return UString("FlashMap store"); - case Types::NvarEntry: return UString("NVAR entry"); - case Types::VssEntry: return UString("VSS entry"); - case Types::FsysEntry: return UString("Fsys entry"); - case Types::EvsaEntry: return UString("EVSA entry"); - case Types::FlashMapEntry: return UString("FlashMap entry"); - case Types::Microcode: return UString("Microcode"); - case Types::SlicData: return UString("SLIC data"); + case Types::Root: return UString("Root"); + case Types::Image: return UString("Image"); + case Types::Capsule: return UString("Capsule"); + case Types::Region: return UString("Region"); + case Types::Volume: return UString("Volume"); + case Types::Padding: return UString("Padding"); + case Types::File: return UString("File"); + case Types::Section: return UString("Section"); + case Types::FreeSpace: return UString("Free space"); + case Types::VssStore: return UString("VSS store"); + case Types::LenovoVssStore: return UString("Lenovo VSS store"); + case Types::FtwStore: return UString("FTW store"); + case Types::FdcStore: return UString("FDC store"); + case Types::FsysStore: return UString("Fsys store"); + case Types::EvsaStore: return UString("EVSA store"); + case Types::CmdbStore: return UString("CMDB store"); + case Types::FlashMapStore: return UString("FlashMap store"); + case Types::NvarEntry: return UString("NVAR entry"); + case Types::VssEntry: return UString("VSS entry"); + case Types::FsysEntry: return UString("Fsys entry"); + case Types::EvsaEntry: return UString("EVSA entry"); + case Types::FlashMapEntry: return UString("FlashMap entry"); + case Types::Microcode: return UString("Microcode"); + case Types::SlicData: return UString("SLIC data"); } return UString("Unknown"); @@ -70,6 +71,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) case Types::Root: case Types::FreeSpace: case Types::VssStore: + case Types::LenovoVssStore: case Types::FdcStore: case Types::FsysStore: case Types::EvsaStore: @@ -115,8 +117,8 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) if (subtype == Subtypes::AuthVssEntry) return UString("Auth"); break; case Types::FsysEntry: - if (subtype == Subtypes::InvalidFsysEntry) return UString("Invalid"); - if (subtype == Subtypes::NormalFsysEntry) return UString("Normal"); + if (subtype == Subtypes::InvalidFsysEntry) return UString("Invalid"); + if (subtype == Subtypes::NormalFsysEntry) return UString("Normal"); break; case Types::EvsaEntry: if (subtype == Subtypes::InvalidEvsaEntry) return UString("Invalid"); diff --git a/common/types.h b/common/types.h index 0884890..5f55ffc 100644 --- a/common/types.h +++ b/common/types.h @@ -44,6 +44,7 @@ namespace Types { Section, FreeSpace, VssStore, + LenovoVssStore, FtwStore, FdcStore, FsysStore,