UT 0.19.6, UE 0.3.5, UP 0.2.5

- added support for firmware volumes with CRC32 stored in ZeroVector
(Apple UEFI feature)
- ZeroVector included to FV information
- added new volume types AppleCRC, AppleCRC Boot and AppleCRC Unknown
- added support for HP POSTCode sections
- size information split into header size and body size
- decimal sizes are added, shown in braces after hexadecimal sizes
- corrected small bug with Extract Body action being enabled for items
with empty body
This commit is contained in:
Nikolaj Schlej 2015-01-25 23:55:05 +01:00
parent 476929bc4f
commit fb7e1c4c89
8 changed files with 171 additions and 82 deletions

View file

@ -52,7 +52,7 @@ int main(int argc, char *argv[])
} }
else { else {
std::cout << "UEFIExtract 0.3.3" << std::endl << std::endl << std::cout << "UEFIExtract 0.3.5" << std::endl << std::endl <<
"Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << 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; "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; return 1;

View file

@ -31,7 +31,7 @@ int main(int argc, char *argv[])
result = w.patchFromFile(a.arguments().at(1)); result = w.patchFromFile(a.arguments().at(1));
} }
else { else {
std::cout << "UEFIPatch 0.2.4 - UEFI image file patching utility" << std::endl << std::endl << std::cout << "UEFIPatch 0.2.5 - UEFI image file patching utility" << std::endl << std::endl <<
"Usage: UEFIPatch image_file" << std::endl << std::endl << "Usage: UEFIPatch image_file" << std::endl << std::endl <<
"Patches will be read from patches.txt file\n"; "Patches will be read from patches.txt file\n";
return ERR_SUCCESS; return ERR_SUCCESS;

View file

@ -160,6 +160,8 @@ QString sectionTypeToQString(const UINT8 type)
return QObject::tr("PEI dependency"); return QObject::tr("PEI dependency");
case EFI_SECTION_SMM_DEPEX: case EFI_SECTION_SMM_DEPEX:
return QObject::tr("SMM dependency"); return QObject::tr("SMM dependency");
case HP_SECTION_POSTCODE:
return QObject::tr("HP postcode");
case SCT_SECTION_POSTCODE: case SCT_SECTION_POSTCODE:
return QObject::tr("SCT postcode"); return QObject::tr("SCT postcode");
default: default:
@ -205,8 +207,10 @@ UINT32 sizeOfSectionHeader(EFI_COMMON_SECTION_HEADER* header)
return sizeof(EFI_PEI_DEPEX_SECTION); return sizeof(EFI_PEI_DEPEX_SECTION);
case EFI_SECTION_SMM_DEPEX: case EFI_SECTION_SMM_DEPEX:
return sizeof(EFI_SMM_DEPEX_SECTION); return sizeof(EFI_SMM_DEPEX_SECTION);
case HP_SECTION_POSTCODE:
return sizeof(POSTCODE_SECTION);
case SCT_SECTION_POSTCODE: case SCT_SECTION_POSTCODE:
return sizeof(SCT_POSTCODE_SECTION); return sizeof(POSTCODE_SECTION);
default: default:
return sizeof(EFI_COMMON_SECTION_HEADER); return sizeof(EFI_COMMON_SECTION_HEADER);
} }

5
ffs.h
View file

