diff --git a/UEFIExtract/uefiextract_main.cpp b/UEFIExtract/uefiextract_main.cpp index ec7969c..0e7123b 100644 --- a/UEFIExtract/uefiextract_main.cpp +++ b/UEFIExtract/uefiextract_main.cpp @@ -1,6 +1,6 @@ /* uefiextract_main.cpp -Copyright (c) 2014, Nikolaj Schlej. All rights reserved. +Copyright (c) 2015, 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 @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) } else { - std::cout << "UEFIExtract 0.4.1" << std::endl << std::endl << + std::cout << "UEFIExtract 0.4.2" << std::endl << std::endl << "Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl << "Returned value is a bit mask where 0 on position N meant File with GUID_N was found and unpacked, 1 otherwise" << std::endl; return 1; diff --git a/UEFIFind/uefifind.cpp b/UEFIFind/uefifind.cpp index 2a5d71b..2adfafb 100644 --- a/UEFIFind/uefifind.cpp +++ b/UEFIFind/uefifind.cpp @@ -53,10 +53,28 @@ UINT8 UEFIFind::init(const QString & path) return ERR_SUCCESS; } +QString UEFIFind::guidToQString(const UINT8* guid) +{ + const UINT32 u32 = *(const UINT32*)guid; + const UINT16 u16_1 = *(const UINT16*)(guid + 4); + const UINT16 u16_2 = *(const UINT16*)(guid + 6); + const UINT8 u8_1 = *(const UINT8*)(guid + 8); + const UINT8 u8_2 = *(const UINT8*)(guid + 9); + const UINT8 u8_3 = *(const UINT8*)(guid + 10); + const UINT8 u8_4 = *(const UINT8*)(guid + 11); + const UINT8 u8_5 = *(const UINT8*)(guid + 12); + const UINT8 u8_6 = *(const UINT8*)(guid + 13); + const UINT8 u8_7 = *(const UINT8*)(guid + 14); + const UINT8 u8_8 = *(const UINT8*)(guid + 15); + + return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11").hexarg2(u32, 8).hexarg2(u16_1, 4).hexarg2(u16_2, 4).hexarg2(u8_1, 2).hexarg2(u8_2, 2) + .hexarg2(u8_3, 2).hexarg2(u8_4, 2).hexarg2(u8_5, 2).hexarg2(u8_6, 2).hexarg2(u8_7, 2).hexarg2(u8_8, 2); +} + UINT8 UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result) { QModelIndex root = model->index(0, 0); - QSet files; + QSet > files; result.clear(); @@ -70,31 +88,24 @@ UINT8 UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPatt return ERR_SUCCESS; } - QModelIndex index; - Q_FOREACH(index, files) { - QByteArray data = model->header(index).left(16); + QPair indexes; + Q_FOREACH(indexes, files) { + QByteArray data = model->header(indexes.first).left(16); + result.append(guidToQString((const UINT8*)data.constData())); - UINT32 u32 = *(UINT32*)data.constData(); - UINT16 u16_1 = *(UINT16*)(data.constData() + 4); - UINT16 u16_2 = *(UINT16*)(data.constData() + 6); - UINT8 u8_1 = *(UINT8*)(data.constData() + 8); - UINT8 u8_2 = *(UINT8*)(data.constData() + 9); - UINT8 u8_3 = *(UINT8*)(data.constData() + 10); - UINT8 u8_4 = *(UINT8*)(data.constData() + 11); - UINT8 u8_5 = *(UINT8*)(data.constData() + 12); - UINT8 u8_6 = *(UINT8*)(data.constData() + 13); - UINT8 u8_7 = *(UINT8*)(data.constData() + 14); - UINT8 u8_8 = *(UINT8*)(data.constData() + 15); + // Special case of freeform subtype GUID files + if (indexes.second.isValid() && model->subtype(indexes.second) == EFI_SECTION_FREEFORM_SUBTYPE_GUID) { + data = model->header(indexes.second).left(sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION)); + result.append(" ").append(guidToQString((const UINT8*)data.constData() + sizeof(EFI_COMMON_SECTION_HEADER))); + } + + result.append("\n"); - QString guid = QString("%1-%2-%3-%4%5-%6%7%8%9%10%11\n").hexarg2(u32, 8).hexarg2(u16_1, 4).hexarg2(u16_2, 4).hexarg2(u8_1, 2).hexarg2(u8_2, 2) - .hexarg2(u8_3, 2).hexarg2(u8_4, 2).hexarg2(u8_5, 2).hexarg2(u8_6, 2).hexarg2(u8_7, 2).hexarg2(u8_8, 2); - - result.append(guid); } return ERR_SUCCESS; } -UINT8 UEFIFind::findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet & files) +UINT8 UEFIFind::findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet > & files) { if (!index.isValid()) return ERR_SUCCESS; @@ -132,10 +143,13 @@ UINT8 UEFIFind::findFileRecursive(const QModelIndex index, const QString & hexPa if (offset % 2 == 0) { if (model->type(index) != Types::File) { QModelIndex ffs = model->findParentOfType(index, Types::File); - files.insert(ffs); + if (model->type(index) == Types::Section && model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID) + files.insert(QPair(ffs, index)); + else + files.insert(QPair(ffs, QModelIndex())); } else - files.insert(index); + files.insert(QPair(index, QModelIndex())); break; } diff --git a/UEFIFind/uefifind.h b/UEFIFind/uefifind.h index 374b56d..4137f9b 100644 --- a/UEFIFind/uefifind.h +++ b/UEFIFind/uefifind.h @@ -19,12 +19,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include #include "../basetypes.h" #include "../ffsengine.h" +#include "../ffs.h" class UEFIFind : public QObject { @@ -38,7 +40,8 @@ public: UINT8 find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result); private: - UINT8 findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet & files); + UINT8 findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet > & files); + QString UEFIFind::guidToQString(const UINT8* guid); FfsEngine* ffsEngine; TreeModel* model; diff --git a/UEFIFind/uefifind_main.cpp b/UEFIFind/uefifind_main.cpp index 01b2fa6..bcd5c2e 100644 --- a/UEFIFind/uefifind_main.cpp +++ b/UEFIFind/uefifind_main.cpp @@ -1,6 +1,6 @@ /* uefifind_main.cpp -Copyright (c) 2014, Nikolaj Schlej. All rights reserved. +Copyright (c) 2015, 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 @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) return ERR_SUCCESS; } else { - std::cout << "UEFIFind 0.2.0" << std::endl << std::endl << + std::cout << "UEFIFind 0.3.0" << std::endl << std::endl << "Usage: uefifind {header | body | all} {list | count} pattern imagefile\n"; return ERR_INVALID_PARAMETER; } diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index 74ad273..8d6e44b 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -1,6 +1,6 @@ /* uefipatch_main.cpp -Copyright (c) 2014, Nikolaj Schlej. All rights reserved. +Copyright (c) 2015, 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 @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) result = w.patchFromFile(a.arguments().at(1)); } else { - std::cout << "UEFIPatch 0.3.1 - UEFI image file patching utility" << std::endl << std::endl << + std::cout << "UEFIPatch 0.3.2 - UEFI image file patching utility" << std::endl << std::endl << "Usage: UEFIPatch image_file" << std::endl << std::endl << "Patches will be read from patches.txt file\n"; return ERR_SUCCESS; diff --git a/ffs.cpp b/ffs.cpp index 9b50ea1..fcdf03f 100644 --- a/ffs.cpp +++ b/ffs.cpp @@ -23,6 +23,10 @@ const QVector FFSv2Volumes = << EFI_INTEL_FILE_SYSTEM2_GUID << EFI_SONY_FILE_SYSTEM_GUID; +const QVector FFSv3Volumes = + QVector() + << EFI_FIRMWARE_FILE_SYSTEM3_GUID; + const UINT8 ffsAlignmentTable[] = { 0, 4, 7, 9, 10, 12, 15, 16 }; @@ -140,7 +144,7 @@ QString sectionTypeToQString(const UINT8 type) case EFI_SECTION_RAW: return QObject::tr("Raw"); case EFI_SECTION_PEI_DEPEX: return QObject::tr("PEI dependency"); case EFI_SECTION_SMM_DEPEX: return QObject::tr("SMM dependency"); - case HP_SECTION_POSTCODE: return QObject::tr("HP postcode"); + case INSYDE_SECTION_POSTCODE: return QObject::tr("Insyde postcode"); case SCT_SECTION_POSTCODE: return QObject::tr("SCT postcode"); default: return QObject::tr("Unknown"); } @@ -151,27 +155,47 @@ UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header) if (!header) return 0; + bool extended = false; + /*if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) { + extended = true; + }*/ + switch (header->Type) { case EFI_SECTION_GUID_DEFINED: { - const EFI_GUID_DEFINED_SECTION* gdsHeader = (const EFI_GUID_DEFINED_SECTION*)header; - return gdsHeader->DataOffset; } - case EFI_SECTION_COMPRESSION: return sizeof(EFI_COMPRESSION_SECTION); - case EFI_SECTION_DISPOSABLE: return sizeof(EFI_DISPOSABLE_SECTION); - case EFI_SECTION_PE32: return sizeof(EFI_PE32_SECTION); - case EFI_SECTION_PIC: return sizeof(EFI_PIC_SECTION); - case EFI_SECTION_TE: return sizeof(EFI_TE_SECTION); - case EFI_SECTION_DXE_DEPEX: return sizeof(EFI_DXE_DEPEX_SECTION); - case EFI_SECTION_VERSION: return sizeof(EFI_VERSION_SECTION); - case EFI_SECTION_USER_INTERFACE: return sizeof(EFI_USER_INTERFACE_SECTION); - case EFI_SECTION_COMPATIBILITY16: return sizeof(EFI_COMPATIBILITY16_SECTION); - case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION); - case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION); - case EFI_SECTION_RAW: return sizeof(EFI_RAW_SECTION); - case EFI_SECTION_PEI_DEPEX: return sizeof(EFI_PEI_DEPEX_SECTION); - case EFI_SECTION_SMM_DEPEX: return sizeof(EFI_SMM_DEPEX_SECTION); - case HP_SECTION_POSTCODE: return sizeof(POSTCODE_SECTION); - case SCT_SECTION_POSTCODE: return sizeof(POSTCODE_SECTION); - default: return sizeof(EFI_COMMON_SECTION_HEADER); + if (!extended) { + const EFI_GUID_DEFINED_SECTION* gdsHeader = (const EFI_GUID_DEFINED_SECTION*)header; + if (QByteArray((const char*)&gdsHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) { + const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)(gdsHeader + 1); + return gdsHeader->DataOffset + certificateHeader->Length; + } + return gdsHeader->DataOffset; + } + else { + const EFI_GUID_DEFINED_SECTION2* gdsHeader = (const EFI_GUID_DEFINED_SECTION2*)header; + if (QByteArray((const char*)&gdsHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) { + const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)(gdsHeader + 1); + return gdsHeader->DataOffset + certificateHeader->Length; + } + return gdsHeader->DataOffset; + } + } + case EFI_SECTION_COMPRESSION: return extended ? sizeof(EFI_COMPRESSION_SECTION2) : sizeof(EFI_COMPRESSION_SECTION); + case EFI_SECTION_DISPOSABLE: return extended ? sizeof(EFI_DISPOSABLE_SECTION2) : sizeof(EFI_DISPOSABLE_SECTION); + case EFI_SECTION_PE32: return extended ? sizeof(EFI_PE32_SECTION2) : sizeof(EFI_PE32_SECTION); + case EFI_SECTION_PIC: return extended ? sizeof(EFI_PIC_SECTION2) : sizeof(EFI_PIC_SECTION); + case EFI_SECTION_TE: return extended ? sizeof(EFI_TE_SECTION2) : sizeof(EFI_TE_SECTION); + case EFI_SECTION_DXE_DEPEX: return extended ? sizeof(EFI_DXE_DEPEX_SECTION2) : sizeof(EFI_DXE_DEPEX_SECTION); + case EFI_SECTION_VERSION: return extended ? sizeof(EFI_VERSION_SECTION2) : sizeof(EFI_VERSION_SECTION); + case EFI_SECTION_USER_INTERFACE: return extended ? sizeof(EFI_USER_INTERFACE_SECTION2) : sizeof(EFI_USER_INTERFACE_SECTION); + case EFI_SECTION_COMPATIBILITY16: return extended ? sizeof(EFI_COMPATIBILITY16_SECTION2) : sizeof(EFI_COMPATIBILITY16_SECTION); + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return extended ? sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION2) : sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION); + case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return extended ? sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2) : sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION); + case EFI_SECTION_RAW: return extended ? sizeof(EFI_RAW_SECTION2) : sizeof(EFI_RAW_SECTION); + case EFI_SECTION_PEI_DEPEX: return extended ? sizeof(EFI_PEI_DEPEX_SECTION2) : sizeof(EFI_PEI_DEPEX_SECTION); + case EFI_SECTION_SMM_DEPEX: return extended ? sizeof(EFI_SMM_DEPEX_SECTION2) : sizeof(EFI_SMM_DEPEX_SECTION); + case INSYDE_SECTION_POSTCODE: return extended ? sizeof(POSTCODE_SECTION2) : sizeof(POSTCODE_SECTION); + case SCT_SECTION_POSTCODE: return extended ? sizeof(POSTCODE_SECTION2) : sizeof(POSTCODE_SECTION); + default: return extended ? sizeof(EFI_COMMON_SECTION_HEADER2) : sizeof(EFI_COMMON_SECTION_HEADER); } } diff --git a/ffs.h b/ffs.h index 8287e3d..8b7da95 100644 --- a/ffs.h +++ b/ffs.h @@ -108,18 +108,23 @@ const QByteArray EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM2_GUID ("\x8C\x1B\x00\xBD\x71\x6A\x7B\x48\xA1\x4F\x0C\x2A\x2D\xCF\x7A\x5D", 16); const QByteArray EFI_INTEL_FILE_SYSTEM_GUID ("\xFF\xFF\x3F\xAD\x8B\xD2\xC4\x44\x9F\x13\x9E\xA9\x8A\x97\xF9\xF0", 16); -//AD3FFFFF-D28B-44C4-9F13-9EA98A97F9F0 //Intel 1 +// AD3FFFFF-D28B-44C4-9F13-9EA98A97F9F0 // Intel 1 const QByteArray EFI_INTEL_FILE_SYSTEM2_GUID ("\x70\xCD\xA1\xD6\x33\x4B\x94\x49\xA6\xEA\x37\x5F\x2C\xCC\x54\x37", 16); -//D6A1CD70-4B33-4994-A6EA-375F2CCC5437 //Intel 2 +// D6A1CD70-4B33-4994-A6EA-375F2CCC5437 // Intel 2 const QByteArray EFI_SONY_FILE_SYSTEM_GUID ("\x56\x41\x49\x4F\xD6\xAE\x64\x4D\xA5\x37\xB8\xA5\x55\x7B\xCE\xEC", 16); -//4F494156-AED6-4D64-A537-B8A5557BCEEC //Sony 1 +// 4F494156-AED6-4D64-A537-B8A5557BCEEC // Sony 1 - -//Vector of volume GUIDs with FFSv2-compatible files +// Vector of volume GUIDs with FFSv2-compatible files extern const QVector FFSv2Volumes; +const QByteArray EFI_FIRMWARE_FILE_SYSTEM3_GUID // 5473C07A-3DCB-4dca-BD6F-1E9689E7349A +("\x7A\xC0\x73\x54\xCB\x3D\xCA\x4D\xBD\x6F\x1E\x96\x89\xE7\x34\x9A", 16); + +// Vector of volume GUIDs with FFSv3-compatible files +extern const QVector FFSv3Volumes; + // Firmware volume signature const QByteArray EFI_FV_SIGNATURE("_FVH", 4); #define EFI_FV_SIGNATURE_OFFSET 0x28 @@ -214,21 +219,21 @@ typedef struct _EFI_FIRMWARE_VOLUME_EXT_HEADER { // Extended header entry // The extended header entries follow each other and are // terminated by ExtHeaderType EFI_FV_EXT_TYPE_END -#define EFI_FV_EXT_TYPE_END 0x00 +#define EFI_FV_EXT_TYPE_END 0x0000 typedef struct _EFI_FIRMWARE_VOLUME_EXT_ENTRY { UINT16 ExtEntrySize; UINT16 ExtEntryType; } EFI_FIRMWARE_VOLUME_EXT_ENTRY; // GUID that maps OEM file types to GUIDs -#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01 +#define EFI_FV_EXT_TYPE_OEM_TYPE 0x0001 typedef struct _EFI_FIRMWARE_VOLUME_EXT_HEADER_OEM_TYPE { EFI_FIRMWARE_VOLUME_EXT_ENTRY Header; UINT32 TypeMask; //EFI_GUID Types[1]; } EFI_FIRMWARE_VOLUME_EXT_HEADER_OEM_TYPE; -#define EFI_FV_EXT_TYPE_GUID_TYPE 0x02 +#define EFI_FV_EXT_TYPE_GUID_TYPE 0x0002 typedef struct _EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE { EFI_FIRMWARE_VOLUME_EXT_ENTRY Header; EFI_GUID FormatType; @@ -269,7 +274,7 @@ EFI_GUID Name; EFI_FFS_INTEGRITY_CHECK IntegrityCheck; UINT8 Type; UINT8 Attributes; -UINT8 Size[3]; +UINT8 Size[3]; // Set to 0xFFFFFF UINT8 State; UINT32 ExtendedSize; } EFI_FFS_FILE_HEADER2; @@ -302,8 +307,9 @@ UINT32 ExtendedSize; #define EFI_FV_FILETYPE_FFS_MAX 0xFF // File attributes -#define FFS_ATTRIB_TAIL_PRESENT 0x01 -#define FFS_ATTRIB_RECOVERY 0x02 +#define FFS_ATTRIB_TAIL_PRESENT 0x01 // Valid only for revision 1 volumes +#define FFS_ATTRIB_RECOVERY 0x02 // Valid only for revision 1 volumes +#define FFS_ATTRIB_LARGE_FILE 0x01 // Valid only for FFSv3 volumes #define FFS_ATTRIB_FIXED 0x04 #define FFS_ATTRIB_DATA_ALIGNMENT 0x38 #define FFS_ATTRIB_CHECKSUM 0x40 @@ -357,6 +363,9 @@ typedef struct _EFI_COMMON_SECTION_HEADER2 { UINT32 ExtendedSize; } EFI_COMMON_SECTION_HEADER2; +// Section2 usage indicator +#define EFI_SECTION2_IS_USED 0xFFFFFF + // File section types #define EFI_SECTION_ALL 0x00 // Impossible attribute for file in the FS @@ -379,7 +388,7 @@ typedef struct _EFI_COMMON_SECTION_HEADER2 { #define EFI_SECTION_PEI_DEPEX 0x1B #define EFI_SECTION_SMM_DEPEX 0x1C #define SCT_SECTION_POSTCODE 0xF0 // Specific to Phoenix SCT images -#define HP_SECTION_POSTCODE 0x20 // Specific to HP images +#define INSYDE_SECTION_POSTCODE 0x20 // Specific to Insyde images // Compression section typedef struct _EFI_COMPRESSION_SECTION { @@ -389,6 +398,14 @@ typedef struct _EFI_COMPRESSION_SECTION { UINT8 CompressionType; } EFI_COMPRESSION_SECTION; +typedef struct _EFI_COMPRESSION_SECTION2 { + UINT8 Size[3]; + UINT8 Type; + UINT32 ExtendedSize; + UINT32 UncompressedLength; + UINT8 CompressionType; +} EFI_COMPRESSION_SECTION2; + // Compression types #define EFI_NOT_COMPRESSED 0x00 #define EFI_STANDARD_COMPRESSION 0x01 @@ -403,6 +420,15 @@ typedef struct _EFI_GUID_DEFINED_SECTION { UINT16 Attributes; } EFI_GUID_DEFINED_SECTION; +typedef struct _EFI_GUID_DEFINED_SECTION2 { + UINT8 Size[3]; + UINT8 Type; + UINT32 ExtendedSize; + EFI_GUID SectionDefinitionGuid; + UINT16 DataOffset; + UINT16 Attributes; +} EFI_GUID_DEFINED_SECTION2; + // Attributes for GUID defined section #define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01 #define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02 @@ -417,7 +443,7 @@ const QByteArray EFI_GUIDED_SECTION_TIANO // A31280AD-481E-41B6-95E8-127F4C98477 const QByteArray EFI_GUIDED_SECTION_LZMA // EE4E5898-3914-4259-9D6E-DC7BD79403CF ("\x98\x58\x4E\xEE\x14\x39\x59\x42\x9D\x6E\xDC\x7B\xD7\x94\x03\xCF", 16); -const QByteArray EFI_GUIDED_SECTION_INTEL_SIGNED //0F9D89E8-9259-4F76-A5AF-0C89E34023DF +const QByteArray EFI_FIRMWARE_CONTENTS_SIGNED_GUID //0F9D89E8-9259-4F76-A5AF-0C89E34023DF ("\xE8\x89\x9D\x0F\x59\x92\x76\x4F\xA5\xAF\x0C\x89\xE3\x40\x23\xDF", 16); // Version section @@ -427,6 +453,13 @@ typedef struct _EFI_VERSION_SECTION { UINT16 BuildNumber; } EFI_VERSION_SECTION; +typedef struct _EFI_VERSION_SECTION2 { + UINT8 Size[3]; + UINT8 Type; + UINT32 ExtendedSize; + UINT16 BuildNumber; +} EFI_VERSION_SECTION2; + // Freeform subtype GUID section typedef struct _EFI_FREEFORM_SUBTYPE_GUID_SECTION { UINT8 Size[3]; @@ -434,6 +467,13 @@ typedef struct _EFI_FREEFORM_SUBTYPE_GUID_SECTION { EFI_GUID SubTypeGuid; } EFI_FREEFORM_SUBTYPE_GUID_SECTION; +typedef struct _EFI_FREEFORM_SUBTYPE_GUID_SECTION2 { + UINT8 Size[3]; + UINT8 Type; + UINT32 ExtendedSize; + EFI_GUID SubTypeGuid; +} EFI_FREEFORM_SUBTYPE_GUID_SECTION2; + // Phoenix SCT and HP postcode section typedef struct _POSTCODE_SECTION { UINT8 Size[3]; @@ -441,18 +481,36 @@ typedef struct _POSTCODE_SECTION { UINT32 Postcode; } POSTCODE_SECTION; +typedef struct _POSTCODE_SECTION2 { + UINT8 Size[3]; + UINT8 Type; + UINT32 ExtendedSize; + UINT32 Postcode; +} POSTCODE_SECTION2; + // Other sections -typedef EFI_COMMON_SECTION_HEADER EFI_DISPOSABLE_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_SMM_DEPEX_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_PIC_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION; -typedef EFI_COMMON_SECTION_HEADER EFI_USER_INTERFACE_SECTION; +typedef EFI_COMMON_SECTION_HEADER EFI_DISPOSABLE_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_DISPOSABLE_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_RAW_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_DXE_DEPEX_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_PEI_DEPEX_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_SMM_DEPEX_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_SMM_DEPEX_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_PE32_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_PIC_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_PIC_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_TE_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_COMPATIBILITY16_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_FIRMWARE_VOLUME_IMAGE_SECTION2; +typedef EFI_COMMON_SECTION_HEADER EFI_USER_INTERFACE_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2; //Section routines extern UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header); @@ -490,6 +548,39 @@ extern UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header); /// #define EFI_DEP_SOR 0x09 +//***************************************************************************** +// UEFI Crypto-signed Stuff +//***************************************************************************** + +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 +#define WIN_CERT_TYPE_EFI_GUID 0x0EF1 + +typedef struct _WIN_CERTIFICATE { + UINT32 Length; + UINT16 Revision; + UINT16 CertificateType; + //UINT8 CertData[]; +} WIN_CERTIFICATE; + +typedef struct _WIN_CERTIFICATE_UEFI_GUID { + WIN_CERTIFICATE Header; // Standard WIN_CERTIFICATE + EFI_GUID CertType; // Determines format of CertData + // UINT8 CertData[]; // Certificate data follows +} WIN_CERTIFICATE_UEFI_GUID; + +// WIN_CERTIFICATE_UEFI_GUID.CertType +const QByteArray EFI_CERT_TYPE_RSA2048_SHA256_GUID +("\x14\x74\x71\xA7\x16\xC6\x77\x49\x94\x20\x84\x47\x12\xA7\x35\xBF"); +const QByteArray EFI_CERT_TYPE_PKCS7_GUID +("\x9D\xD2\xAF\x4A\xDF\x68\xEE\x49\x8A\xA9\x34\x7D\x37\x56\x65\xA7"); + +// WIN_CERTIFICATE_UEFI_GUID.CertData +typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 { + UINT32 HashType; + UINT8 PublicKey[256]; + UINT8 Signature[256]; +} EFI_CERT_BLOCK_RSA_2048_SHA256; + // Restore previous packing rules #pragma pack(pop) diff --git a/ffsengine.cpp b/ffsengine.cpp index a2c075b..9eb883c 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -784,8 +784,12 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co volumeFfsVersion = 2; } - //!TODO:Check for FFS v3 volume - + // Check for FFS v3 volume + /*if (FFSv3Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) { + volumeIsUnknown = false; + volumeFfsVersion = 3; + }*/ + // Check attributes // Determine value of empty byte char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; @@ -896,7 +900,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Check free space to be actually free QByteArray freeSpace = volume.mid(fileOffset); if (freeSpace.count(empty) != freeSpace.count()) { - msg(tr("parseVolume: non-standard data found in volume's free space"), index); + msg(tr("parseVolume: non-UEFI data found in volume's free space"), index); // Search for the first non-empty byte UINT32 i; @@ -1085,7 +1089,6 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U // Check for non-empty pad file else if (fileHeader->Type == EFI_FV_FILETYPE_PAD) { parseAsNonEmptyPadFile = true; - msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), index); } // Get info @@ -1139,7 +1142,11 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U } // ... and all bytes after as a padding QByteArray padding = body.mid(i); - model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, QByteArray(), index, mode); + QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, QByteArray(), index, mode); + + // Show message + msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex); + return ERR_SUCCESS; } @@ -1360,6 +1367,9 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c bool msgUnknownGuid = false; bool msgInvalidCrc = false; bool msgUnknownAuth = false; + bool msgSigned = false; + bool msgUnknownSignature = false; + bool msgUnknownUefiGuidSignature = false; const EFI_GUID_DEFINED_SECTION* guidDefinedSectionHeader; header = section.left(sizeof(EFI_GUID_DEFINED_SECTION)); @@ -1368,7 +1378,6 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c guidDefinedSectionHeader = (const EFI_GUID_DEFINED_SECTION*)(header.constData()); body = section.mid(guidDefinedSectionHeader->DataOffset, sectionSize - guidDefinedSectionHeader->DataOffset); QByteArray processed = body; - QByteArray signature; // Get info name = guidToQString(guidDefinedSectionHeader->SectionDefinitionGuid); @@ -1418,11 +1427,39 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c else info += tr("\nCompression type: unknown"); } - // Intel signed section - else if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_INTEL_SIGNED) { - UINT32 signatureSize = *(const UINT32*)body.constData(); - signature = body.left(signatureSize); - processed = body.mid(signatureSize); + // Signed section + else if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) { + msgSigned = true; + const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)body.constData(); + if (certificateHeader->CertificateType == WIN_CERT_TYPE_EFI_GUID) { + info += tr("\nSignature type: UEFI"); + const WIN_CERTIFICATE_UEFI_GUID* guidCertificateHeader = (const WIN_CERTIFICATE_UEFI_GUID*)certificateHeader; + if (QByteArray((const char*)&guidCertificateHeader->CertType, sizeof(EFI_GUID)) == EFI_CERT_TYPE_RSA2048_SHA256_GUID) { + info += tr("\nSignature subtype: RSA2048/SHA256"); + // TODO: show signature info in Information panel + } + else if (QByteArray((const char*)&guidCertificateHeader->CertType, sizeof(EFI_GUID)) == EFI_CERT_TYPE_PKCS7_GUID) { + info += tr("\nSignature subtype: PCKS7"); + // TODO: show signature info in Information panel + } + else { + info += tr("\nSignature subtype: unknown"); + msgUnknownUefiGuidSignature = true; + } + } + else if (certificateHeader->CertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { + info += tr("\nSignature type: PCKS7"); + // TODO: show signature info in Information panel + } + else { + info += tr("\nSignature type: unknown"); + msgUnknownSignature = true; + } + + // Add additional to the header + header.append(body.left(certificateHeader->Length)); + // Get new body + processed = body = body.mid(certificateHeader->Length); } // Unknown GUIDed section else { @@ -1461,18 +1498,17 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c msg(tr("parseSection: GUID defined section with unknown authentication method"), index); if (msgInvalidCrc) msg(tr("parseSection: GUID defined section with invalid CRC32"), index); + if (msgSigned) + msg(tr("parseSection: signature may become invalid after any modification"), index); + if (msgUnknownUefiGuidSignature) + msg(tr("parseSection: GUID defined section with unknown signature subtype"), index); + if (msgUnknownSignature) + msg(tr("parseSection: GUID defined section with unknown signature type"), index); if (!parseCurrentSection) { msg(tr("parseSection: GUID defined section can not be processed"), index); } else { // Parse processed data - if (!signature.isEmpty()) { - // Add Intel signature padding to the tree - QModelIndex signatureIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Intel signature"), "", tr("Full size: %1h (%2)").hexarg(signature.size()).arg(signature.size()), QByteArray(), signature, QByteArray(), index, mode); - // Show message - msg(tr("parseSection: Intel signature may become invalid after any modification of the following sections"), signatureIndex); - } - result = parseSections(processed, index); if (result) return result; @@ -1824,7 +1860,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c } break; case SCT_SECTION_POSTCODE: - case HP_SECTION_POSTCODE: { + case INSYDE_SECTION_POSTCODE: { header = section.left(sizeof(POSTCODE_SECTION)); body = section.mid(sizeof(POSTCODE_SECTION), sectionSize - sizeof(POSTCODE_SECTION)); @@ -3358,7 +3394,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, } // Check for Intel signed section if (guidDefinedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED - && QByteArray((const char*)&guidDefinedHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_INTEL_SIGNED) { + && QByteArray((const char*)&guidDefinedHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) { msg(tr("reconstructSection: GUID defined section signature can become invalid") .arg(guidToQString(guidDefinedHeader->SectionDefinitionGuid)), index); } diff --git a/uefitool.cpp b/uefitool.cpp index bc885c9..67436c9 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.20.1")) +version(tr("0.20.2")) { clipboard = QApplication::clipboard(); @@ -349,7 +349,7 @@ void UEFITool::replace(const UINT8 mode) } else if (model->type(index) == Types::Section) { if (mode == REPLACE_MODE_AS_IS) { - path = QFileDialog::getOpenFileName(this, tr("Select section file to replace selected object"), currentDir, "Section files (*.sec *.bin);;All files (*)"); + path = QFileDialog::getOpenFileName(this, tr("Select section file to replace selected object"), currentDir, "Section files (*.sct *.bin);;All files (*)"); } else if (mode == REPLACE_MODE_BODY) { if (model->subtype(index) == EFI_SECTION_COMPRESSION || model->subtype(index) == EFI_SECTION_GUID_DEFINED || model->subtype(index) == EFI_SECTION_DISPOSABLE)