mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-22 07:58:22 +08:00
UT A16
- added various size checks to prevent crashes found by fuzzing with AFL - rewritten parsing of GUID-defined sections
This commit is contained in:
parent
5fd8edf0be
commit
8c05b4da6a
@ -17,7 +17,7 @@
|
||||
UEFITool::UEFITool(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr("0.30.0_alpha15"))
|
||||
version(tr("0.30.0_alpha16"))
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
|
||||
@ -199,8 +199,7 @@ bool UEFITool::enableExtractBodyUncompressed(const QModelIndex ¤t)
|
||||
pdata.section.compressed.algorithm != COMPRESSION_ALGORITHM_UNKNOWN) { //Compressed section
|
||||
return true;
|
||||
}
|
||||
else if (model->subtype(current) == EFI_SECTION_GUID_DEFINED &&
|
||||
(pdata.section.guidDefined.attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) {
|
||||
else if (model->subtype(current) == EFI_SECTION_GUID_DEFINED) {
|
||||
QByteArray guid = QByteArray((const char*)&pdata.section.guidDefined.guid, sizeof(EFI_GUID));
|
||||
if (guid == EFI_GUIDED_SECTION_TIANO || guid == EFI_GUIDED_SECTION_LZMA) {
|
||||
return true;
|
||||
|
@ -78,6 +78,7 @@ typedef UINT8 STATUS;
|
||||
#define ERR_DIR_ALREADY_EXIST 32
|
||||
#define ERR_DIR_CREATE 33
|
||||
#define ERR_TRUNCATED_IMAGE 34
|
||||
#define ERR_INVALID_CAPSULE 35
|
||||
#define ERR_NOT_IMPLEMENTED 0xFF
|
||||
|
||||
// UDK porting definitions
|
||||
|
@ -31,6 +31,9 @@ typedef struct _FLASH_DESCRIPTOR_HEADER {
|
||||
// Descriptor region size
|
||||
#define FLASH_DESCRIPTOR_SIZE 0x1000
|
||||
|
||||
// Maximum base value in descriptor map
|
||||
#define FLASH_DESCRIPTOR_MAX_BASE 0xE0
|
||||
|
||||
// Descriptor map
|
||||
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
|
||||
typedef struct _FLASH_DESCRIPTOR_MAP {
|
||||
|
73
common/ffs.h
73
common/ffs.h
@ -68,13 +68,10 @@ const QByteArray TOSHIBA_CAPSULE_GUID
|
||||
// AMI Aptio extended capsule header
|
||||
typedef struct _APTIO_CAPSULE_HEADER {
|
||||
EFI_CAPSULE_HEADER CapsuleHeader;
|
||||
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
|
||||
// the capsule volume
|
||||
//!TODO: Enable certificate and ROM layout reading
|
||||
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
|
||||
// that are included in the signature calculation
|
||||
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of the capsule volume
|
||||
UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume that are included in the signature calculation
|
||||
//FW_CERTIFICATE FWCert;
|
||||
//ROM_AREA RomAreaMap[1];
|
||||
//ROM_AREA RomAreaMap[1];
|
||||
} APTIO_CAPSULE_HEADER;
|
||||
|
||||
// AMI Aptio signed extended capsule GUID
|
||||
@ -454,6 +451,35 @@ const QByteArray EFI_GUIDED_SECTION_LZMA // EE4E5898-3914-4259-9D6E-DC7BD79403CF
|
||||
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);
|
||||
|
||||
//#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;
|
||||
|
||||
// Version section
|
||||
typedef struct _EFI_VERSION_SECTION {
|
||||
UINT8 Size[3];
|
||||
@ -549,43 +575,10 @@ typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2;
|
||||
|
||||
///
|
||||
/// If present, this must be the first opcode,
|
||||
/// EFI_DEP_SOR is only used by DXE driver.
|
||||
/// EFI_DEP_SOR is only used by DXE drivers
|
||||
///
|
||||
#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)
|
||||
|
||||
|
@ -64,19 +64,32 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
// Reset capsule offset fixeup value
|
||||
capsuleOffsetFixup = 0;
|
||||
|
||||
// Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER
|
||||
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
|
||||
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
|
||||
msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||
msg(tr("parseImageFile: image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Check buffer for being normal EFI capsule header
|
||||
UINT32 capsuleHeaderSize = 0;
|
||||
QModelIndex index;
|
||||
UINT32 capsuleHeaderSize = 0;
|
||||
// Check buffer for being normal EFI capsule header
|
||||
if (buffer.startsWith(EFI_CAPSULE_GUID)
|
||||
|| buffer.startsWith(INTEL_CAPSULE_GUID)) {
|
||||
// Get info
|
||||
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
|
||||
|
||||
// Check sanity of HeaderSize and CapsuleImageSize values
|
||||
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->CapsuleImageSize) {
|
||||
msg(tr("parseImageFile: UEFI capsule header size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
if (capsuleHeader->CapsuleImageSize == 0 || capsuleHeader->CapsuleImageSize > (UINT32)buffer.size()) {
|
||||
msg(tr("parseImageFile: UEFI capsule image size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->CapsuleImageSize).arg(capsuleHeader->CapsuleImageSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
|
||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||
QByteArray body = buffer.mid(capsuleHeaderSize);
|
||||
@ -84,8 +97,8 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
QString info = tr("Offset: 0h\nCapsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
||||
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
||||
.hexarg(buffer.size()).arg(buffer.size())
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
|
||||
.hexarg(capsuleHeader->CapsuleImageSize - capsuleHeader->HeaderSize).arg(capsuleHeader->CapsuleImageSize - capsuleHeader->HeaderSize)
|
||||
.hexarg(capsuleHeaderSize).arg(capsuleHeaderSize)
|
||||
.hexarg(capsuleHeader->CapsuleImageSize - capsuleHeaderSize).arg(capsuleHeader->CapsuleImageSize - capsuleHeaderSize)
|
||||
.hexarg2(capsuleHeader->Flags, 8);
|
||||
|
||||
// Construct parsing data
|
||||
@ -93,7 +106,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
pdata.fixed = TRUE;
|
||||
|
||||
// Set capsule offset fixup for correct volume allignment warnings
|
||||
capsuleOffsetFixup = capsuleHeader->HeaderSize;
|
||||
capsuleOffsetFixup = capsuleHeaderSize;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, parsingDataToQByteArray(pdata), root);
|
||||
@ -102,6 +115,19 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
||||
// Get info
|
||||
const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)buffer.constData();
|
||||
|
||||
// Check sanity of HeaderSize and FullSize values
|
||||
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->FullSize) {
|
||||
msg(tr("parseImageFile: Toshiba capsule header size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
if (capsuleHeader->FullSize == 0 || capsuleHeader->FullSize > (UINT32)buffer.size()) {
|
||||
msg(tr("parseImageFile: Toshiba capsule full size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->FullSize).arg(capsuleHeader->FullSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
|
||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
@ -109,8 +135,8 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
QString info = tr("Offset: 0h\nCapsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
||||
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
||||
.hexarg(buffer.size()).arg(buffer.size())
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
|
||||
.hexarg(capsuleHeader->FullSize - capsuleHeader->HeaderSize).arg(capsuleHeader->FullSize - capsuleHeader->HeaderSize)
|
||||
.hexarg(capsuleHeaderSize).arg(capsuleHeaderSize)
|
||||
.hexarg(capsuleHeader->FullSize - capsuleHeaderSize).arg(capsuleHeader->FullSize - capsuleHeaderSize)
|
||||
.hexarg2(capsuleHeader->Flags, 8);
|
||||
|
||||
// Construct parsing data
|
||||
@ -118,7 +144,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
pdata.fixed = TRUE;
|
||||
|
||||
// Set capsule offset fixup for correct volume allignment warnings
|
||||
capsuleOffsetFixup = capsuleHeader->HeaderSize;
|
||||
capsuleOffsetFixup = capsuleHeaderSize;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, parsingDataToQByteArray(pdata), root);
|
||||
@ -126,8 +152,25 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
// Check buffer for being extended Aptio signed capsule header
|
||||
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
|
||||
bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID);
|
||||
|
||||
if ((UINT32)buffer.size() <= sizeof(APTIO_CAPSULE_HEADER)) {
|
||||
msg(tr("parseImageFile: AMI capsule image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(APTIO_CAPSULE_HEADER)).arg(sizeof(APTIO_CAPSULE_HEADER)));
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Get info
|
||||
const APTIO_CAPSULE_HEADER* capsuleHeader = (const APTIO_CAPSULE_HEADER*)buffer.constData();
|
||||
|
||||
// Check sanity of RomImageOffset and CapsuleImageSize values
|
||||
if (capsuleHeader->RomImageOffset == 0 || capsuleHeader->RomImageOffset > (UINT32)buffer.size() || capsuleHeader->RomImageOffset > capsuleHeader->CapsuleHeader.CapsuleImageSize) {
|
||||
msg(tr("parseImageFile: AMI capsule image offset of %1h (%2) bytes is invalid").hexarg(capsuleHeader->RomImageOffset).arg(capsuleHeader->RomImageOffset));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
if (capsuleHeader->CapsuleHeader.CapsuleImageSize == 0 || capsuleHeader->CapsuleHeader.CapsuleImageSize > (UINT32)buffer.size()) {
|
||||
msg(tr("parseImageFile: AMI capsule image size of %1h (%2) bytes is invalid").hexarg(capsuleHeader->CapsuleHeader.CapsuleImageSize).arg(capsuleHeader->CapsuleHeader.CapsuleImageSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
|
||||
capsuleHeaderSize = capsuleHeader->RomImageOffset;
|
||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||
QByteArray body = buffer.mid(capsuleHeaderSize);
|
||||
@ -220,13 +263,31 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
|
||||
// Check for buffer size to be greater or equal to descriptor region size
|
||||
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
||||
msg(tr("parseIntelImage: input file is smaller then minimum descriptor size of %1h (%2) bytes").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE));
|
||||
msg(tr("parseIntelImage: input file is smaller than minimum descriptor size of %1h (%2) bytes").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Parse descriptor map
|
||||
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
|
||||
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
||||
|
||||
// Check sanity of base values
|
||||
if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
|| descriptorMap->MasterBase == descriptorMap->RegionBase
|
||||
|| descriptorMap->MasterBase == descriptorMap->ComponentBase) {
|
||||
msg(tr("parseIntelImage: invalid descriptor master base %1h").hexarg2(descriptorMap->MasterBase, 2));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
|| descriptorMap->RegionBase == descriptorMap->ComponentBase) {
|
||||
msg(tr("parseIntelImage: invalid descriptor region base %1h").hexarg2(descriptorMap->RegionBase, 2));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorMap->ComponentBase > FLASH_DESCRIPTOR_MAX_BASE) {
|
||||
msg(tr("parseIntelImage: invalid descriptor component base %1h").hexarg2(descriptorMap->ComponentBase, 2));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8(descriptor, descriptorMap->RegionBase);
|
||||
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase);
|
||||
|
||||
@ -601,6 +662,8 @@ STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffs
|
||||
// Check sanity
|
||||
if (gbe.isEmpty())
|
||||
return ERR_EMPTY_REGION;
|
||||
if ((UINT32)gbe.size() < GBE_VERSION_OFFSET + sizeof(GBE_VERSION))
|
||||
return ERR_INVALID_REGION;
|
||||
|
||||
// Get parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
@ -666,6 +729,10 @@ STATUS FfsParser::parseMeRegion(const QByteArray & me, const UINT32 parentOffset
|
||||
}
|
||||
}
|
||||
|
||||
// Check sanity
|
||||
if ((UINT32)me.size() < (UINT32)versionOffset + sizeof(ME_VERSION))
|
||||
return ERR_INVALID_REGION;
|
||||
|
||||
// Add version information
|
||||
if (versionFound) {
|
||||
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
||||
@ -853,10 +920,17 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
|
||||
UINT32 volumeSize = 0;
|
||||
UINT32 bmVolumeSize = 0;
|
||||
result = getVolumeSize(data, volumeOffset, volumeSize, bmVolumeSize);
|
||||
if (result)
|
||||
if (result) {
|
||||
msg(tr("parseRawArea: getVolumeSize failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that volume is fully present in input
|
||||
if (volumeSize > (UINT32)data.size() || volumeOffset + volumeSize > (UINT32)data.size()) {
|
||||
msg(tr("parseRawArea: one of volumes inside overlaps the end of data"), index);
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
QByteArray volume = data.mid(volumeOffset, volumeSize);
|
||||
if (volumeSize > (UINT32)volume.size()) {
|
||||
// Mark the rest as padding and finish the parsing
|
||||
@ -948,9 +1022,27 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
|
||||
// Get parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
// Check that there is space for the volume header
|
||||
if ((UINT32)volume.size() < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
|
||||
msg(tr("parseVolumeHeader: input volume size %1h (%2) is smaller than volume header size 40h (64)").hexarg(volume.size()).arg(volume.size()));
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
// Populate volume header
|
||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData());
|
||||
|
||||
// Check sanity of HeaderLength value
|
||||
if ((UINT32)ALIGN8(volumeHeader->HeaderLength) > (UINT32)volume.size()) {
|
||||
msg(tr("parseVolumeHeader: volume header overlaps the end of data"));
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
// Check sanity of ExtHeaderOffset value
|
||||
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset
|
||||
&& (UINT32)ALIGN8(volumeHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)) > (UINT32)volume.size()) {
|
||||
msg(tr("parseVolumeHeader: extended volume header overlaps the end of data"));
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
// Calculate volume header size
|
||||
UINT32 headerSize;
|
||||
EFI_GUID extendedHeaderGuid = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
|
||||
@ -1137,7 +1229,7 @@ STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bio
|
||||
// Check volume header to be sane
|
||||
for (; nextIndex > 0; nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset + nextIndex + 1)) {
|
||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + nextIndex - EFI_FV_SIGNATURE_OFFSET);
|
||||
if (volumeHeader->FvLength >= 0xFFFFFFFFUL) {
|
||||
if (volumeHeader->FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY) || volumeHeader->FvLength >= 0xFFFFFFFFUL) {
|
||||
msg(tr("findNextVolume: volume candidate skipped, has invalid FvLength %1h").hexarg2(volumeHeader->FvLength, 16), index);
|
||||
continue;
|
||||
}
|
||||
@ -1162,6 +1254,10 @@ STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bio
|
||||
|
||||
STATUS FfsParser::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize)
|
||||
{
|
||||
// Check that there is space for the volume header and at least two block map entries.
|
||||
if ((UINT32)bios.size() < volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY))
|
||||
return ERR_INVALID_VOLUME;
|
||||
|
||||
// Populate volume header
|
||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset);
|
||||
|
||||
@ -1182,6 +1278,10 @@ STATUS FfsParser::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UI
|
||||
|
||||
volumeSize = volumeHeader->FvLength;
|
||||
bmVolumeSize = calcVolumeSize;
|
||||
|
||||
if (volumeSize == 0)
|
||||
return ERR_INVALID_VOLUME;
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1202,9 +1302,18 @@ STATUS FfsParser::parseVolumeNonUefiData(const QByteArray & data, const UINT32 p
|
||||
QByteArray padding = data;
|
||||
QByteArray vtf;
|
||||
INT32 vtfIndex = data.lastIndexOf(EFI_FFS_VOLUME_TOP_FILE_GUID);
|
||||
if (vtfIndex > 0) { // VTF found inside non-UEFI data
|
||||
if (vtfIndex >= 0) { // VTF candidate found inside non-UEFI data
|
||||
padding = data.left(vtfIndex);
|
||||
vtf = data.mid(vtfIndex);
|
||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)vtf.constData();
|
||||
if (vtf.size() < sizeof(EFI_FFS_FILE_HEADER) // VTF candidate is too small to be a real VTF in FFSv1/v2 volume
|
||||
|| (pdata.ffsVersion == 3
|
||||
&& (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)
|
||||
&& vtf.size() < sizeof(EFI_FFS_FILE_HEADER2))) { // VTF candidate is too small to be a real VTF in FFSv3 volume
|
||||
vtfIndex = -1;
|
||||
padding = data;
|
||||
vtf.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Add non-UEFI data first
|
||||
@ -1216,7 +1325,7 @@ STATUS FfsParser::parseVolumeNonUefiData(const QByteArray & data, const UINT32 p
|
||||
QModelIndex paddingIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, parsingDataToQByteArray(pdata), index);
|
||||
msg(tr("parseVolumeNonUefiData: non-UEFI data found in volume's free space"), paddingIndex);
|
||||
|
||||
if (vtfIndex > 0) {
|
||||
if (vtfIndex >= 0) {
|
||||
// Get VTF file header
|
||||
QByteArray header = vtf.left(sizeof(EFI_FFS_FILE_HEADER));
|
||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
|
||||
@ -1356,13 +1465,13 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
|
||||
if (model->type(current) != Types::File || model->subtype(current) == EFI_FV_FILETYPE_PAD)
|
||||
continue;
|
||||
QByteArray currentGuid = model->header(current).left(sizeof(EFI_GUID));
|
||||
// Check files after current for having the same GUID
|
||||
// Check files after current for having an equal GUID
|
||||
for (int j = i + 1; j < model->rowCount(index); j++) {
|
||||
QModelIndex another = index.child(j, 0);
|
||||
// Skip non-file entries
|
||||
if (model->type(another) != Types::File)
|
||||
continue;
|
||||
// Check GUIDs for being same
|
||||
// Check GUIDs for being equal
|
||||
QByteArray anotherGuid = model->header(another).left(sizeof(EFI_GUID));
|
||||
if (currentGuid == anotherGuid) {
|
||||
msg(tr("parseVolumeBody: file with duplicate GUID %1").arg(guidToQString(*(const EFI_GUID*)anotherGuid.constData())), another);
|
||||
@ -1392,10 +1501,14 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
|
||||
UINT32 FfsParser::getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion)
|
||||
{
|
||||
if (ffsVersion == 2) {
|
||||
if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER))
|
||||
return 0;
|
||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset);
|
||||
return uint24ToUint32(fileHeader->Size);
|
||||
}
|
||||
else if (ffsVersion == 3) {
|
||||
if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER2))
|
||||
return 0;
|
||||
const EFI_FFS_FILE_HEADER2* fileHeader = (const EFI_FFS_FILE_HEADER2*)(volume.constData() + fileOffset);
|
||||
if (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)
|
||||
return fileHeader->ExtendedSize;
|
||||
@ -1412,6 +1525,9 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
||||
if (file.isEmpty())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER))
|
||||
return ERR_INVALID_FILE;
|
||||
|
||||
// Get parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1419,6 +1535,8 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
||||
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
|
||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
|
||||
if (pdata.ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
|
||||
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2))
|
||||
return ERR_INVALID_FILE;
|
||||
header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
|
||||
}
|
||||
|
||||
@ -1430,9 +1548,9 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
||||
msgUnalignedFile = true;
|
||||
|
||||
// Check file alignment agains volume alignment
|
||||
bool msgFileAlignmentIsGreaterThenVolumes = false;
|
||||
bool msgFileAlignmentIsGreaterThanVolumes = false;
|
||||
if (!pdata.volume.isWeakAligned && pdata.volume.alignment < alignment)
|
||||
msgFileAlignmentIsGreaterThenVolumes = true;
|
||||
msgFileAlignmentIsGreaterThanVolumes = true;
|
||||
|
||||
// Check header checksum
|
||||
QByteArray tempHeader = header;
|
||||
@ -1538,7 +1656,7 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
||||
// Show messages
|
||||
if (msgUnalignedFile)
|
||||
msg(tr("parseFileHeader: unaligned file"), index);
|
||||
if (msgFileAlignmentIsGreaterThenVolumes)
|
||||
if (msgFileAlignmentIsGreaterThanVolumes)
|
||||
msg(tr("parseFileHeader: file alignment %1h is greater than parent volume alignment %2h").hexarg(alignment).hexarg(pdata.volume.alignment), index);
|
||||
if (msgInvalidHeaderChecksum)
|
||||
msg(tr("parseFileHeader: invalid header checksum"), index);
|
||||
@ -1555,10 +1673,14 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
||||
UINT32 FfsParser::getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion)
|
||||
{
|
||||
if (ffsVersion == 2) {
|
||||
if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER))
|
||||
return 0;
|
||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset);
|
||||
return uint24ToUint32(sectionHeader->Size);
|
||||
}
|
||||
else if (ffsVersion == 3) {
|
||||
if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER2))
|
||||
return 0;
|
||||
const EFI_COMMON_SECTION_HEADER2* sectionHeader = (const EFI_COMMON_SECTION_HEADER2*)(file.constData() + sectionOffset);
|
||||
UINT32 size = uint24ToUint32(sectionHeader->Size);
|
||||
if (size == EFI_SECTION2_IS_USED)
|
||||
@ -1732,8 +1854,11 @@ STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex &
|
||||
|
||||
STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
|
||||
switch (sectionHeader->Type) {
|
||||
// Special
|
||||
case EFI_SECTION_COMPRESSION: return parseCompressedSectionHeader(section, parentOffset, parent, index);
|
||||
@ -1764,6 +1889,10 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa
|
||||
|
||||
STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Get data from parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1796,6 +1925,10 @@ STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UIN
|
||||
|
||||
STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(EFI_COMPRESSION_SECTION))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Get data from parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1806,6 +1939,8 @@ STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const
|
||||
UINT8 compressionType = compressedSectionHeader->CompressionType;
|
||||
UINT32 uncompressedLength = compressedSectionHeader->UncompressedLength;
|
||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||
if ((UINT32)section.size() < sizeof(EFI_COMPRESSION_SECTION2))
|
||||
return ERR_INVALID_SECTION;
|
||||
const EFI_COMPRESSION_SECTION2* compressedSectionHeader2 = (const EFI_COMPRESSION_SECTION2*)sectionHeader;
|
||||
headerSize = sizeof(EFI_COMPRESSION_SECTION2);
|
||||
compressionType = compressedSectionHeader2->CompressionType;
|
||||
@ -1839,6 +1974,10 @@ STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const
|
||||
|
||||
STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(EFI_GUID_DEFINED_SECTION))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Get data from parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1848,11 +1987,93 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
|
||||
EFI_GUID guid = guidDefinedSectionHeader->SectionDefinitionGuid;
|
||||
UINT16 dataOffset = guidDefinedSectionHeader->DataOffset;
|
||||
UINT16 attributes = guidDefinedSectionHeader->Attributes;
|
||||
UINT32 nextHeaderOffset = sizeof(EFI_GUID_DEFINED_SECTION);
|
||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||
if ((UINT32)section.size() < sizeof(EFI_GUID_DEFINED_SECTION2))
|
||||
return ERR_INVALID_SECTION;
|
||||
const EFI_GUID_DEFINED_SECTION2* guidDefinedSectionHeader2 = (const EFI_GUID_DEFINED_SECTION2*)sectionHeader;
|
||||
guid = guidDefinedSectionHeader2->SectionDefinitionGuid;
|
||||
dataOffset = guidDefinedSectionHeader2->DataOffset;
|
||||
attributes = guidDefinedSectionHeader2->Attributes;
|
||||
nextHeaderOffset = sizeof(EFI_GUID_DEFINED_SECTION2);
|
||||
}
|
||||
|
||||
// Check for special GUIDed sections
|
||||
QByteArray additionalInfo;
|
||||
QByteArray baGuid((const char*)&guid, sizeof(EFI_GUID));
|
||||
bool msgNoAuthStatusAttribute = false;
|
||||
bool msgNoProcessingRequiredAttributeCompressed = false;
|
||||
bool msgNoProcessingRequiredAttributeSigned = false;
|
||||
bool msgInvalidCrc = false;
|
||||
bool msgUnknownCertType = false;
|
||||
bool msgUnknownCertSubtype = false;
|
||||
if (baGuid == EFI_GUIDED_SECTION_CRC32) {
|
||||
if ((attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == 0) { // Check that AuthStatusValid attribute is set on compressed GUIDed sections
|
||||
msgNoAuthStatusAttribute = true;
|
||||
}
|
||||
|
||||
if ((UINT32)section.size() < nextHeaderOffset + sizeof(UINT32))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
UINT32 crc = *(UINT32*)(section.constData() + nextHeaderOffset);
|
||||
additionalInfo += tr("\nChecksum type: CRC32");
|
||||
// Calculate CRC32 of section data
|
||||
UINT32 calculated = crc32(0, (const UINT8*)section.constData() + dataOffset, section.size() - dataOffset);
|
||||
if (crc == calculated) {
|
||||
additionalInfo += tr("\nChecksum: %1h, valid").hexarg2(crc, 8);
|
||||
}
|
||||
else {
|
||||
additionalInfo += tr("\nChecksum: %1h, invalid, should be %2h").hexarg2(crc, 8).hexarg2(calculated, 8);
|
||||
msgInvalidCrc = true;
|
||||
}
|
||||
// No need to change dataOffset here
|
||||
}
|
||||
else if (baGuid == EFI_GUIDED_SECTION_LZMA || baGuid == EFI_GUIDED_SECTION_TIANO) {
|
||||
if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { // Check that ProcessingRequired attribute is set on compressed GUIDed sections
|
||||
msgNoProcessingRequiredAttributeCompressed = true;
|
||||
}
|
||||
// No need to change dataOffset here
|
||||
}
|
||||
else if (baGuid == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) {
|
||||
if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { // Check that ProcessingRequired attribute is set on signed GUIDed sections
|
||||
msgNoProcessingRequiredAttributeSigned = true;
|
||||
}
|
||||
|
||||
// Get certificate type and length
|
||||
if ((UINT32)section.size() < nextHeaderOffset + sizeof(WIN_CERTIFICATE))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
const WIN_CERTIFICATE* winCertificate = (const WIN_CERTIFICATE*)(section.constData() + nextHeaderOffset);
|
||||
UINT32 certLength = winCertificate->Length;
|
||||
UINT16 certType = winCertificate->CertificateType;
|
||||
|
||||
// Adjust dataOffset
|
||||
dataOffset += certLength;
|
||||
|
||||
// Check section size once again
|
||||
if ((UINT32)section.size() < dataOffset)
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Check certificate type
|
||||
if (certType == WIN_CERT_TYPE_EFI_GUID) {
|
||||
additionalInfo += tr("\nCertificate type: UEFI").hexarg2(certType, 4);
|
||||
|
||||
// Get certificate GUID
|
||||
const WIN_CERTIFICATE_UEFI_GUID* winCertificateUefiGuid = (const WIN_CERTIFICATE_UEFI_GUID*)(section.constData() + nextHeaderOffset);
|
||||
QByteArray certTypeGuid((const char*)&winCertificateUefiGuid->CertType, sizeof(EFI_GUID));
|
||||
|
||||
if (certTypeGuid == EFI_CERT_TYPE_RSA2048_SHA256_GUID) {
|
||||
additionalInfo += tr("\nCertificate subtype: RSA2048/SHA256");
|
||||
}
|
||||
else {
|
||||
additionalInfo += tr("\nCertificate subtype: unknown, GUID %1").arg(guidToQString(winCertificateUefiGuid->CertType));
|
||||
msgUnknownCertSubtype = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
additionalInfo += tr("\nCertificate type: unknown (%1h)").hexarg2(certType, 4);
|
||||
msgUnknownCertType = true;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray header = section.left(dataOffset);
|
||||
@ -1869,20 +2090,40 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
|
||||
.hexarg(dataOffset)
|
||||
.hexarg2(attributes, 4);
|
||||
|
||||
// Append additional info
|
||||
info.append(additionalInfo);
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset += parentOffset;
|
||||
pdata.section.guidDefined.attributes = attributes;
|
||||
pdata.section.guidDefined.guid = guid;
|
||||
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Section, sectionHeader->Type, name, QString(), info, header, body, parsingDataToQByteArray(pdata), parent);
|
||||
|
||||
// Show messages
|
||||
if (msgNoAuthStatusAttribute)
|
||||
msg(tr("parseGuidedSectionHeader: CRC32 GUIDed section without AuthStatusValid attribute"), index);
|
||||
if (msgNoProcessingRequiredAttributeCompressed)
|
||||
msg(tr("parseGuidedSectionHeader: compressed GUIDed section without ProcessingRequired attribute"), index);
|
||||
if (msgNoProcessingRequiredAttributeSigned)
|
||||
msg(tr("parseGuidedSectionHeader: signed GUIDed section without ProcessingRequired attribute"), index);
|
||||
if (msgInvalidCrc)
|
||||
msg(tr("parseGuidedSectionHeader: GUID defined section with invalid CRC32"), index);
|
||||
if (msgUnknownCertType)
|
||||
msg(tr("parseGuidedSectionHeader: signed GUIDed section with unknown type"), index);
|
||||
if (msgUnknownCertSubtype)
|
||||
msg(tr("parseGuidedSectionHeader: signed GUIDed section with unknown subtype"), index);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Get data from parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1892,6 +2133,8 @@ STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, c
|
||||
UINT32 headerSize = sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION);
|
||||
EFI_GUID guid = fsgHeader->SubTypeGuid;
|
||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||
if ((UINT32)section.size() < sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2))
|
||||
return ERR_INVALID_SECTION;
|
||||
const EFI_FREEFORM_SUBTYPE_GUID_SECTION2* fsgHeader2 = (const EFI_FREEFORM_SUBTYPE_GUID_SECTION2*)sectionHeader;
|
||||
headerSize = sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2);
|
||||
guid = fsgHeader2->SubTypeGuid;
|
||||
@ -1925,6 +2168,10 @@ STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, c
|
||||
|
||||
STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(EFI_VERSION_SECTION))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Get data from parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1934,6 +2181,8 @@ STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UI
|
||||
UINT32 headerSize = sizeof(EFI_VERSION_SECTION);
|
||||
UINT16 buildNumber = versionHeader->BuildNumber;
|
||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||
if ((UINT32)section.size() < sizeof(EFI_VERSION_SECTION2))
|
||||
return ERR_INVALID_SECTION;
|
||||
const EFI_VERSION_SECTION2* versionHeader2 = (const EFI_VERSION_SECTION2*)sectionHeader;
|
||||
headerSize = sizeof(EFI_VERSION_SECTION2);
|
||||
buildNumber = versionHeader2->BuildNumber;
|
||||
@ -1963,6 +2212,10 @@ STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UI
|
||||
|
||||
STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if ((UINT32)section.size() < sizeof(POSTCODE_SECTION))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
// Get data from parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
@ -1972,6 +2225,8 @@ STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const U
|
||||
UINT32 headerSize = sizeof(POSTCODE_SECTION);
|
||||
UINT32 postCode = postcodeHeader->Postcode;
|
||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||
if ((UINT32)section.size() < sizeof(POSTCODE_SECTION2))
|
||||
return ERR_INVALID_SECTION;
|
||||
const POSTCODE_SECTION2* postcodeHeader2 = (const POSTCODE_SECTION2*)sectionHeader;
|
||||
headerSize = sizeof(POSTCODE_SECTION2);
|
||||
postCode = postcodeHeader2->Postcode;
|
||||
@ -2005,6 +2260,8 @@ STATUS FfsParser::parseSectionBody(const QModelIndex & index)
|
||||
// Sanity check
|
||||
if (!index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
if ((UINT32)model->header(index).size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(model->header(index).constData());
|
||||
|
||||
@ -2082,7 +2339,6 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
|
||||
|
||||
// Get data from parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
UINT32 attributes = pdata.section.guidDefined.attributes;
|
||||
EFI_GUID guid = pdata.section.guidDefined.guid;
|
||||
|
||||
// Check if section requires processing
|
||||
@ -2090,123 +2346,43 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
|
||||
QString info;
|
||||
bool parseCurrentSection = true;
|
||||
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
|
||||
if (attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) {
|
||||
// Tiano compressed section
|
||||
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
|
||||
algorithm = EFI_STANDARD_COMPRESSION;
|
||||
STATUS result = decompress(model->body(index), algorithm, processed);
|
||||
if (result) {
|
||||
parseCurrentSection = false;
|
||||
msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
|
||||
info += tr("\nCompression algorithm: Tiano");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else if (algorithm == COMPRESSION_ALGORITHM_EFI11) {
|
||||
info += tr("\nCompression algorithm: EFI 1.1");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else
|
||||
info += tr("\nCompression type: unknown");
|
||||
}
|
||||
// LZMA compressed section
|
||||
else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) {
|
||||
algorithm = EFI_CUSTOMIZED_COMPRESSION;
|
||||
STATUS result = decompress(model->body(index), algorithm, processed);
|
||||
if (result) {
|
||||
parseCurrentSection = false;
|
||||
msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
|
||||
info += tr("\nCompression algorithm: LZMA");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else
|
||||
info += tr("\nCompression algorithm: unknown");
|
||||
}
|
||||
// Signed section
|
||||
else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) {
|
||||
UINT8 subtype = 0;
|
||||
bool msgUnknownSubtype = false;
|
||||
const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)model->body(index).constData();
|
||||
QString signInfo = tr("Full Size: %1h (%2)").hexarg2(certificateHeader->Length, 8).arg(certificateHeader->Length);
|
||||
signInfo += tr("\nType: Signature");
|
||||
if (certificateHeader->CertificateType == WIN_CERT_TYPE_EFI_GUID) {
|
||||
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) {
|
||||
signInfo += tr("\nSubtype: RSA2048/SHA256");
|
||||
subtype = Subtypes::UefiSignature;
|
||||
}
|
||||
else if (QByteArray((const char*)&guidCertificateHeader->CertType, sizeof(EFI_GUID)) == EFI_CERT_TYPE_PKCS7_GUID) {
|
||||
signInfo += tr("\nSubtype: PKCS7");
|
||||
subtype = Subtypes::Pkcs7Signature;
|
||||
}
|
||||
else {
|
||||
signInfo += tr("\nSubtype: unknown");
|
||||
msgUnknownSubtype = true;
|
||||
}
|
||||
}
|
||||
else if (certificateHeader->CertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
|
||||
signInfo += tr("\nSubtype: PKCS7");
|
||||
subtype = Subtypes::Pkcs7Signature;
|
||||
}
|
||||
else {
|
||||
signInfo += tr("\nSubtype: unknown");
|
||||
msgUnknownSubtype = true;
|
||||
}
|
||||
|
||||
//Get parsing data
|
||||
PARSING_DATA signPdata = parsingDataFromQModelIndex(index);
|
||||
signPdata.offset += model->header(index).size();
|
||||
if (signPdata.isOnFlash) signInfo.prepend(tr("Offset: %1h\n").hexarg(signPdata.offset));
|
||||
|
||||
// Add signature data to the tree
|
||||
QModelIndex signatureIndex = model->addItem(Types::Signature, subtype, tr("Signature"), "", signInfo, QByteArray(), processed.left(certificateHeader->Length), parsingDataToQByteArray(signPdata), index);
|
||||
|
||||
// Show messages
|
||||
msg(tr("parseGuidedSectionBody: signature may become invalid after any modification"), signatureIndex);
|
||||
if (msgUnknownSubtype)
|
||||
msg(tr("parseGuidedSectionBody: signature with unknown subtype"), signatureIndex);
|
||||
|
||||
// Change offset
|
||||
pdata.offset += certificateHeader->Length;
|
||||
|
||||
// Get new body
|
||||
processed = processed.mid(certificateHeader->Length);
|
||||
}
|
||||
// Unknown GUIDed section
|
||||
else {
|
||||
// Tiano compressed section
|
||||
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
|
||||
algorithm = EFI_STANDARD_COMPRESSION;
|
||||
STATUS result = decompress(model->body(index), algorithm, processed);
|
||||
if (result) {
|
||||
parseCurrentSection = false;
|
||||
msg(tr("parseGuidedSectionBody: GUID defined section with unknown processing method"), index);
|
||||
msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if section requires checksum calculation
|
||||
if (attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID)
|
||||
{
|
||||
// CRC32 section
|
||||
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_CRC32) {
|
||||
info += tr("\nChecksum type: CRC32");
|
||||
// Calculate CRC32 of section data
|
||||
QByteArray body = model->body(index);
|
||||
UINT32 crc = crc32(0, (const UINT8*)body.constData(), body.size());
|
||||
// Check stored CRC32
|
||||
UINT32 stored = *(const UINT32*)(model->header(index).constData() + sizeof(EFI_GUID_DEFINED_SECTION));
|
||||
if (crc == stored) {
|
||||
info += tr("\nChecksum %1h: valid").hexarg2(stored, 8);
|
||||
}
|
||||
else {
|
||||
info += tr("\nChecksum %1h: invalid").hexarg2(stored, 8);
|
||||
msg(tr("parseGuidedSectionBody: GUID defined section with invalid CRC32"), index);
|
||||
}
|
||||
if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
|
||||
info += tr("\nCompression algorithm: Tiano");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else if (algorithm == COMPRESSION_ALGORITHM_EFI11) {
|
||||
info += tr("\nCompression algorithm: EFI 1.1");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else
|
||||
msg(tr("parseGuidedSectionBody: GUID defined section with unknown authentication method"), index);
|
||||
info += tr("\nCompression type: unknown");
|
||||
}
|
||||
// LZMA compressed section
|
||||
else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) {
|
||||
algorithm = EFI_CUSTOMIZED_COMPRESSION;
|
||||
STATUS result = decompress(model->body(index), algorithm, processed);
|
||||
if (result) {
|
||||
parseCurrentSection = false;
|
||||
msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
|
||||
info += tr("\nCompression algorithm: LZMA");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else
|
||||
info += tr("\nCompression algorithm: unknown");
|
||||
}
|
||||
|
||||
// Add info
|
||||
@ -2246,8 +2422,10 @@ STATUS FfsParser::parseDepexSectionBody(const QModelIndex & index)
|
||||
QString parsed;
|
||||
|
||||
// Check data to be present
|
||||
if (!body.size())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END
|
||||
msg(tr("parseDepexSectionBody: DEPEX section too short"), index);
|
||||
return ERR_DEPEX_PARSE_FAILED;
|
||||
}
|
||||
|
||||
const EFI_GUID * guid;
|
||||
const UINT8* current = (const UINT8*)body.constData();
|
||||
@ -2364,7 +2542,7 @@ STATUS FfsParser::parseUiSectionBody(const QModelIndex & index)
|
||||
if (!index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
QString text = QString::fromUtf16((const ushort*)model->body(index).constData());
|
||||
QString text = QString::fromUtf16((const ushort*)model->body(index).constData(), model->body(index).size()/2);
|
||||
|
||||
// Add info
|
||||
model->addInfo(index, tr("\nText: %1").arg(text));
|
||||
@ -2377,8 +2555,11 @@ STATUS FfsParser::parseUiSectionBody(const QModelIndex & index)
|
||||
|
||||
STATUS FfsParser::parseAprioriRawSection(const QByteArray & body, QString & parsed)
|
||||
{
|
||||
// Sanity check
|
||||
if (body.size() % sizeof(EFI_GUID)) {
|
||||
msg(tr("parseAprioriRawSection: apriori file has size is not a multiple of 16"));
|
||||
}
|
||||
parsed.clear();
|
||||
|
||||
UINT32 count = body.size() / sizeof(EFI_GUID);
|
||||
if (count > 0) {
|
||||
for (UINT32 i = 0; i < count; i++) {
|
||||
@ -2437,72 +2618,98 @@ STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index)
|
||||
|
||||
// Get section body
|
||||
QByteArray body = model->body(index);
|
||||
if ((UINT32)body.size() < sizeof(EFI_IMAGE_DOS_HEADER)) {
|
||||
msg(tr("parsePeImageSectionBody: section body size is smaller than DOS header size"), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Get PE info
|
||||
QByteArray info;
|
||||
|
||||
const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData();
|
||||
if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
||||
info += tr("\nDOS signature: %1h, invalid").hexarg2(dosHeader->e_magic, 4);
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS signature"), index);
|
||||
model->addInfo(index, info);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew);
|
||||
if (body.size() < (UINT8*)peHeader - (UINT8*)dosHeader) {
|
||||
info += tr("\nDOS header: invalid");
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS header"), index);
|
||||
model->addInfo(index, info);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) {
|
||||
info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8);
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE signature"), index);
|
||||
model->addInfo(index, info);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1);
|
||||
if (body.size() < (UINT8*)imageFileHeader - (UINT8*)dosHeader) {
|
||||
info += tr("\nPE header: invalid");
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE header"), index);
|
||||
model->addInfo(index, info);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
info += tr("\nDOS signature: %1h\nPE signature: %2h\nMachine type: %3\nNumber of sections: %4\nCharacteristics: %5h")
|
||||
.hexarg2(dosHeader->e_magic, 4)
|
||||
.hexarg2(peHeader->Signature, 8)
|
||||
.arg(machineTypeToQString(imageFileHeader->Machine))
|
||||
.arg(imageFileHeader->NumberOfSections)
|
||||
.hexarg2(imageFileHeader->Characteristics, 4);
|
||||
|
||||
EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader;
|
||||
optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1);
|
||||
if (body.size() < (UINT8*)optionalHeader.H32 - (UINT8*)dosHeader) {
|
||||
info += tr("\nPE optional header: invalid");
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE optional header"), index);
|
||||
model->addInfo(index, info);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) {
|
||||
info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h")
|
||||
.hexarg2(optionalHeader.H32->Magic, 4)
|
||||
.hexarg2(optionalHeader.H32->Subsystem, 4)
|
||||
.hexarg(optionalHeader.H32->AddressOfEntryPoint)
|
||||
.hexarg(optionalHeader.H32->BaseOfCode)
|
||||
.hexarg(optionalHeader.H32->ImageBase);
|
||||
}
|
||||
else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) {
|
||||
info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h")
|
||||
.hexarg2(optionalHeader.H64->Magic, 4)
|
||||
.hexarg2(optionalHeader.H64->Subsystem, 4)
|
||||
.hexarg(optionalHeader.H64->AddressOfEntryPoint)
|
||||
.hexarg(optionalHeader.H64->BaseOfCode)
|
||||
.hexarg(optionalHeader.H64->ImageBase);
|
||||
}
|
||||
else {
|
||||
const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew);
|
||||
if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) {
|
||||
info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8);
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE signature"), index);
|
||||
}
|
||||
else {
|
||||
const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1);
|
||||
info += tr("\nDOS signature: %1h\nPE signature: %2h\nMachine type: %3\nNumber of sections: %4\nCharacteristics: %5h")
|
||||
.hexarg2(dosHeader->e_magic, 4)
|
||||
.hexarg2(peHeader->Signature, 8)
|
||||
.arg(machineTypeToQString(imageFileHeader->Machine))
|
||||
.arg(imageFileHeader->NumberOfSections)
|
||||
.hexarg2(imageFileHeader->Characteristics, 4);
|
||||
|
||||
EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader;
|
||||
optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1);
|
||||
if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) {
|
||||
info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h")
|
||||
.hexarg2(optionalHeader.H32->Magic, 4)
|
||||
.hexarg2(optionalHeader.H32->Subsystem, 4)
|
||||
.hexarg(optionalHeader.H32->AddressOfEntryPoint)
|
||||
.hexarg(optionalHeader.H32->BaseOfCode)
|
||||
.hexarg(optionalHeader.H32->ImageBase);
|
||||
}
|
||||
else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) {
|
||||
info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h")
|
||||
.hexarg2(optionalHeader.H64->Magic, 4)
|
||||
.hexarg2(optionalHeader.H64->Subsystem, 4)
|
||||
.hexarg(optionalHeader.H64->AddressOfEntryPoint)
|
||||
.hexarg(optionalHeader.H64->BaseOfCode)
|
||||
.hexarg(optionalHeader.H64->ImageBase);
|
||||
}
|
||||
else {
|
||||
info += tr("\nOptional header signature: %1h, unknown").hexarg2(optionalHeader.H64->Magic, 4);
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid optional PE header signature"), index);
|
||||
}
|
||||
}
|
||||
info += tr("\nOptional header signature: %1h, unknown").hexarg2(optionalHeader.H32->Magic, 4);
|
||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid optional PE header signature"), index);
|
||||
}
|
||||
|
||||
// Add PE info
|
||||
model->addInfo(index, info);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index)
|
||||
{
|
||||
// Sanity check
|
||||
// Check sanity
|
||||
if (!index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
// Get section body
|
||||
QByteArray body = model->body(index);
|
||||
if ((UINT32)body.size() < sizeof(EFI_IMAGE_TE_HEADER)) {
|
||||
msg(tr("parsePeImageSectionBody: section body size is smaller than TE header size"), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Get TE info
|
||||
QByteArray info;
|
||||
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData();
|
||||
if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
|
||||
@ -2611,4 +2818,3 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,6 @@ typedef struct _COMPRESSED_SECTION_PARSING_DATA {
|
||||
|
||||
typedef struct _GUIDED_SECTION_PARSING_DATA {
|
||||
EFI_GUID guid;
|
||||
UINT32 attributes;
|
||||
} GUIDED_SECTION_PARSING_DATA;
|
||||
|
||||
typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
|
||||
|
@ -93,6 +93,7 @@ QString errorCodeToQString(UINT8 errorCode)
|
||||
//case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
|
||||
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
|
||||
case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated");
|
||||
case ERR_INVALID_CAPSULE: return QObject::tr("Invalid capsule");
|
||||
default: return QObject::tr("Unknown error %1").arg(errorCode);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user