NE_alpha4

- second pass of parsing to add physical memory addresses to all
uncompressed items in the tree
- TE image revisions can be detected now
- more builder routines, but still not ready for enabling
- PE and TE header info is back
This commit is contained in:
Nikolaj Schlej 2015-06-19 20:26:45 +02:00
parent 129819314d
commit 87bd80b72c
6 changed files with 411 additions and 158 deletions

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.30.0_alpha3")) version(tr("0.30.0_alpha4"))
{ {
clipboard = QApplication::clipboard(); clipboard = QApplication::clipboard();

View File

@ -37,9 +37,15 @@ void FfsBuilder::clearMessages()
messagesVector.clear(); 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) STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule)
@ -63,20 +69,24 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule)
// Clear the supplied QByteArray // Clear the supplied QByteArray
capsule.clear(); capsule.clear();
// Reconstruct children // Build children
for (int i = 0; i < model->rowCount(index); i++) { for (int i = 0; i < model->rowCount(index); i++) {
QModelIndex currentChild = index.child(i, 0); QModelIndex currentChild = index.child(i, 0);
QByteArray currentData; QByteArray currentData;
// Check child type // Check child type
if (model->type(currentChild) == Types::Image) { if (model->type(currentChild) == Types::Image) {
result = buildImage(currentChild, currentData); if (model->subtype(currentChild) == Subtypes::IntelImage)
if (!result) { result = buildIntelImage(currentChild, currentData);
capsule.append(currentData); else
} result = buildRawArea(currentChild, currentData);
else {
// 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); 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)); capsule.append(model->header(currentChild)).append(model->body(currentChild));
} }
else
capsule.append(currentData);
} }
else { else {
msg(tr("buildCapsule: unexpected child item of type \"%1\" can't be processed, original item data used").arg(itemTypeToQString(model->type(currentChild))), currentChild); 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 // 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)") msg(tr("buildCapsule: new capsule size %1h (%2) is bigger than the original %3h (%4)")
.hexarg(capsule.size()).arg(capsule.size()) .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize),index);
.hexarg(model->body(index).size()).arg(model->body(index).size()),
index);
return ERR_INVALID_PARAMETER; 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)") msg(tr("buildCapsule: new capsule size %1h (%2) is smaller than the original %3h (%4)")
.hexarg(capsule.size()).arg(capsule.size()) .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index);
.hexarg(model->body(index).size()).arg(model->body(index).size()),
index);
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
} }
} }
@ -107,16 +115,197 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule)
capsule = model->header(index).append(capsule); capsule = model->header(index).append(capsule);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
msg(tr("buildCapsule: unexpected action \"%1\"").arg(actionTypeToQString(model->action(index))), index); msg(tr("buildCapsule: unexpected action \"%1\"").arg(actionTypeToQString(model->action(index))), index);
return ERR_NOT_IMPLEMENTED; 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; 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 // Sanity check
if (!index.isValid()) if (!index.isValid())
@ -137,7 +326,7 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea)
// Clear the supplied QByteArray // Clear the supplied QByteArray
rawArea.clear(); rawArea.clear();
// Reconstruct children // Build children
for (int i = 0; i < model->rowCount(index); i++) { for (int i = 0; i < model->rowCount(index); i++) {
QModelIndex currentChild = index.child(i, 0); QModelIndex currentChild = index.child(i, 0);
QByteArray currentData; QByteArray currentData;
@ -162,27 +351,26 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea)
rawArea.append(currentData); rawArea.append(currentData);
} }
// Check size of reconstructed raw area, it must remain the same // Check size of new raw area, it must be same as original one
if (rawArea.size() > model->body(index).size()) { UINT32 newSize = rawArea.size();
msg(tr("buildRawArea: new raw area size %1h (%2) is bigger than the original %3h (%4)") UINT32 oldSize = model->body(index).size();
.hexarg(rawArea.size()).arg(rawArea.size()) if (newSize > oldSize) {
.hexarg(model->body(index).size()).arg(model->body(index).size()), msg(tr("buildRawArea: new area size %1h (%2) is bigger than the original %3h (%4)")
index); .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index);
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
} }
else if (rawArea.size() < model->body(index).size()) { else if (newSize < oldSize) {
msg(tr("buildRawArea: new raw area size %1h (%2) is smaller than the original %3h (%4)") msg(tr("buildRawArea: new area size %1h (%2) is smaller than the original %3h (%4)")
.hexarg(rawArea.size()).arg(rawArea.size()) .hexarg(newSize).arg(newSize).hexarg(oldSize).arg(oldSize), index);
.hexarg(model->body(index).size()).arg(model->body(index).size()),
index);
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
} }
} }
else else
rawArea = model->body(index); rawArea = model->body(index);
// Build successful, append header // Build successful, add header if needed
rawArea = model->header(index).append(rawArea); if (addHeader)
rawArea = model->header(index).append(rawArea);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -190,11 +378,6 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea)
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
} }
STATUS FfsBuilder::buildVolume(const QModelIndex & index, QByteArray & volume)
{
return ERR_NOT_IMPLEMENTED;
}
STATUS FfsBuilder::buildPadding(const QModelIndex & index, QByteArray & padding) STATUS FfsBuilder::buildPadding(const QModelIndex & index, QByteArray & padding)
{ {
// Sanity check // Sanity check
@ -209,7 +392,9 @@ STATUS FfsBuilder::buildPadding(const QModelIndex & index, QByteArray & padding)
// Erase // Erase
else if (model->action(index) == Actions::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; return ERR_SUCCESS;
} }
@ -231,7 +416,9 @@ STATUS FfsBuilder::buildNonUefiData(const QModelIndex & index, QByteArray & data
// Erase // Erase
else if (model->action(index) == Actions::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; return ERR_SUCCESS;
} }
@ -255,6 +442,11 @@ STATUS FfsBuilder::buildFreeSpace(const QModelIndex & index, QByteArray & freeSp
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
} }
STATUS FfsBuilder::buildVolume(const QModelIndex & index, QByteArray & volume)
{
return ERR_NOT_IMPLEMENTED;
}
STATUS FfsBuilder::buildPadFile(const QModelIndex & index, QByteArray & padFile) STATUS FfsBuilder::buildPadFile(const QModelIndex & index, QByteArray & padFile)
{ {
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
@ -270,3 +462,7 @@ STATUS FfsBuilder::buildSection(const QModelIndex & index, QByteArray & section)
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
} }
STATUS FfsBuilder::build(const QModelIndex & root, QByteArray & image)
{
return ERR_NOT_IMPLEMENTED;
}

