diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index 44a4db3..e6319c5 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.30.0_alpha3")) +version(tr("0.30.0_alpha4")) { clipboard = QApplication::clipboard(); diff --git a/common/ffsbuilder.cpp b/common/ffsbuilder.cpp index 3394954..7d2a9eb 100644 --- a/common/ffsbuilder.cpp +++ b/common/ffsbuilder.cpp @@ -37,9 +37,15 @@ void FfsBuilder::clearMessages() messagesVector.clear(); } -STATUS FfsBuilder::build(const QModelIndex & root, QByteArray & image) +STATUS FfsBuilder::erase(const QModelIndex & index, QByteArray & erased) { - return ERR_NOT_IMPLEMENTED; + // Sanity check + if (!index.isValid()) + return ERR_INVALID_PARAMETER; + + PARSING_DATA pdata = parsingDataFromQByteArray(index); + erased.fill(pdata.emptyByte); + return ERR_SUCCESS; } STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) @@ -63,20 +69,24 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) // Clear the supplied QByteArray capsule.clear(); - // Reconstruct children + // Build children for (int i = 0; i < model->rowCount(index); i++) { QModelIndex currentChild = index.child(i, 0); QByteArray currentData; // Check child type if (model->type(currentChild) == Types::Image) { - result = buildImage(currentChild, currentData); - if (!result) { - capsule.append(currentData); - } - else { + if (model->subtype(currentChild) == Subtypes::IntelImage) + result = buildIntelImage(currentChild, currentData); + else + result = buildRawArea(currentChild, currentData); + + // Check build result + if (result) { msg(tr("buildCapsule: building of \"%1\" failed with error \"%2\", original item data used").arg(model->name(currentChild)).arg(errorCodeToQString(result)), currentChild); capsule.append(model->header(currentChild)).append(model->body(currentChild)); } + else + capsule.append(currentData); } else { msg(tr("buildCapsule: unexpected child item of type \"%1\" can't be processed, original item data used").arg(itemTypeToQString(model->type(currentChild))), currentChild); @@ -85,18 +95,16 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) } // Check size of reconstructed capsule, it must remain the same - if (capsule.size() > model->body(index).size()) { + UINT32 newSize = capsule.size(); + UINT32 oldSize = model->body(index).size(); + if (newSize > oldSize) { msg(tr("buildCapsule: new capsule size %1h (%2) is bigger than the original %3h (%4)") - .hexarg(capsule.size()).arg(capsule.size()) - .hexarg(model->body(index).size()).arg(model->body(index).size()), - index); + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize),index); return ERR_INVALID_PARAMETER; } - else if (capsule.size() < model->body(index).size()) { + else if (newSize < oldSize) { msg(tr("buildCapsule: new capsule size %1h (%2) is smaller than the original %3h (%4)") - .hexarg(capsule.size()).arg(capsule.size()) - .hexarg(model->body(index).size()).arg(model->body(index).size()), - index); + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); return ERR_INVALID_PARAMETER; } } @@ -107,16 +115,197 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) capsule = model->header(index).append(capsule); return ERR_SUCCESS; } + msg(tr("buildCapsule: unexpected action \"%1\"").arg(actionTypeToQString(model->action(index))), index); return ERR_NOT_IMPLEMENTED; } -STATUS FfsBuilder::buildImage(const QModelIndex & index, QByteArray & intelImage) +STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intelImage) { + if (!index.isValid()) + return ERR_SUCCESS; + + UINT8 result; + + // No action + if (model->action(index) == Actions::NoAction) { + intelImage = model->header(index).append(model->body(index)); + return ERR_SUCCESS; + } + + // Other supported actions + else if (model->action(index) == Actions::Rebuild) { + intelImage.clear(); + // First child will always be descriptor for this type of image + QByteArray descriptor; + result = buildRegion(index.child(0, 0), descriptor); + if (result) + return result; + intelImage.append(descriptor); + + const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor.constData() + sizeof(FLASH_DESCRIPTOR_HEADER)); + const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase); + QByteArray gbe; + UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); + UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); + QByteArray me; + UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); + UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); + QByteArray bios; + UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); + UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + QByteArray pdr; + UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); + UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); + + UINT32 offset = descriptor.size(); + // Reconstruct other regions + char empty = '\xFF'; + for (int i = 1; i < model->rowCount(index); i++) { + QByteArray region; + result = buildRegion(index.child(i, 0), region); + if (result) + return result; + + UINT8 type = model->subtype(index.child(i, 0)); + switch (type) + { + case Subtypes::GbeRegion: + gbe = region; + if (gbeBegin > offset) + intelImage.append(QByteArray(gbeBegin - offset, empty)); + intelImage.append(gbe); + offset = gbeEnd; + break; + case Subtypes::MeRegion: + me = region; + if (meBegin > offset) + intelImage.append(QByteArray(meBegin - offset, empty)); + intelImage.append(me); + offset = meEnd; + break; + case Subtypes::BiosRegion: + bios = region; + if (biosBegin > offset) + intelImage.append(QByteArray(biosBegin - offset, empty)); + intelImage.append(bios); + offset = biosEnd; + break; + case Subtypes::PdrRegion: + pdr = region; + if (pdrBegin > offset) + intelImage.append(QByteArray(pdrBegin - offset, empty)); + intelImage.append(pdr); + offset = pdrEnd; + break; + default: + msg(tr("buildIntelImage: unknown region type found"), index); + return ERR_INVALID_REGION; + } + } + if ((UINT32)model->body(index).size() > offset) + intelImage.append(QByteArray((UINT32)model->body(index).size() - offset, empty)); + + // Check size of new image, it must be same as old one + UINT32 newSize = intelImage.size(); + UINT32 oldSize = model->body(index).size(); + if (newSize > oldSize) { + msg(tr("buildIntelImage: new image size %1h (%2) is bigger than the original %3h (%4)") + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); + return ERR_INVALID_PARAMETER; + } + else if (newSize < oldSize) { + msg(tr("buildIntelImage: new image size %1h (%2) is smaller than the original %3h (%4)") + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); + return ERR_INVALID_PARAMETER; + } + + // Reconstruction successful + return ERR_SUCCESS; + } + + msg(tr("buildIntelImage: unexpected action \"%1\"").arg(actionTypeToQString(model->action(index))), index); return ERR_NOT_IMPLEMENTED; } -STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea) +STATUS FfsBuilder::buildRegion(const QModelIndex & index, QByteArray & region) +{ + if (!index.isValid()) + return ERR_SUCCESS; + + UINT8 result; + + // No action required + if (model->action(index) == Actions::NoAction) { + region = model->header(index).append(model->body(index)); + return ERR_SUCCESS; + } + + // Erase + else if (model->action(index) == Actions::Erase) { + region = model->header(index).append(model->body(index)); + if (erase(index, region)) + msg(tr("buildRegion: erase failed, original item data used"), index); + return ERR_SUCCESS; + } + + // Rebuild or replace + else if (model->action(index) == Actions::Rebuild || + model->action(index) == Actions::Replace) { + if (model->rowCount(index)) { + region.clear(); + // Build children + for (int i = 0; i < model->rowCount(index); i++) { + QModelIndex currentChild = index.child(i, 0); + QByteArray currentData; + // Check child type + if (model->type(currentChild) == Types::Volume) { + result = buildVolume(currentChild, currentData); + } + else if (model->type(currentChild) == Types::Padding) { + result = buildPadding(currentChild, currentData); + } + else { + msg(tr("buildRegion: unexpected child item of type \"%1\" can't be processed, original item data used").arg(itemTypeToQString(model->type(currentChild))), currentChild); + result = ERR_SUCCESS; + currentData = model->header(currentChild).append(model->body(currentChild)); + } + // Check build result + if (result) { + msg(tr("buildRegion: building of \"%1\" failed with error \"%2\", original item data used").arg(model->name(currentChild)).arg(errorCodeToQString(result)), currentChild); + currentData = model->header(currentChild).append(model->body(currentChild)); + } + // Append current data + region.append(currentData); + } + } + else + region = model->body(index); + + // Check size of new region, it must be same as original one + UINT32 newSize = region.size(); + UINT32 oldSize = model->body(index).size(); + if (newSize > oldSize) { + msg(tr("buildRegion: new region size %1h (%2) is bigger than the original %3h (%4)") + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); + return ERR_INVALID_PARAMETER; + } + else if (newSize < oldSize) { + msg(tr("buildRegion: new region size %1h (%2) is smaller than the original %3h (%4)") + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); + return ERR_INVALID_PARAMETER; + } + + // Build successful + region = model->header(index).append(region); + return ERR_SUCCESS; + } + + msg(tr("buildRegion: unexpected action \"%1\"").arg(actionTypeToQString(model->action(index))), index); + return ERR_NOT_IMPLEMENTED; +} + +STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea, bool addHeader) { // Sanity check if (!index.isValid()) @@ -137,7 +326,7 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea) // Clear the supplied QByteArray rawArea.clear(); - // Reconstruct children + // Build children for (int i = 0; i < model->rowCount(index); i++) { QModelIndex currentChild = index.child(i, 0); QByteArray currentData; @@ -162,27 +351,26 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea) rawArea.append(currentData); } - // Check size of reconstructed raw area, it must remain the same - if (rawArea.size() > model->body(index).size()) { - msg(tr("buildRawArea: new raw area size %1h (%2) is bigger than the original %3h (%4)") - .hexarg(rawArea.size()).arg(rawArea.size()) - .hexarg(model->body(index).size()).arg(model->body(index).size()), - index); + // Check size of new raw area, it must be same as original one + UINT32 newSize = rawArea.size(); + UINT32 oldSize = model->body(index).size(); + if (newSize > oldSize) { + msg(tr("buildRawArea: new area size %1h (%2) is bigger than the original %3h (%4)") + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); return ERR_INVALID_PARAMETER; } - else if (rawArea.size() < model->body(index).size()) { - msg(tr("buildRawArea: new raw area size %1h (%2) is smaller than the original %3h (%4)") - .hexarg(rawArea.size()).arg(rawArea.size()) - .hexarg(model->body(index).size()).arg(model->body(index).size()), - index); + else if (newSize < oldSize) { + msg(tr("buildRawArea: new area size %1h (%2) is smaller than the original %3h (%4)") + .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index); return ERR_INVALID_PARAMETER; } } else rawArea = model->body(index); - // Build successful, append header - rawArea = model->header(index).append(rawArea); + // Build successful, add header if needed + if (addHeader) + rawArea = model->header(index).append(rawArea); return ERR_SUCCESS; } @@ -190,11 +378,6 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea) return ERR_NOT_IMPLEMENTED; } -STATUS FfsBuilder::buildVolume(const QModelIndex & index, QByteArray & volume) -{ - return ERR_NOT_IMPLEMENTED; -} - STATUS FfsBuilder::buildPadding(const QModelIndex & index, QByteArray & padding) { // Sanity check @@ -209,7 +392,9 @@ STATUS FfsBuilder::buildPadding(const QModelIndex & index, QByteArray & padding) // Erase else if (model->action(index) == Actions::Erase) { - padding.fill('\xFF', model->header(index).size() + model->body(index).size()); + padding = model->header(index).append(model->body(index)); + if(erase(index, padding)) + msg(tr("buildPadding: erase failed, original item data used"), index); return ERR_SUCCESS; } @@ -231,7 +416,9 @@ STATUS FfsBuilder::buildNonUefiData(const QModelIndex & index, QByteArray & data // Erase else if (model->action(index) == Actions::Erase) { - data.fill('\xFF', model->header(index).size() + model->body(index).size()); + data = model->header(index).append(model->body(index)); + if (erase(index, data)) + msg(tr("buildNonUefiData: erase failed, original item data used"), index); return ERR_SUCCESS; } @@ -255,6 +442,11 @@ STATUS FfsBuilder::buildFreeSpace(const QModelIndex & index, QByteArray & freeSp return ERR_NOT_IMPLEMENTED; } +STATUS FfsBuilder::buildVolume(const QModelIndex & index, QByteArray & volume) +{ + return ERR_NOT_IMPLEMENTED; +} + STATUS FfsBuilder::buildPadFile(const QModelIndex & index, QByteArray & padFile) { return ERR_NOT_IMPLEMENTED; @@ -270,3 +462,7 @@ STATUS FfsBuilder::buildSection(const QModelIndex & index, QByteArray & section) return ERR_NOT_IMPLEMENTED; } +STATUS FfsBuilder::build(const QModelIndex & root, QByteArray & image) +{ + return ERR_NOT_IMPLEMENTED; +} diff --git a/common/ffsbuilder.h b/common/ffsbuilder.h index 6f136d7..dbd2805 100644 --- a/common/ffsbuilder.h +++ b/common/ffsbuilder.h @@ -21,6 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "../common/basetypes.h" #include "../common/treemodel.h" +#include "../common/descriptor.h" #include "../common/ffs.h" #include "../common/utility.h" @@ -44,17 +45,19 @@ private: // UEFI standard structures STATUS buildCapsule(const QModelIndex & index, QByteArray & capsule); - STATUS buildImage(const QModelIndex & index, QByteArray & intelImage); + STATUS buildIntelImage(const QModelIndex & index, QByteArray & intelImage); STATUS buildRegion(const QModelIndex & index, QByteArray & region); - STATUS buildRawArea(const QModelIndex & index, QByteArray & rawArea); - STATUS buildVolume(const QModelIndex & index, QByteArray & volume); + STATUS buildRawArea(const QModelIndex & index, QByteArray & rawArea, bool addHeader = true); STATUS buildPadding(const QModelIndex & index, QByteArray & padding); + STATUS buildVolume(const QModelIndex & index, QByteArray & volume); STATUS buildNonUefiData(const QModelIndex & index, QByteArray & data); STATUS buildFreeSpace(const QModelIndex & index, QByteArray & freeSpace); STATUS buildPadFile(const QModelIndex & index, QByteArray & padFile); STATUS buildFile(const QModelIndex & index, QByteArray & file); STATUS buildSection(const QModelIndex & index, QByteArray & section); + // Utility functions + STATUS erase(const QModelIndex & index, QByteArray & erased); }; #endif diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index e824c28..93d7725 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -153,7 +153,19 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex & QModelIndex biosIndex = model->addItem(Types::Image, Subtypes::UefiImage, name, QString(), info, QByteArray(), flashImage, parsingDataToQByteArray(pdata), index); // Parse the image - return parseRawArea(flashImage, biosIndex); + result = parseRawArea(flashImage, biosIndex); + if (result) + return result; + + // Check if the last VTF is found + if (!lastVtf.isValid()) { + msg(tr("parseImageFile: not a single Volume Top File is found, physical memory addresses can't be calculated"), biosIndex); + } + else { + return addMemoryAddressesInfo(biosIndex); + } + + return ERR_SUCCESS; } STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & index) @@ -397,6 +409,14 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelInd return result; } + // Check if the last VTF is found + if (!lastVtf.isValid()) { + msg(tr("parseIntelImage: not a single Volume Top File is found, physical memory addresses can't be calculated"), index); + } + else { + return addMemoryAddressesInfo(index); + } + return ERR_SUCCESS; } @@ -595,6 +615,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde // Construct parsing data pdata.fixed = TRUE; + pdata.offset = offset + headerSize; if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset)); // Add tree item @@ -731,7 +752,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare // 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 } }; + EFI_GUID extendedHeaderGuid = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; bool hasExtendedHeader = false; if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { hasExtendedHeader = true; @@ -1216,6 +1237,17 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf .hexarg(body.size()).arg(body.size()) .hexarg2(fileHeader->State, 2); + // Check if the file is a Volume Top File + QString text; + bool isVtf = false; + if (EFI_FFS_VOLUME_TOP_FILE_GUID == header.left(sizeof(EFI_GUID))) { + // Mark it as the last VTF + // This information will later be used to determine memory addresses of uncompressed image elements + // Because the last byte of the last VFT is mapped to 0xFFFFFFFF physical memory address + isVtf = true; + text = tr("Volume Top File"); + } + // Construct parsing data pdata.fixed = fileHeader->Attributes & FFS_ATTRIB_FIXED; pdata.offset += parentOffset; @@ -1224,7 +1256,12 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset)); // Add tree item - index = model->addItem(Types::File, fileHeader->Type, name, "", info, header, body, parsingDataToQByteArray(pdata), parent); + index = model->addItem(Types::File, fileHeader->Type, name, text, info, header, body, parsingDataToQByteArray(pdata), parent); + + // Overwrite lastVtf, if needed + if (isVtf) { + lastVtf = index; + } // Show messages if (msgUnalignedFile) @@ -1435,9 +1472,9 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa case EFI_SECTION_DXE_DEPEX: case EFI_SECTION_PEI_DEPEX: case EFI_SECTION_SMM_DEPEX: - case EFI_SECTION_TE: case EFI_SECTION_PE32: case EFI_SECTION_PIC: + case EFI_SECTION_TE: case EFI_SECTION_COMPATIBILITY16: case EFI_SECTION_USER_INTERFACE: case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: @@ -1732,6 +1769,7 @@ STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const U return ERR_SUCCESS; } + STATUS FfsParser::parseSectionBody(const QModelIndex & index) { // Sanity check @@ -1751,9 +1789,9 @@ STATUS FfsParser::parseSectionBody(const QModelIndex & index) case EFI_SECTION_DXE_DEPEX: case EFI_SECTION_PEI_DEPEX: case EFI_SECTION_SMM_DEPEX: return parseDepexSectionBody(index); - case EFI_SECTION_TE: return ERR_SUCCESS;//return parseTeSectionBody(index); + case EFI_SECTION_TE: return parseTeImageSectionBody(index); case EFI_SECTION_PE32: - case EFI_SECTION_PIC: return ERR_SUCCESS;//return parsePeSectionBody(index); + case EFI_SECTION_PIC: return parsePeImageSectionBody(index); case EFI_SECTION_USER_INTERFACE: return parseUiSectionBody(index); case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return parseRawArea(model->body(index), index); case EFI_SECTION_RAW: return parseRawSectionBody(index); @@ -2109,37 +2147,29 @@ STATUS FfsParser::parseRawSectionBody(const QModelIndex & index) return parseRawArea(model->body(index), index); } -/* -STATUS FfsEngine::parsePeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) -{ - const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); - UINT32 headerSize = sizeOfSectionHeader(sectionHeader); - QByteArray header = section.left(headerSize); - QByteArray body = section.mid(headerSize); - // Get standard info - QString name = sectionTypeToQString(sectionHeader->Type) + tr(" section"); - QString info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)") - .hexarg2(sectionHeader->Type, 2) - .hexarg(section.size()).arg(section.size()) - .hexarg(header.size()).arg(header.size()) - .hexarg(body.size()).arg(body.size()); +STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index) +{ + // Sanity check + if (!index.isValid()) + return ERR_INVALID_PARAMETER; + + // Get section body + QByteArray body = model->body(index); // Get PE info - bool msgInvalidDosSignature = false; - bool msgInvalidPeSignature = false; - bool msgUnknownOptionalHeaderSignature = false; + 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); - msgInvalidDosSignature = true; + msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS signature"), index); } 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); - msgInvalidPeSignature = true; + msg(tr("parsePeImageSectionBody: PE32 image with invalid PE signature"), index); } else { const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1); @@ -2153,82 +2183,53 @@ STATUS FfsEngine::parsePeSectionHeader(const QByteArray & section, const UINT32 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\nRelativeEntryPoint: %3h\nBaseOfCode: %4h\nImageBase: %5h\nEntryPoint: %6h") + info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entryPoint: %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) - .hexarg(optionalHeader.H32->ImageBase + optionalHeader.H32->AddressOfEntryPoint); + .hexarg(optionalHeader.H32->ImageBase); } else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { - info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nRelativeEntryPoint: %3h\nBaseOfCode: %4h\nImageBase: %5h\nEntryPoint: %6h") + info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entryPoint: %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) - .hexarg(optionalHeader.H64->ImageBase + optionalHeader.H64->AddressOfEntryPoint); + .hexarg(optionalHeader.H64->ImageBase); } else { info += tr("\nOptional header signature: %1h, unknown").hexarg2(optionalHeader.H64->Magic, 4); - msgUnknownOptionalHeaderSignature = true; + msg(tr("parsePeImageSectionBody: PE32 image with invalid optional PE header signature"), index); } } } - // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); + // Add PE info + model->addInfo(index, info); - // Show messages - if (msgInvalidDosSignature) { - msg("parseSection: PE32 image with invalid DOS signature", index); - } - if (msgInvalidPeSignature) { - msg("parseSection: PE32 image with invalid PE signature", index); - } - if (msgUnknownOptionalHeaderSignature) { - msg("parseSection: PE32 image with unknown optional header signature", index); - } - - // Special case of PEI Core - QModelIndex core = model->findParentOfType(index, Types::File); - if (core.isValid() && model->subtype(core) == EFI_FV_FILETYPE_PEI_CORE - && oldPeiCoreEntryPoint == 0) { - result = getEntryPoint(model->body(index), oldPeiCoreEntryPoint); - if (result) - msg(tr("parseSection: can't get original PEI core entry point"), index); - } return ERR_SUCCESS; } -*/ -/* -STATUS FfsEngine::parseTeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) + +STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index) { - const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); - UINT32 headerSize = sizeOfSectionHeader(sectionHeader); - QByteArray header = section.left(headerSize); - QByteArray body = section.mid(headerSize); + // Sanity check + if (!index.isValid()) + return ERR_INVALID_PARAMETER; - // Get standard info - QString name = sectionTypeToQString(sectionHeader->Type) + tr(" section"); - QString info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)") - .hexarg2(sectionHeader->Type, 2) - .hexarg(section.size()).arg(section.size()) - .hexarg(header.size()).arg(header.size()) - .hexarg(body.size()).arg(body.size()); + // Get section body + QByteArray body = model->body(index); // Get TE info - bool msgInvalidSignature = false; + QByteArray info; const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData(); - UINT32 teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) { info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4); - msgInvalidSignature = true; + msg(tr("parseTeImageSectionBody: TE image with invalid TE signature"), index); } else { - info += tr("\nSignature: %1h\nMachine type: %2\nNumber of sections: %3\nSubsystem: %4h\nStrippedSize: %5h (%6)\nBaseOfCode: %7h\nRelativeEntryPoint: %8h\nImageBase: %9h\nEntryPoint: %10h") + info += tr("\nSignature: %1h\nMachine type: %2\nNumber of sections: %3\nSubsystem: %4h\nStripped size: %5h (%6)\nBase of code: %7h\nAddress of entry point: %8h\nImage base: %9h\nAdjusted image base: %10h") .hexarg2(teHeader->Signature, 4) .arg(machineTypeToQString(teHeader->Machine)) .arg(teHeader->NumberOfSections) @@ -2237,51 +2238,95 @@ STATUS FfsEngine::parseTeSectionHeader(const QByteArray & section, const UINT32 .hexarg(teHeader->BaseOfCode) .hexarg(teHeader->AddressOfEntryPoint) .hexarg(teHeader->ImageBase) - .hexarg(teHeader->ImageBase + teHeader->AddressOfEntryPoint - teFixup); - } - // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); - - // Show messages - if (msgInvalidSignature) { - msg("parseSection: TE image with invalid TE signature", index); + .hexarg(teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER)); } - // Special case of PEI Core - QModelIndex core = model->findParentOfType(index, Types::File); - if (core.isValid() && model->subtype(core) == EFI_FV_FILETYPE_PEI_CORE - && oldPeiCoreEntryPoint == 0) { - result = getEntryPoint(model->body(index), oldPeiCoreEntryPoint); - if (result) - msg(tr("parseSection: can't get original PEI core entry point"), index); - } + // Get data from parsing data + PARSING_DATA pdata = parsingDataFromQByteArray(index); + pdata.section.teImage.imageBase = teHeader->ImageBase; + pdata.section.teImage.adjustedImageBase = teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); + + // Update parsing data + model->setParsingData(index, parsingDataToQByteArray(pdata)); + + // Add TE info + model->addInfo(index, info); + return ERR_SUCCESS; } -STATUS FfsEngine::parseFirmwareVolumeImageSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) + +STATUS FfsParser::addMemoryAddressesInfo(const QModelIndex & index) { - const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); - QByteArray header = section.left(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION)); - QByteArray body = section.mid(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION)); + // Sanity check + if (!index.isValid() || !lastVtf.isValid()) + return ERR_INVALID_PARAMETER; - // Get info - QString name = sectionTypeToQString(sectionHeader->Type) + tr(" section"); - QString info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)") - .hexarg2(sectionHeader->Type, 2) - .hexarg(section.size()).arg(section.size()) - .hexarg(header.size()).arg(header.size()) - .hexarg(body.size()).arg(body.size()); - - // Add tree item - index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); - - // Parse section body as BIOS space - result = parseBios(body, index); - if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) { - msg(tr("parseSection: parsing firmware volume image section as BIOS failed with error \"%1\"").arg(errorMessage(result)), index); - return result; + // Get parsing data for the last VTF + PARSING_DATA pdata = parsingDataFromQByteArray(lastVtf); + if (!pdata.isOnFlash) { + msg(tr("addPhysicalAddressInfo: the last VTF appears inside compressed item, the image may be damaged"), lastVtf); + return ERR_SUCCESS; } - return ERR_SUCCESS; -} -*/ + // Calculate address difference + const UINT32 vtfSize = model->header(lastVtf).size() + model->body(lastVtf).size() + (pdata.file.hasTail ? sizeof(UINT16) : 0); + const UINT32 diff = 0xFFFFFFFF - pdata.offset - vtfSize + 1; + + // Apply address information to index and all it's child items + return addMemoryAddressesRecursive(index, diff); +} + +STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff) +{ + // Sanity check + if (!index.isValid()) + return ERR_SUCCESS; + + // Get parsing data for the current item + PARSING_DATA pdata = parsingDataFromQByteArray(index); + + // Set address value for non-compressed data + if (pdata.isOnFlash) { + // Check address sanity + if ((const UINT64)diff + pdata.offset <= 0xFFFFFFFF) { + // Update info + pdata.address = diff + pdata.offset; + UINT32 headerSize = model->header(index).size(); + if (headerSize) { + model->addInfo(index, tr("\nHeader memory address: %1h").hexarg2(pdata.address, 8)); + model->addInfo(index, tr("\nData memory address: %1h").hexarg2(pdata.address + headerSize, 8)); + } + else { + model->addInfo(index, tr("\nMemory address: %1h").hexarg2(pdata.address, 8)); + } + + // Special case of uncompressed TE image sections + if (model->type(index) == Types::Section && model->subtype(index) == EFI_SECTION_TE && pdata.isOnFlash) { + // Check data memory address to be equal to either ImageBase or AdjustedImageBase + if (pdata.section.teImage.imageBase == pdata.address + headerSize) { + pdata.section.teImage.revision = 1; + model->addInfo(index, tr("\nTE image format revision: %1").arg(pdata.section.teImage.revision)); + } + else if (pdata.section.teImage.adjustedImageBase == pdata.address + headerSize) { + pdata.section.teImage.revision = 2; + model->addInfo(index, tr("\nTE image format revision: %1").arg(pdata.section.teImage.revision)); + } + else { + msg(tr("addMemoryAddressesRecursive: image base is nether original nor adjusted, the image is either damaged or a part of backup PEI volume"), index); + pdata.section.teImage.revision = 0; + } + } + + // Set modified parsing data + model->setParsingData(index, parsingDataToQByteArray(pdata)); + } + } + + // Process child items + for (int i = 0; i < model->rowCount(index); i++) { + addMemoryAddressesRecursive(index.child(i, 0), diff); + } + + return ERR_SUCCESS; +} \ No newline at end of file diff --git a/common/ffsparser.h b/common/ffsparser.h index 2229421..df19cdc 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -53,13 +53,10 @@ public: STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseSectionBody(const QModelIndex & index); - /*// Search routines TODO: move to another class - // Extract routine TODO: move to another class - STATUS extract(const QModelIndex & index, QString & name, QByteArray & extracted, const UINT8 mode);*/ - private: TreeModel *model; QVector > messagesVector; + QModelIndex lastVtf; STATUS parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & root); STATUS parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); @@ -83,6 +80,8 @@ private: STATUS parseDepexSectionBody(const QModelIndex & index); STATUS parseUiSectionBody(const QModelIndex & index); STATUS parseRawSectionBody(const QModelIndex & index); + STATUS parsePeImageSectionBody(const QModelIndex & index); + STATUS parseTeImageSectionBody(const QModelIndex & index); UINT8 getPaddingType(const QByteArray & padding); STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed); @@ -91,6 +90,9 @@ private: UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion); UINT32 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion); + STATUS addMemoryAddressesInfo(const QModelIndex & index); + STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff); + // Internal operations BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2); diff --git a/common/parsingdata.h b/common/parsingdata.h index 8feec51..3be8071 100644 --- a/common/parsingdata.h +++ b/common/parsingdata.h @@ -61,11 +61,18 @@ typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA { EFI_GUID guid; } FREEFORM_GUIDED_SECTION_PARSING_DATA; +typedef struct _TE_IMAGE_SECTION_PARSING_DATA { + UINT32 imageBase; + UINT32 adjustedImageBase; + UINT8 revision; +} TE_IMAGE_SECTION_PARSING_DATA; + typedef struct _SECTION_PARSING_DATA { union { COMPRESSED_SECTION_PARSING_DATA compressed; GUIDED_SECTION_PARSING_DATA guidDefined; FREEFORM_GUIDED_SECTION_PARSING_DATA freeformSubtypeGuid; + TE_IMAGE_SECTION_PARSING_DATA teImage; }; } SECTION_PARSING_DATA; @@ -75,7 +82,7 @@ typedef struct _PARSING_DATA { UINT8 emptyByte; UINT8 ffsVersion; UINT32 offset; - UINT64 address; + UINT32 address; union { //CAPSULE_PARSING_DATA capsule; //IMAGE_PARSING_DATA image;