@ -361,6 +361,7 @@ typedef struct {
#define EFI_SECTION_PEI_DEPEX 0x1B #define EFI_SECTION_PEI_DEPEX 0x1B
#define EFI_SECTION_SMM_DEPEX 0x1C #define EFI_SECTION_SMM_DEPEX 0x1C
#define SCT_SECTION_POSTCODE 0xF0 // Specific to Phoenix SCT images #define SCT_SECTION_POSTCODE 0xF0 // Specific to Phoenix SCT images
#define HP_SECTION_POSTCODE 0x20 // Specific to HP images
// Compression section // Compression section
typedef struct { typedef struct {
@ -415,12 +416,12 @@ typedef struct {
EFI_GUID SubTypeGuid; EFI_GUID SubTypeGuid;
} EFI_FREEFORM_SUBTYPE_GUID_SECTION; } EFI_FREEFORM_SUBTYPE_GUID_SECTION;
// Phoenix SCT postcode section // Phoenix SCT and HP postcode section
typedef struct { typedef struct {
UINT8 Size[3]; UINT8 Size[3];
UINT8 Type; UINT8 Type;
UINT32 Postcode; UINT32 Postcode;
} SCT_POSTCODE_SECTION; } POSTCODE_SECTION;
// Other sections // Other sections
typedef EFI_COMMON_SECTION_HEADER EFI_DISPOSABLE_SECTION; typedef EFI_COMMON_SECTION_HEADER EFI_DISPOSABLE_SECTION;

View file

@ -257,10 +257,10 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
QByteArray header = buffer.left(capsuleHeaderSize); QByteArray header = buffer.left(capsuleHeaderSize);
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize); QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
QString name = tr("UEFI capsule"); QString name = tr("UEFI capsule");
QString info = tr("Header size: 0x%1\nFlags: 0x%2\nImage size: 0x%3") QString info = tr("Header size: 0x%1(%2)\nFlags: 0x%3\nImage size: 0x%4(%5)")
.hexarg(capsuleHeader->HeaderSize, 8) .hexarg(capsuleHeader->HeaderSize, 4).arg(capsuleHeader->HeaderSize)
.hexarg(capsuleHeader->Flags, 8) .hexarg(capsuleHeader->Flags, 8)
.hexarg(capsuleHeader->CapsuleImageSize, 8); .hexarg(capsuleHeader->CapsuleImageSize, 8).arg(capsuleHeader->HeaderSize);
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body); index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
} }
@ -273,10 +273,10 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
QByteArray header = buffer.left(capsuleHeaderSize); QByteArray header = buffer.left(capsuleHeaderSize);
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize); QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
QString name = tr("AMI Aptio capsule"); QString name = tr("AMI Aptio capsule");
QString info = tr("Header size: 0x%1\nFlags: 0x%2\nImage size: 0x%3") QString info = tr("Header size: 0x%1(%2)\nFlags: 0x%3\nImage size: 0x%4(%5)")
.hexarg(aptioCapsuleHeader->RomImageOffset, 4) .hexarg(capsuleHeaderSize, 4).arg(capsuleHeaderSize)
.hexarg(aptioCapsuleHeader->CapsuleHeader.Flags, 8) .hexarg(aptioCapsuleHeader->CapsuleHeader.Flags, 8)
.hexarg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - aptioCapsuleHeader->RomImageOffset, 8); .hexarg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - capsuleHeaderSize, 8).arg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - capsuleHeaderSize);
//!TODO: more info about Aptio capsule //!TODO: more info about Aptio capsule
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, Subtypes::AptioCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body); index = model->addItem(Types::Capsule, Subtypes::AptioCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
@ -300,8 +300,8 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
// Get info // Get info
QString name = tr("BIOS image"); QString name = tr("BIOS image");
QString info = tr("Size: 0x%1") QString info = tr("Size: 0x%1(%2)")
.hexarg(flashImage.size(), 8); .hexarg(flashImage.size(), 8).arg(flashImage.size());
// Add tree item // Add tree item
index = model->addItem(Types::Image, Subtypes::BiosImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), index); index = model->addItem(Types::Image, Subtypes::BiosImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), flashImage, QByteArray(), index);
@ -436,8 +436,8 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
// Intel image // Intel image
name = tr("Intel image"); name = tr("Intel image");
info = tr("Size: 0x%1\nFlash chips: %2\nRegions: %3\nMasters: %4\nPCH straps: %5\nPROC straps: %6\nICC table entries: %7") info = tr("Size: 0x%1(%2)\nFlash chips: %3\nRegions: %4\nMasters: %5\nPCH straps: %6\nPROC straps: %7\nICC table entries: %8")
.hexarg(intelImage.size(), 8) .hexarg(intelImage.size(), 8).arg(intelImage.size())
.arg(descriptorMap->NumberOfFlashChips + 1) // .arg(descriptorMap->NumberOfFlashChips + 1) //
.arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage .arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage
.arg(descriptorMap->NumberOfMasters + 1) // .arg(descriptorMap->NumberOfMasters + 1) //
@ -452,7 +452,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
// Get descriptor info // Get descriptor info
body = intelImage.left(FLASH_DESCRIPTOR_SIZE); body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
name = tr("Descriptor region"); name = tr("Descriptor region");
info = tr("Size: 0x%1").hexarg(FLASH_DESCRIPTOR_SIZE, 8); info = tr("Size: 0x%1(%2)").hexarg(FLASH_DESCRIPTOR_SIZE, 8).arg(FLASH_DESCRIPTOR_SIZE);
// Check regions presence once again // Check regions presence once again
QVector<UINT32> offsets; QVector<UINT32> offsets;
@ -557,8 +557,8 @@ UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, con
QString name = tr("GbE region"); QString name = tr("GbE region");
GBE_MAC* mac = (GBE_MAC*)gbe.constData(); GBE_MAC* mac = (GBE_MAC*)gbe.constData();
GBE_VERSION* version = (GBE_VERSION*)(gbe.constData() + GBE_VERSION_OFFSET); GBE_VERSION* version = (GBE_VERSION*)(gbe.constData() + GBE_VERSION_OFFSET);
QString info = tr("Size: 0x%1\nMAC: %2:%3:%4:%5:%6:%7\nVersion: %8.%9") QString info = tr("Size: 0x%1(%2)\nMAC: %3:%4:%5:%6:%7:%8\nVersion: %9.%10")
.hexarg(gbe.size(), 8) .hexarg(gbe.size(), 8).arg(gbe.size())
.hexarg(mac->vendor[0], 2) .hexarg(mac->vendor[0], 2)
.hexarg(mac->vendor[1], 2) .hexarg(mac->vendor[1], 2)
.hexarg(mac->vendor[2], 2) .hexarg(mac->vendor[2], 2)
@ -581,8 +581,8 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
// Get info // Get info
QString name = tr("ME region"); QString name = tr("ME region");
QString info = tr("Size: 0x%1"). QString info = tr("Size: 0x%1(%2)").
hexarg(me.size(), 8); hexarg(me.size(), 8).arg(me.size());
// Search for new signature // Search for new signature
INT32 versionOffset = me.indexOf(ME_VERSION_SIGNATURE2); INT32 versionOffset = me.indexOf(ME_VERSION_SIGNATURE2);
@ -622,8 +622,8 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con
// Get info // Get info
QString name = tr("PDR region"); QString name = tr("PDR region");
QString info = tr("Size: 0x%1"). QString info = tr("Size: 0x%1(%2)").
hexarg(pdr.size(), 8); hexarg(pdr.size(), 8).arg(pdr.size());
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent, mode); index = model->addItem(Types::Region, Subtypes::PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent, mode);
@ -643,8 +643,8 @@ UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, c
// Get info // Get info
QString name = tr("BIOS region"); QString name = tr("BIOS region");
QString info = tr("Size: 0x%1"). QString info = tr("Size: 0x%1(%2)").
hexarg(bios.size(), 8); hexarg(bios.size(), 8).arg(bios.size());
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent, mode); index = model->addItem(Types::Region, Subtypes::BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent, mode);
@ -678,8 +678,8 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
// Get info // Get info
QByteArray padding = bios.left(prevVolumeOffset); QByteArray padding = bios.left(prevVolumeOffset);
name = tr("Padding"); name = tr("Padding");
info = tr("Size: 0x%1") info = tr("Size: 0x%1(%2)")
.hexarg(padding.size(), 8); .hexarg(padding.size(), 8).arg(padding.size());
// Add tree item // Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
@ -704,8 +704,8 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
QByteArray padding = bios.mid(prevVolumeOffset + prevVolumeSize, paddingSize); QByteArray padding = bios.mid(prevVolumeOffset + prevVolumeSize, paddingSize);
// Get info // Get info
name = tr("Padding"); name = tr("Padding");
info = tr("Size: 0x%1") info = tr("Size: 0x%1(%2)")
.hexarg(padding.size(), 8); .hexarg(padding.size(), 8).arg(padding.size());
// Add tree item // Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
} }
@ -778,8 +778,8 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
QByteArray padding = bios.right(endPaddingSize); QByteArray padding = bios.right(endPaddingSize);
// Get info // Get info
name = tr("Padding"); name = tr("Padding");
info = tr("Size: 0x%1") info = tr("Size: 0x%1(%2)")
.hexarg(padding.size(), 8); .hexarg(padding.size(), 8).arg(padding.size());
// Add tree item // Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent); model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, QByteArray(), parent);
} }
@ -857,7 +857,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
else if (QByteArray((const char*)&volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM_GUID) { else if (QByteArray((const char*)&volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM_GUID) {
// Code can be added here // Code can be added here
} }
// Apple Boot Volume FFS GUID // Apple Boot Volume 2 FFS GUID
else if (QByteArray((const char*)&volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM2_GUID) { else if (QByteArray((const char*)&volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM2_GUID) {
// Code can be added here // Code can be added here
} }
@ -880,32 +880,52 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
// Get volume size // Get volume size
UINT8 result;
UINT32 volumeSize; UINT32 volumeSize;
UINT32 bmVolumeSize; UINT32 bmVolumeSize;
result = getVolumeSize(volume, 0, volumeSize, bmVolumeSize); UINT8 result = getVolumeSize(volume, 0, volumeSize, bmVolumeSize);
if (result) if (result)
return result; return result;
// Check for Apple CRC32 in ZeroVector
UINT32 crc32FromZeroVector = *(UINT32*)(volume.constData() + 8);
if (crc32FromZeroVector != 0) {
// Calculate CRC32 of the volume body
UINT32 crc = crc32(0, NULL, 0);
crc = crc32(crc, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
if (crc == crc32FromZeroVector) {
subtype = (subtype == Subtypes::UnknownVolume) ? Subtypes::UnknownAppleCrcVolume : Subtypes::AppleCrcVolume;
}
}
// Check header checksum by recalculating it // Check header checksum by recalculating it
if (subtype == Subtypes::NormalVolume && calculateChecksum16((UINT16*)volumeHeader, volumeHeader->HeaderLength)) if ((subtype == Subtypes::NormalVolume || subtype == Subtypes::AppleCrcVolume) && calculateChecksum16((UINT16*)volumeHeader, volumeHeader->HeaderLength))
msgInvalidChecksum = true; msgInvalidChecksum = true;
// Get info // Get info
QString name = guidToQString(volumeHeader->FileSystemGuid); QString name = guidToQString(volumeHeader->FileSystemGuid);
QString info = tr("FileSystem GUID: %1\nSize: 0x%2\nRevision: %3\nAttributes: 0x%4\nErase polarity: %5\nHeader size: 0x%6") QString info = tr("FileSystem GUID: %1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nRevision: %6\nAttributes: 0x%7\nErase polarity: %8\nZeroVector:\n%9 %10 %11 %12 %13 %14 %15 %16\n%17 %18 %19 %20 %21 %22 %23 %24")
.arg(guidToQString(volumeHeader->FileSystemGuid)) .arg(guidToQString(volumeHeader->FileSystemGuid))
.hexarg(volumeSize, 8) .hexarg(headerSize, 8).arg(headerSize)
.hexarg(volumeSize - headerSize, 8).arg(volumeSize - headerSize)
.arg(volumeHeader->Revision) .arg(volumeHeader->Revision)
.hexarg(volumeHeader->Attributes, 8) .hexarg(volumeHeader->Attributes, 8)
.arg(empty ? "1" : "0") .arg(empty ? "1" : "0")
.hexarg(headerSize, 8); .hexarg(volumeHeader->ZeroVector[0], 2).hexarg(volumeHeader->ZeroVector[1], 2).hexarg(volumeHeader->ZeroVector[2], 2).hexarg(volumeHeader->ZeroVector[3], 2)
.hexarg(volumeHeader->ZeroVector[4], 2).hexarg(volumeHeader->ZeroVector[5], 2).hexarg(volumeHeader->ZeroVector[6], 2).hexarg(volumeHeader->ZeroVector[7], 2)
.hexarg(volumeHeader->ZeroVector[8], 2).hexarg(volumeHeader->ZeroVector[9], 2).hexarg(volumeHeader->ZeroVector[10], 2).hexarg(volumeHeader->ZeroVector[11], 2)
.hexarg(volumeHeader->ZeroVector[12], 2).hexarg(volumeHeader->ZeroVector[13], 2).hexarg(volumeHeader->ZeroVector[14], 2).hexarg(volumeHeader->ZeroVector[15], 2);
// Apple CRC32 volume
if (subtype == Subtypes::AppleCrcVolume || subtype == Subtypes::UnknownAppleCrcVolume) {
info += tr("\nCRC32 in ZeroVector: valid");
}
// Extended header present // Extended header present
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset); EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset);
info += tr("\nExtended header size: 0x%1\nVolume name: %2") info += tr("\nExtended header size: 0x%1(%2)\nVolume GUID: %3")
.hexarg(extendedHeader->ExtHeaderSize, 8) .hexarg(extendedHeader->ExtHeaderSize, 8).arg(extendedHeader->ExtHeaderSize)
.arg(guidToQString(extendedHeader->FvName)); .arg(guidToQString(extendedHeader->FvName));
} }
@ -921,7 +941,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
msg(tr("parseVolume: Volume header checksum is invalid"), index); msg(tr("parseVolume: Volume header checksum is invalid"), index);
// Do not parse the contents of volumes other then normal // Do not parse the contents of volumes other then normal
if (subtype != Subtypes::NormalVolume) if (subtype != Subtypes::NormalVolume && subtype != Subtypes::AppleCrcVolume)
return ERR_SUCCESS; return ERR_SUCCESS;
// Search for and parse all files // Search for and parse all files
@ -1069,10 +1089,16 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
break; break;
case EFI_FV_FILETYPE_SECURITY_CORE: case EFI_FV_FILETYPE_SECURITY_CORE:
// Set parent volume type to BootVolume // Set parent volume type to BootVolume
if (model->subtype(parent) == Subtypes::AppleCrcVolume || model->subtype(parent) == Subtypes::BootAppleCrcVolume)
model->setSubtype(parent, Subtypes::BootAppleCrcVolume);
else
model->setSubtype(parent, Subtypes::BootVolume); model->setSubtype(parent, Subtypes::BootVolume);
break; break;
case EFI_FV_FILETYPE_PEI_CORE: case EFI_FV_FILETYPE_PEI_CORE:
// Set parent volume type to BootVolume // Set parent volume type to BootVolume
if (model->subtype(parent) == Subtypes::AppleCrcVolume || model->subtype(parent) == Subtypes::BootAppleCrcVolume)
model->setSubtype(parent, Subtypes::BootAppleCrcVolume);
else
model->setSubtype(parent, Subtypes::BootVolume); model->setSubtype(parent, Subtypes::BootVolume);
break; break;
case EFI_FV_FILETYPE_DXE_CORE: case EFI_FV_FILETYPE_DXE_CORE:
@ -1118,11 +1144,12 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
name = guidToQString(fileHeader->Name); name = guidToQString(fileHeader->Name);
else else
name = tr("Padding"); name = tr("Padding");
info = tr("Name: %1\nType: 0x%2\nAttributes: 0x%3\nSize: 0x%4\nState: 0x%5") info = tr("Name: %1\nType: 0x%2\nAttributes: 0x%3\nHeader size: 0x%4(%5)\nBody size: 0x%6(%7)\nState: 0x%8")
.arg(guidToQString(fileHeader->Name)) .arg(guidToQString(fileHeader->Name))
.hexarg(fileHeader->Type, 2) .hexarg(fileHeader->Type, 2)
.hexarg(fileHeader->Attributes, 2) .hexarg(fileHeader->Attributes, 2)
.hexarg(uint24ToUint32(fileHeader->Size), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(uint24ToUint32(fileHeader->Size) - header.size(), 6).arg(uint24ToUint32(fileHeader->Size) - header.size())
.hexarg(fileHeader->State, 2); .hexarg(fileHeader->State, 2);
// Add tree item // Add tree item
@ -1333,11 +1360,12 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
parseCurrentSection = false; parseCurrentSection = false;
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2\nCompression type: %3\nDecompressed size: 0x%4") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nCompression type: %6\nDecompressed size: 0x%7(%8)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.arg(compressionTypeToQString(algorithm)) .arg(compressionTypeToQString(algorithm))
.hexarg(compressedSectionHeader->UncompressedLength, 8); .hexarg(compressedSectionHeader->UncompressedLength, 8).arg(compressedSectionHeader->UncompressedLength);
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, algorithm, name, "", info, header, body, QByteArray(), parent, mode);
@ -1370,10 +1398,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
// Get info // Get info
name = guidToQString(guidDefinedSectionHeader->SectionDefinitionGuid); name = guidToQString(guidDefinedSectionHeader->SectionDefinitionGuid);
info = tr("GUID: %1\nType: 0x%2\nSize: 0x%3\nData offset: 0x%4\nAttributes: 0x%5") info = tr("GUID: %1\nType: 0x%2\nHeader size: 0x%3(%4)\nBody size: 0x%5(%6)\nData offset: 0x%7\nAttributes: 0x%8")
.arg(name) .arg(name)
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.hexarg(guidDefinedSectionHeader->DataOffset, 4) .hexarg(guidDefinedSectionHeader->DataOffset, 4)
.hexarg(guidDefinedSectionHeader->Attributes, 4); .hexarg(guidDefinedSectionHeader->Attributes, 4);
@ -1390,11 +1419,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
if (algorithm == COMPRESSION_ALGORITHM_TIANO) { if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
info += tr("\nCompression type: Tiano"); info += tr("\nCompression type: Tiano");
info += tr("\nDecompressed size: 0x%1").hexarg(decompressed.length(), 8); info += tr("\nDecompressed size: 0x%1(%2)").hexarg(decompressed.length(), 8).arg(decompressed.length());
} }
else if (algorithm == COMPRESSION_ALGORITHM_EFI11) { else if (algorithm == COMPRESSION_ALGORITHM_EFI11) {
info += tr("\nCompression type: EFI 1.1"); info += tr("\nCompression type: EFI 1.1");
info += tr("\nDecompressed size: 0x%1").hexarg(decompressed.length(), 8); info += tr("\nDecompressed size: 0x%1(%2)").hexarg(decompressed.length(), 8).arg(decompressed.length());
} }
else else
info += tr("\nCompression type: unknown"); info += tr("\nCompression type: unknown");
@ -1409,7 +1438,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
if (algorithm == COMPRESSION_ALGORITHM_LZMA) { if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
info += tr("\nCompression type: LZMA"); info += tr("\nCompression type: LZMA");
info += tr("\nDecompressed size: 0x%1").hexarg(decompressed.length(), 8); info += tr("\nDecompressed size: 0x%1(%2)").hexarg(decompressed.length(), 8).arg(decompressed.length());
} }
else else
info += tr("\nCompression type: unknown"); info += tr("\nCompression type: unknown");
@ -1461,15 +1490,15 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
if (!parseCurrentSection) { if (!parseCurrentSection) {
msg(tr("parseSection: GUID defined section can not be processed"), index); msg(tr("parseSection: GUID defined section can not be processed"), index);
} }
else if (parseAsIntelSigned) { // Parse as intel signed sections else if (parseAsIntelSigned) { // Parse as Intel signed sections
// Get signature // Get signature
QByteArray signature = body.left(*(UINT32*)body.constData()); QByteArray signature = body.left(*(UINT32*)body.constData());
// Get info for it // Get info for it
QString signatureInfo = tr("Size: 0x%1").hexarg(signature.size(), 8); QString signatureInfo = tr("Size: 0x%1(%2)").hexarg(signature.size(), 8).arg(signature.size());
// Add it to the tree // Add it to the tree
model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Padding"), tr("Intel signature"), signatureInfo, QByteArray(), signature, QByteArray(), index, mode); model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Padding"), tr("Intel signature"), signatureInfo, QByteArray(), signature, QByteArray(), index, mode);
// Get internal lzma section data // Get internal LZMA section data
QByteArray lzmaSection = body.mid(signature.size()); QByteArray lzmaSection = body.mid(signature.size());
// Parse internal sections // Parse internal sections
result = parseSections(lzmaSection, index); result = parseSections(lzmaSection, index);
@ -1489,9 +1518,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
body = section.mid(sizeof(EFI_DISPOSABLE_SECTION), sectionSize - sizeof(EFI_DISPOSABLE_SECTION)); body = section.mid(sizeof(EFI_DISPOSABLE_SECTION), sectionSize - sizeof(EFI_DISPOSABLE_SECTION));
// Get info // Get info
info = tr("parseSection: 0x%1\nSize: 0x%2") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6); .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@ -1513,9 +1543,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
body = section.mid(headerSize, sectionSize - headerSize); body = section.mid(headerSize, sectionSize - headerSize);
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6); .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size());
// Parse dependency expression // Parse dependency expression
QString str; QString str;
@ -1542,9 +1573,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
body = section.mid(headerSize, sectionSize - headerSize); body = section.mid(headerSize, sectionSize - headerSize);
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6); .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@ -1565,9 +1597,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
EFI_FREEFORM_SUBTYPE_GUID_SECTION* fsgHeader = (EFI_FREEFORM_SUBTYPE_GUID_SECTION*)sectionHeader; EFI_FREEFORM_SUBTYPE_GUID_SECTION* fsgHeader = (EFI_FREEFORM_SUBTYPE_GUID_SECTION*)sectionHeader;
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2\nSubtype GUID: %3") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nSubtype GUID: %6")
.hexarg(fsgHeader->Type, 2) .hexarg(fsgHeader->Type, 2)
.hexarg(body.size(), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.arg(guidToQString(fsgHeader->SubTypeGuid)); .arg(guidToQString(fsgHeader->SubTypeGuid));
// Add tree item // Add tree item
@ -1581,9 +1614,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
EFI_VERSION_SECTION* versionHeader = (EFI_VERSION_SECTION*)sectionHeader; EFI_VERSION_SECTION* versionHeader = (EFI_VERSION_SECTION*)sectionHeader;
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2\nBuild number: %3\nVersion string: %4") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nBuild number: %6\nVersion string: %7")
.hexarg(versionHeader->Type, 2) .hexarg(versionHeader->Type, 2)
.hexarg(body.size(), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.arg(versionHeader->BuildNumber) .arg(versionHeader->BuildNumber)
.arg(QString::fromUtf16((const ushort*)body.constData())); .arg(QString::fromUtf16((const ushort*)body.constData()));
@ -1597,9 +1631,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
QString text = QString::fromUtf16((const ushort*)body.constData()); QString text = QString::fromUtf16((const ushort*)body.constData());
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2\nText: %3") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nText: %6")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.arg(text); .arg(text);
// Add tree item // Add tree item
@ -1614,9 +1649,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
body = section.mid(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION), sectionSize - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION)); body = section.mid(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION), sectionSize - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6); .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@ -1635,9 +1671,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
body = section.mid(sizeof(EFI_RAW_SECTION), sectionSize - sizeof(EFI_RAW_SECTION)); body = section.mid(sizeof(EFI_RAW_SECTION), sectionSize - sizeof(EFI_RAW_SECTION));
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6); .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size());
// Check for apriori file // Check for apriori file
QModelIndex parentFile = model->findParentOfType(parent, Types::File); QModelIndex parentFile = model->findParentOfType(parent, Types::File);
@ -1682,16 +1719,35 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
} }
} }
break; break;
case SCT_SECTION_POSTCODE: {
header = section.left(sizeof(SCT_POSTCODE_SECTION));
body = section.mid(sizeof(SCT_POSTCODE_SECTION), sectionSize - sizeof(SCT_POSTCODE_SECTION));
SCT_POSTCODE_SECTION* postcodeHeader = (SCT_POSTCODE_SECTION*)sectionHeader; case HP_SECTION_POSTCODE: {
header = section.left(sizeof(POSTCODE_SECTION));
body = section.mid(sizeof(POSTCODE_SECTION), sectionSize - sizeof(POSTCODE_SECTION));
POSTCODE_SECTION* postcodeHeader = (POSTCODE_SECTION*)sectionHeader;
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2\nPostcode: 0x%3") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nPostcode: 0x%6")
.hexarg(postcodeHeader->Type, 2) .hexarg(postcodeHeader->Type, 2)
.hexarg(body.size(), 6) .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.hexarg(postcodeHeader->Postcode, 2);
// Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
}
break;
case SCT_SECTION_POSTCODE: {
header = section.left(sizeof(POSTCODE_SECTION));
body = section.mid(sizeof(POSTCODE_SECTION), sectionSize - sizeof(POSTCODE_SECTION));
POSTCODE_SECTION* postcodeHeader = (POSTCODE_SECTION*)sectionHeader;
// Get info
info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)\nPostcode: 0x%6")
.hexarg(postcodeHeader->Type, 2)
.hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size())
.hexarg(postcodeHeader->Postcode, 2); .hexarg(postcodeHeader->Postcode, 2);
// Add tree item // Add tree item
@ -1703,9 +1759,10 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
header = section.left(sizeof(EFI_COMMON_SECTION_HEADER)); header = section.left(sizeof(EFI_COMMON_SECTION_HEADER));
body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER)); body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
// Get info // Get info
info = tr("Type: 0x%1\nSize: 0x%2") info = tr("Type: 0x%1\nHeader size: 0x%2(%3)\nBody size: 0x%4(%5)")
.hexarg(sectionHeader->Type, 2) .hexarg(sectionHeader->Type, 2)
.hexarg(body.size(), 6); .hexarg(header.size(), 2).arg(header.size())
.hexarg(body.size(), 6).arg(body.size());
// Add tree item // Add tree item
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
@ -2844,6 +2901,24 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
// Reconstruction successful // Reconstruction successful
reconstructed = header.append(reconstructed); reconstructed = header.append(reconstructed);
// Recalculate CRC32 in ZeroVector, if needed
if (model->subtype(index) == Subtypes::AppleCrcVolume || model->subtype(index) == Subtypes::UnknownAppleCrcVolume) {
// Get current CRC32 value from volume header
UINT32 current = *(UINT32*)(reconstructed.constData() + 8);
// Calculate new value
UINT32 crc = crc32(0, NULL, 0);
crc = crc32(crc, (const UINT8*)reconstructed.constData() + volumeHeader->HeaderLength, reconstructed.size() - volumeHeader->HeaderLength);
// Update the value
if (current != crc) {
*(UINT32*)(reconstructed.data() + 8) = crc;
// Recalculate header checksum again
volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)reconstructed.data();
volumeHeader->Checksum = 0;
volumeHeader->Checksum = calculateChecksum16((UINT16*)volumeHeader, volumeHeader->HeaderLength);
}
}
return ERR_SUCCESS; return ERR_SUCCESS;
} }