View File

@ -21,6 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "../common/basetypes.h" #include "../common/basetypes.h"
#include "../common/treemodel.h" #include "../common/treemodel.h"
#include "../common/descriptor.h"
#include "../common/ffs.h" #include "../common/ffs.h"
#include "../common/utility.h" #include "../common/utility.h"
@ -44,17 +45,19 @@ private:
// UEFI standard structures // UEFI standard structures
STATUS buildCapsule(const QModelIndex & index, QByteArray & capsule); 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 buildRegion(const QModelIndex & index, QByteArray & region);
STATUS buildRawArea(const QModelIndex & index, QByteArray & rawArea); STATUS buildRawArea(const QModelIndex & index, QByteArray & rawArea, bool addHeader = true);
STATUS buildVolume(const QModelIndex & index, QByteArray & volume);
STATUS buildPadding(const QModelIndex & index, QByteArray & padding); STATUS buildPadding(const QModelIndex & index, QByteArray & padding);
STATUS buildVolume(const QModelIndex & index, QByteArray & volume);
STATUS buildNonUefiData(const QModelIndex & index, QByteArray & data); STATUS buildNonUefiData(const QModelIndex & index, QByteArray & data);
STATUS buildFreeSpace(const QModelIndex & index, QByteArray & freeSpace); STATUS buildFreeSpace(const QModelIndex & index, QByteArray & freeSpace);
STATUS buildPadFile(const QModelIndex & index, QByteArray & padFile); STATUS buildPadFile(const QModelIndex & index, QByteArray & padFile);
STATUS buildFile(const QModelIndex & index, QByteArray & file); STATUS buildFile(const QModelIndex & index, QByteArray & file);
STATUS buildSection(const QModelIndex & index, QByteArray & section); STATUS buildSection(const QModelIndex & index, QByteArray & section);
// Utility functions
STATUS erase(const QModelIndex & index, QByteArray & erased);
}; };
#endif #endif