View file

@ -85,6 +85,12 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
return QObject::tr("Unknown"); return QObject::tr("Unknown");
else if (subtype == Subtypes::NvramVolume) else if (subtype == Subtypes::NvramVolume)
return QObject::tr("NVRAM"); return QObject::tr("NVRAM");
else if (subtype == Subtypes::AppleCrcVolume)
return QObject::tr("AppleCRC");
else if (subtype == Subtypes::UnknownAppleCrcVolume)
return QObject::tr("AppleCRC Unknown");
else if (subtype == Subtypes::BootAppleCrcVolume)
return QObject::tr("AppleCRC Boot");
else else
return ""; return "";
case Types::Capsule: case Types::Capsule:

View file

@ -59,7 +59,10 @@ namespace Subtypes {
NormalVolume = 90, NormalVolume = 90,
BootVolume, BootVolume,
UnknownVolume, UnknownVolume,
NvramVolume NvramVolume,
AppleCrcVolume,
UnknownAppleCrcVolume,
BootAppleCrcVolume
}; };
enum RegionSubtypes { enum RegionSubtypes {

View file

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) : UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::UEFITool), ui(new Ui::UEFITool),
version(tr("0.19.5")) version(tr("0.19.6"))
{ {
clipboard = QApplication::clipboard(); clipboard = QApplication::clipboard();
@ -140,7 +140,7 @@ void UEFITool::populateUi(const QModelIndex &current)
// Enable actions // Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current)); ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
ui->actionRebuild->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section); ui->actionRebuild->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionExtractBody->setDisabled(model->hasEmptyHeader(current)); ui->actionExtractBody->setDisabled(model->hasEmptyBody(current));
ui->actionRemove->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section); ui->actionRemove->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionInsertInto->setEnabled((type == Types::Volume && subtype != Subtypes::UnknownVolume) || ui->actionInsertInto->setEnabled((type == Types::Volume && subtype != Subtypes::UnknownVolume) ||
(type == Types::File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD) || (type == Types::File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD) ||