View File

@ -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); QModelIndex biosIndex = model->addItem(Types::Image, Subtypes::UefiImage, name, QString(), info, QByteArray(), flashImage, parsingDataToQByteArray(pdata), index);
// Parse the image // 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) 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; 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; return ERR_SUCCESS;
} }
@ -595,6 +615,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
// Construct parsing data // Construct parsing data
pdata.fixed = TRUE; pdata.fixed = TRUE;
pdata.offset = offset + headerSize;
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset)); if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add tree item // Add tree item
@ -731,7 +752,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
// Calculate volume header size // Calculate volume header size
UINT32 headerSize; 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; bool hasExtendedHeader = false;
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
hasExtendedHeader = true; hasExtendedHeader = true;
@ -1216,6 +1237,17 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
.hexarg(body.size()).arg(body.size()) .hexarg(body.size()).arg(body.size())
.hexarg2(fileHeader->State, 2); .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 // Construct parsing data
pdata.fixed = fileHeader->Attributes & FFS_ATTRIB_FIXED; pdata.fixed = fileHeader->Attributes & FFS_ATTRIB_FIXED;
pdata.offset += parentOffset; 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)); if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add tree item // 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 // Show messages
if (msgUnalignedFile) if (msgUnalignedFile)
@ -1435,9 +1472,9 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa
case EFI_SECTION_DXE_DEPEX: case EFI_SECTION_DXE_DEPEX:
case EFI_SECTION_PEI_DEPEX: case EFI_SECTION_PEI_DEPEX:
case EFI_SECTION_SMM_DEPEX: case EFI_SECTION_SMM_DEPEX:
case EFI_SECTION_TE:
case EFI_SECTION_PE32: case EFI_SECTION_PE32:
case EFI_SECTION_PIC: case EFI_SECTION_PIC:
case EFI_SECTION_TE:
case EFI_SECTION_COMPATIBILITY16: case EFI_SECTION_COMPATIBILITY16:
case EFI_SECTION_USER_INTERFACE: case EFI_SECTION_USER_INTERFACE:
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
@ -1732,6 +1769,7 @@ STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const U
return ERR_SUCCESS; return ERR_SUCCESS;
} }
STATUS FfsParser::parseSectionBody(const QModelIndex & index) STATUS FfsParser::parseSectionBody(const QModelIndex & index)
{ {
// Sanity check // Sanity check
@ -1751,9 +1789,9 @@ STATUS FfsParser::parseSectionBody(const QModelIndex & index)
case EFI_SECTION_DXE_DEPEX: case EFI_SECTION_DXE_DEPEX:
case EFI_SECTION_PEI_DEPEX: case EFI_SECTION_PEI_DEPEX:
case EFI_SECTION_SMM_DEPEX: return parseDepexSectionBody(index); 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_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_USER_INTERFACE: return parseUiSectionBody(index);
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return parseRawArea(model->body(index), index); case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return parseRawArea(model->body(index), index);
case EFI_SECTION_RAW: return parseRawSectionBody(index); case EFI_SECTION_RAW: return parseRawSectionBody(index);
@ -2109,37 +2147,29 @@ STATUS FfsParser::parseRawSectionBody(const QModelIndex & index)
return parseRawArea(model->body(index), 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 STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index)
QString name = sectionTypeToQString(sectionHeader->Type) + tr(" section"); {
QString info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)") // Sanity check
.hexarg2(sectionHeader->Type, 2) if (!index.isValid())
.hexarg(section.size()).arg(section.size()) return ERR_INVALID_PARAMETER;
.hexarg(header.size()).arg(header.size())
.hexarg(body.size()).arg(body.size()); // Get section body
QByteArray body = model->body(index);
// Get PE info // Get PE info
bool msgInvalidDosSignature = false; QByteArray info;
bool msgInvalidPeSignature = false;
bool msgUnknownOptionalHeaderSignature = false;
const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData(); const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData();
if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) { if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
info += tr("\nDOS signature: %1h, invalid").hexarg2(dosHeader->e_magic, 4); info += tr("\nDOS signature: %1h, invalid").hexarg2(dosHeader->e_magic, 4);
msgInvalidDosSignature = true; msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS signature"), index);
} }
else { else {
const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew); const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew);
if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) { if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) {
info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8); info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8);
msgInvalidPeSignature = true; msg(tr("parsePeImageSectionBody: PE32 image with invalid PE signature"), index);
} }
else { else {
const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1); 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; EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader;
optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1); optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1);
if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { 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->Magic, 4)
.hexarg2(optionalHeader.H32->Subsystem, 4) .hexarg2(optionalHeader.H32->Subsystem, 4)
.hexarg(optionalHeader.H32->AddressOfEntryPoint) .hexarg(optionalHeader.H32->AddressOfEntryPoint)
.hexarg(optionalHeader.H32->BaseOfCode) .hexarg(optionalHeader.H32->BaseOfCode)
.hexarg(optionalHeader.H32->ImageBase) .hexarg(optionalHeader.H32->ImageBase);
.hexarg(optionalHeader.H32->ImageBase + optionalHeader.H32->AddressOfEntryPoint);
} }
else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { 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->Magic, 4)
.hexarg2(optionalHeader.H64->Subsystem, 4) .hexarg2(optionalHeader.H64->Subsystem, 4)
.hexarg(optionalHeader.H64->AddressOfEntryPoint) .hexarg(optionalHeader.H64->AddressOfEntryPoint)
.hexarg(optionalHeader.H64->BaseOfCode) .hexarg(optionalHeader.H64->BaseOfCode)
.hexarg(optionalHeader.H64->ImageBase) .hexarg(optionalHeader.H64->ImageBase);
.hexarg(optionalHeader.H64->ImageBase + optionalHeader.H64->AddressOfEntryPoint);
} }
else { else {
info += tr("\nOptional header signature: %1h, unknown").hexarg2(optionalHeader.H64->Magic, 4); 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 // Add PE info
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); 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; 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()); // Sanity check
UINT32 headerSize = sizeOfSectionHeader(sectionHeader); if (!index.isValid())
QByteArray header = section.left(headerSize); return ERR_INVALID_PARAMETER;
QByteArray body = section.mid(headerSize);
// Get standard info // Get section body
QString name = sectionTypeToQString(sectionHeader->Type) + tr(" section"); QByteArray body = model->body(index);
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 TE info // Get TE info
bool msgInvalidSignature = false; QByteArray info;
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData(); 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) { if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4); info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4);
msgInvalidSignature = true; msg(tr("parseTeImageSectionBody: TE image with invalid TE signature"), index);
} }
else { 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) .hexarg2(teHeader->Signature, 4)
.arg(machineTypeToQString(teHeader->Machine)) .arg(machineTypeToQString(teHeader->Machine))
.arg(teHeader->NumberOfSections) .arg(teHeader->NumberOfSections)
@ -2237,51 +2238,95 @@ STATUS FfsEngine::parseTeSectionHeader(const QByteArray & section, const UINT32
.hexarg(teHeader->BaseOfCode) .hexarg(teHeader->BaseOfCode)
.hexarg(teHeader->AddressOfEntryPoint) .hexarg(teHeader->AddressOfEntryPoint)
.hexarg(teHeader->ImageBase) .hexarg(teHeader->ImageBase)
.hexarg(teHeader->ImageBase + teHeader->AddressOfEntryPoint - teFixup); .hexarg(teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER));
}
// 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);
} }
// Special case of PEI Core // Get data from parsing data
QModelIndex core = model->findParentOfType(index, Types::File); PARSING_DATA pdata = parsingDataFromQByteArray(index);
if (core.isValid() && model->subtype(core) == EFI_FV_FILETYPE_PEI_CORE pdata.section.teImage.imageBase = teHeader->ImageBase;
&& oldPeiCoreEntryPoint == 0) { pdata.section.teImage.adjustedImageBase = teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
result = getEntryPoint(model->body(index), oldPeiCoreEntryPoint);
if (result) // Update parsing data
msg(tr("parseSection: can't get original PEI core entry point"), index); model->setParsingData(index, parsingDataToQByteArray(pdata));
}
// Add TE info
model->addInfo(index, info);
return ERR_SUCCESS; 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()); // Sanity check
QByteArray header = section.left(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION)); if (!index.isValid() || !lastVtf.isValid())
QByteArray body = section.mid(sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION)); return ERR_INVALID_PARAMETER;
// Get info // Get parsing data for the last VTF
QString name = sectionTypeToQString(sectionHeader->Type) + tr(" section"); PARSING_DATA pdata = parsingDataFromQByteArray(lastVtf);
QString info = tr("Type: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)") if (!pdata.isOnFlash) {
.hexarg2(sectionHeader->Type, 2) msg(tr("addPhysicalAddressInfo: the last VTF appears inside compressed item, the image may be damaged"), lastVtf);
.hexarg(section.size()).arg(section.size()) return ERR_SUCCESS;
.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;
} }
// 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; return ERR_SUCCESS;
} }
*/

View File

@ -53,13 +53,10 @@ public:
STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseSectionBody(const 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: private:
TreeModel *model; TreeModel *model;
QVector<QPair<QString, QModelIndex> > messagesVector; QVector<QPair<QString, QModelIndex> > messagesVector;
QModelIndex lastVtf;
STATUS parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & root); STATUS parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & root);
STATUS parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
@ -83,6 +80,8 @@ private:
STATUS parseDepexSectionBody(const QModelIndex & index); STATUS parseDepexSectionBody(const QModelIndex & index);
STATUS parseUiSectionBody(const QModelIndex & index); STATUS parseUiSectionBody(const QModelIndex & index);
STATUS parseRawSectionBody(const QModelIndex & index); STATUS parseRawSectionBody(const QModelIndex & index);
STATUS parsePeImageSectionBody(const QModelIndex & index);
STATUS parseTeImageSectionBody(const QModelIndex & index);
UINT8 getPaddingType(const QByteArray & padding); UINT8 getPaddingType(const QByteArray & padding);
STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed); STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed);
@ -91,6 +90,9 @@ private:
UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion); UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion);
UINT32 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, 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 // Internal operations
BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2); BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);

View File

@ -61,11 +61,18 @@ typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid; EFI_GUID guid;
} FREEFORM_GUIDED_SECTION_PARSING_DATA; } 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 { typedef struct _SECTION_PARSING_DATA {
union { union {
COMPRESSED_SECTION_PARSING_DATA compressed; COMPRESSED_SECTION_PARSING_DATA compressed;
GUIDED_SECTION_PARSING_DATA guidDefined; GUIDED_SECTION_PARSING_DATA guidDefined;
FREEFORM_GUIDED_SECTION_PARSING_DATA freeformSubtypeGuid; FREEFORM_GUIDED_SECTION_PARSING_DATA freeformSubtypeGuid;
TE_IMAGE_SECTION_PARSING_DATA teImage;
}; };
} SECTION_PARSING_DATA; } SECTION_PARSING_DATA;
@ -75,7 +82,7 @@ typedef struct _PARSING_DATA {
UINT8 emptyByte; UINT8 emptyByte;
UINT8 ffsVersion; UINT8 ffsVersion;
UINT32 offset; UINT32 offset;
UINT64 address; UINT32 address;
union { union {
//CAPSULE_PARSING_DATA capsule; //CAPSULE_PARSING_DATA capsule;
//IMAGE_PARSING_DATA image; //IMAGE_PARSING_DATA image;