NE_aplha5

Added FIT detection, parsing and UI, finally
This commit is contained in:
Nikolaj Schlej 2015-07-07 15:57:41 +02:00
parent f3d731c599
commit 407e558b60
16 changed files with 472 additions and 100 deletions

View File

@ -44,7 +44,7 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
return ERR_INVALID_PARAMETER;
// Get data from parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Construct a name for extracted data
QString itemName = model->name(index);

View File

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("0.30.0_alpha4"))
version(tr("0.30.0_alpha5"))
{
clipboard = QApplication::clipboard();
@ -26,6 +26,7 @@ version(tr("0.30.0_alpha4"))
searchDialog = new SearchDialog(this);
model = NULL;
ffsParser = NULL;
fitParser = NULL;
ffsFinder = NULL;
ffsOps = NULL;
@ -69,6 +70,7 @@ version(tr("0.30.0_alpha4"))
ui->infoEdit->setFont(font);
ui->parserMessagesListWidget->setFont(font);
ui->finderMessagesListWidget->setFont(font);
ui->fitTableWidget->setFont(font);
ui->structureTreeView->setFont(font);
searchDialog->ui->guidEdit->setFont(font);
searchDialog->ui->hexEdit->setFont(font);
@ -84,6 +86,7 @@ UEFITool::~UEFITool()
{
delete ffsOps;
delete ffsFinder;
delete fitParser;
delete ffsParser;
delete model;
delete searchDialog;
@ -95,6 +98,7 @@ void UEFITool::init()
// Clear components
ui->parserMessagesListWidget->clear();
ui->finderMessagesListWidget->clear();
ui->fitTableWidget->clear();
ui->infoEdit->clear();
// Set window title
@ -120,6 +124,10 @@ void UEFITool::init()
if (ffsParser)
delete ffsParser;
ffsParser = new FfsParser(model);
// ... and fitParser
if (fitParser)
delete fitParser;
fitParser = new FitParser(model);
// Connect
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
@ -602,6 +610,12 @@ void UEFITool::openImageFile(QString path)
else
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
// Parse FIT
//!TODO: expand and chek errors
result = fitParser->parse(model->index(0, 0), ffsParser->getLastVtf());
if (!result)
showFitTable();
// Enable search ...
if (ffsFinder)
delete ffsFinder;
@ -789,3 +803,78 @@ void UEFITool::writeSettings()
settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2));
settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3));
}
void UEFITool::showFitTable()
{
QVector<QPair<FIT_ENTRY, QString> > fitEntries = fitParser->getFitEntries();
if (fitEntries.isEmpty())
return;
// Set up the FIT table
ui->fitTableWidget->clear();
ui->fitTableWidget->setRowCount(fitEntries.length());
ui->fitTableWidget->setColumnCount(6);
//ui->fitTableWidget->verticalHeader()->setVisible(false);
ui->fitTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Address") << tr("Size") << tr("Version") << tr("Type") << tr("Checksum") << tr("Remark"));
ui->fitTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->fitTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->fitTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
ui->fitTableWidget->horizontalHeader()->setStretchLastSection(true);
// Add all data to the table widget
for (INT32 i = 0; i < fitEntries.length(); i++) {
FIT_ENTRY* entry = &(fitEntries[i].first);
if (i)
ui->fitTableWidget->setItem(i, 0, new QTableWidgetItem(tr("%1h").hexarg2(entry->Address, 16)));
else
ui->fitTableWidget->setItem(i, 0, new QTableWidgetItem(tr("_FIT_ ")));
ui->fitTableWidget->setItem(i, 1, new QTableWidgetItem(tr("%1h (%2)").hexarg2(entry->Size * 16, 8).arg(entry->Size * 16)));
ui->fitTableWidget->setItem(i, 2, new QTableWidgetItem(tr("%1h").hexarg2(entry->Version, 4)));
QString typeString;
switch (entry->Type & 0x7F) {
case FIT_TYPE_HEADER:
typeString.append(tr("Header"));
break;
case FIT_TYPE_MICROCODE:
typeString.append(tr("Microcode"));
break;
case FIT_TYPE_BIOS_AC_MODULE:
typeString.append(tr("BIOS ACM"));
break;
case FIT_TYPE_BIOS_INIT_MODULE:
typeString.append(tr("BIOS Init"));
break;
case FIT_TYPE_TPM_POLICY:
typeString.append(tr("TPM Policy"));
break;
case FIT_TYPE_BIOS_POLICY_DATA:
typeString.append(tr("BIOS Policy Data"));
break;
case FIT_TYPE_TXT_CONF_POLICY:
typeString.append(tr("TXT Configuration Policy"));
break;
case FIT_TYPE_AC_KEY_MANIFEST:
typeString.append(tr("BootGuard Key Manifest"));
break;
case FIT_TYPE_AC_BOOT_POLICY:
typeString.append(tr("BootGuard Boot Policy"));
break;
case FIT_TYPE_EMPTY:
typeString.append(tr("Empty"));
break;
default:
typeString.append(tr("Unknown"));
}
ui->fitTableWidget->setItem(i, 3, new QTableWidgetItem(typeString));
ui->fitTableWidget->setItem(i, 4, new QTableWidgetItem(tr("%1h").hexarg2(entry->Checksum, 2)));
ui->fitTableWidget->setItem(i, 5, new QTableWidgetItem(fitEntries[i].second));
}
ui->fitTableWidget->resizeColumnsToContents();
ui->fitTableWidget->resizeRowsToContents();
ui->messagesTabWidget->setCurrentIndex(2);
}

View File

@ -37,6 +37,7 @@
#include "../common/utility.h"
#include "../common/ffs.h"
#include "../common/ffsparser.h"
#include "../common/fitparser.h"
#include "searchdialog.h"
#include "messagelistitem.h"
#include "ffsfinder.h"
@ -97,6 +98,7 @@ private:
Ui::UEFITool* ui;
TreeModel* model;
FfsParser* ffsParser;
FitParser* fitParser;
FfsFinder* ffsFinder;
FfsOperations* ffsOps;
SearchDialog* searchDialog;
@ -110,6 +112,7 @@ private:
void readSettings();
void showParserMessages();
void showFinderMessages();
void showFitTable();
};
#endif

View File

@ -18,6 +18,7 @@ SOURCES += uefitool_main.cpp \
../common/utility.cpp \
../common/ffsbuilder.cpp \
../common/ffsparser.cpp \
../common/fitparser.cpp \
../common/treeitem.cpp \
../common/treemodel.cpp \
../common/LZMA/LzmaCompress.c \
@ -47,6 +48,7 @@ HEADERS += uefitool.h \
../common/parsingdata.h \
../common/ffsbuilder.h \
../common/ffsparser.h \
../common/fitparser.h \
../common/treeitem.h \
../common/treemodel.h \
../common/LZMA/LzmaCompress.h \

View File

@ -202,6 +202,31 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="fitTab">
<attribute name="title">
<string>FIT</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QTableWidget" name="fitTableWidget"/>
</item>
</layout>
</widget>
</widget>
</widget>
</item>

View File

@ -30,36 +30,6 @@ const QVector<QByteArray> FFSv3Volumes =
const UINT8 ffsAlignmentTable[] =
{ 0, 4, 7, 9, 10, 12, 15, 16 };
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
UINT8 counter = 0;
while (bufferSize--)
counter += buffer[bufferSize];
return (UINT8)(0x100 - counter);
}
UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
UINT16 counter = 0;
UINT32 index = 0;
bufferSize /= sizeof(UINT16);
for (; index < bufferSize; index++) {
counter = (UINT16)(counter + buffer[index]);
}
return (UINT16)(0x10000 - counter);
}
VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
{
ffsSize[2] = (UINT8)((size) >> 16);

View File

@ -240,9 +240,6 @@ typedef struct _EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE {
//UINT8 Data[];
} EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE;
// Volume header 16bit checksum calculation routine
extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
//*****************************************************************************
// EFI FFS File
//*****************************************************************************
@ -341,8 +338,6 @@ const QByteArray EFI_FFS_PAD_FILE_GUID
// FFS size conversion routines
extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize);
extern UINT32 uint24ToUint32(const UINT8* ffsSize);
// FFS file 8bit checksum calculation routine
extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
//*****************************************************************************
// EFI FFS File Section

View File

@ -43,7 +43,7 @@ STATUS FfsBuilder::erase(const QModelIndex & index, QByteArray & erased)
if (!index.isValid())
return ERR_INVALID_PARAMETER;
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
erased.fill(pdata.emptyByte);
return ERR_SUCCESS;
}

View File

@ -85,7 +85,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
.hexarg2(capsuleHeader->Flags, 8);
// Construct parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(QModelIndex());
PARSING_DATA pdata = parsingDataFromQModelIndex(QModelIndex());
pdata.fixed = TRUE;
// Add tree item
@ -108,7 +108,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
.hexarg2(capsuleHeader->CapsuleHeader.Flags, 8);
// Construct parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(QModelIndex());
PARSING_DATA pdata = parsingDataFromQModelIndex(QModelIndex());
pdata.fixed = TRUE;
// Add tree item
@ -146,7 +146,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
.hexarg(capsuleHeaderSize).hexarg(flashImage.size()).arg(flashImage.size());
// Construct parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
pdata.fixed = TRUE;
pdata.offset = capsuleHeaderSize;
@ -160,7 +160,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
// 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);
msg(tr("parseImageFile: not a single Volume Top File is found, the image may be corrupted"), biosIndex);
}
else {
return performSecondPass(biosIndex);
@ -176,7 +176,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelInd
return EFI_INVALID_PARAMETER;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Store the beginning of descriptor as descriptor base address
const UINT8* descriptor = (const UINT8*)intelImage.constData();
@ -412,7 +412,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelInd
// 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);
msg(tr("parseIntelImage: not a single Volume Top File is found, the image may be corrupted"), index);
}
else {
return performSecondPass(index);
@ -428,7 +428,7 @@ STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffs
return ERR_EMPTY_REGION;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get info
QString name = tr("GbE region");
@ -463,7 +463,7 @@ STATUS FfsParser::parseMeRegion(const QByteArray & me, const UINT32 parentOffset
return ERR_EMPTY_REGION;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get info
QString name = tr("ME region");
@ -528,7 +528,7 @@ STATUS FfsParser::parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffs
return ERR_EMPTY_REGION;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get info
QString name = tr("PDR region");
@ -558,7 +558,7 @@ STATUS FfsParser::parseBiosRegion(const QByteArray & bios, const UINT32 parentOf
return ERR_EMPTY_REGION;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get info
QString name = tr("BIOS region");
@ -592,7 +592,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
return ERR_INVALID_PARAMETER;
// Get parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
UINT32 offset = pdata.offset;
UINT32 headerSize = model->header(index).size();
@ -746,7 +746,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
return ERR_INVALID_PARAMETER;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Populate volume header
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData());
@ -831,14 +831,14 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
UINT8 emptyByte = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
// Check for Apple CRC32 in ZeroVector
bool hasZeroVectorCRC32 = false;
bool hasAppleCrc32 = false;
UINT32 volumeSize = volume.size();
UINT32 crc32FromZeroVector = *(UINT32*)(volume.constData() + 8);
if (crc32FromZeroVector != 0) {
UINT32 appleCrc32 = *(UINT32*)(volume.constData() + 8);
if (appleCrc32 != 0) {
// Calculate CRC32 of the volume body
UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
if (crc == crc32FromZeroVector) {
hasZeroVectorCRC32 = true;
if (crc == appleCrc32) {
hasAppleCrc32 = true;
}
}
@ -865,11 +865,6 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
.hexarg2(volumeHeader->Attributes, 8)
.arg(emptyByte ? "1" : "0");
// Apple CRC32 volume
if (hasZeroVectorCRC32) {
info += tr("\nCRC32 in ZeroVector: valid");
}
// Extended header present
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset);
@ -887,14 +882,14 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
pdata.volume.extendedHeaderGuid = extendedHeaderGuid;
pdata.volume.alignment = alignment;
pdata.volume.revision = volumeHeader->Revision;
pdata.volume.hasZeroVectorCRC32 = hasZeroVectorCRC32;
pdata.volume.hasAppleCrc32 = hasAppleCrc32;
pdata.volume.isWeakAligned = (volumeHeader->Revision > 1 && (volumeHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT));
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add text
QString text;
if (hasZeroVectorCRC32)
text += tr("ZeroVectorCRC32 ");
if (hasAppleCrc32)
text += tr("AppleCRC32 ");
// Add tree item
UINT8 subtype = Subtypes::UnknownVolume;
@ -967,7 +962,7 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
UINT32 volumeHeaderSize = model->header(index).size();
// Get parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
UINT32 offset = pdata.offset;
if (pdata.ffsVersion != 2 && pdata.ffsVersion != 3) // Don't parse unknown volumes
@ -1146,7 +1141,7 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
return ERR_INVALID_PARAMETER;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get file header
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
@ -1328,7 +1323,7 @@ STATUS FfsParser::parsePadFileBody(const QModelIndex & index)
return ERR_INVALID_PARAMETER;
// Get data from parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Check if all bytes of the file are empty
QByteArray body = model->body(index);
@ -1395,7 +1390,7 @@ STATUS FfsParser::parseSections(QByteArray sections, const QModelIndex & index)
return ERR_INVALID_PARAMETER;
// Get data from parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Search for and parse all sections
UINT32 bodySize = sections.size();
@ -1491,7 +1486,7 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa
STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Get data from parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Obtain header fields
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@ -1523,7 +1518,7 @@ STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UIN
STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Get data from parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Obtain header fields
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@ -1566,7 +1561,7 @@ STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const
STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Get data from parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Obtain header fields
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@ -1610,7 +1605,7 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Get data from parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Obtain header fields
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@ -1697,7 +1692,7 @@ STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, c
STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Get data from parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Obtain header fields
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@ -1735,7 +1730,7 @@ STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UI
STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Get data from parent's parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(parent);
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Obtain header fields
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
@ -1812,7 +1807,7 @@ STATUS FfsParser::parseCompressedSectionBody(const QModelIndex & index)
return ERR_INVALID_PARAMETER;
// Get data from parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
UINT8 algorithm = pdata.section.compressed.compressionType;
// Decompress section
@ -1852,7 +1847,7 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
return ERR_INVALID_PARAMETER;
// Get data from parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
UINT32 attributes = pdata.section.guidDefined.attributes;
EFI_GUID guid = pdata.section.guidDefined.guid;
@ -2243,7 +2238,7 @@ STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index)
}
// Get data from parsing data
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
pdata.section.teImage.imageBase = teHeader->ImageBase;
pdata.section.teImage.adjustedImageBase = teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
@ -2264,22 +2259,19 @@ STATUS FfsParser::performSecondPass(const QModelIndex & index)
return ERR_INVALID_PARAMETER;
// Get parsing data for the last VTF
PARSING_DATA pdata = parsingDataFromQByteArray(lastVtf);
PARSING_DATA pdata = parsingDataFromQModelIndex(lastVtf);
if (!pdata.isOnFlash) {
msg(tr("addPhysicalAddressInfo: the last VTF appears inside compressed item, the image may be damaged"), lastVtf);
msg(tr("performSecondPass: the last VTF appears inside compressed item, the image may be damaged"), lastVtf);
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;
const UINT32 diff = 0xFFFFFFFFUL - pdata.offset - vtfSize + 1;
// Apply address information to index and all it's child items
addMemoryAddressesRecursive(index, diff);
// Find and parse FIT
parseFit();
return ERR_SUCCESS;
}
@ -2290,12 +2282,12 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U
return ERR_SUCCESS;
// Get parsing data for the current item
PARSING_DATA pdata = parsingDataFromQByteArray(index);
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Set address value for non-compressed data
if (pdata.isOnFlash) {
// Check address sanity
if ((const UINT64)diff + pdata.offset <= 0xFFFFFFFF) {
if ((const UINT64)diff + pdata.offset <= 0xFFFFFFFFUL) {
// Update info
pdata.address = diff + pdata.offset;
UINT32 headerSize = model->header(index).size();
@ -2335,13 +2327,69 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U
return ERR_SUCCESS;
}
STATUS FfsParser::parseFit()
/*STATUS FfsParser::parseFit(const QModelIndex & index)
{
// Check sanity
if (!lastVtf.isValid)
if (!lastVtf.isValid())
return EFI_INVALID_PARAMETER;
// Search for FIT
QModelIndex fitIndex;
STATUS result = findFitRecursive(index, fitIndex);
if (result)
return result;
// FIT not found
if (!fitIndex.isValid())
return ERR_SUCCESS;
// Get parsing data for the current item
PARSING_DATA pdata = parsingDataFromQModelIndex(fitIndex);
// Explicitly set the item as fixed
pdata.fixed = TRUE;
// Set modified parsing data
model->setParsingData(fitIndex, parsingDataToQByteArray(pdata));
return ERR_SUCCESS;
}
STATUS FfsParser::findFitRecursive(const QModelIndex & index, QModelIndex & found)
{
// Sanity check
if (!index.isValid())
return EFI_SUCCESS;
// Process child items
for (int i = 0; i < model->rowCount(index); i++) {
findFitRecursive(index.child(i, 0), found);
if (found.isValid())
return EFI_SUCCESS;
}
// Get parsing data for the current item
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Check item's address to be in required range
INT32 offset = model->body(index).indexOf(FIT_SIGNATURE);
// Check for FIT signature in item's body
if (offset >= 0) {
// FIT candidate found, calculate it's offset and physical address
UINT32 fitOffset = pdata.offset + model->header(index).size() + (UINT32)offset;
UINT32 fitAddress = pdata.address + model->header(index).size() + (UINT32)offset;
// Check FIT address to be in the last VTF
QByteArray lastVtfBody = model->body(lastVtf);
if (*(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - FIT_POINTER_OFFSET) == fitAddress) {
msg(tr("findFitRecursive: FIT table found at offset %1h, physical address %2h")
.hexarg2(fitOffset, 8)
.hexarg2(fitAddress, 8),
index);
found = index;
return ERR_SUCCESS;
}
}
return ERR_SUCCESS;
}*/

View File

@ -53,6 +53,9 @@ public:
STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseSectionBody(const QModelIndex & index);
// Retuns index of the last VTF after parsing is done
const QModelIndex getLastVtf() {return lastVtf;};
private:
TreeModel *model;
QVector<QPair<QString, QModelIndex> > messagesVector;
@ -92,7 +95,8 @@ private:
STATUS performSecondPass(const QModelIndex & index);
STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff);
STATUS parseFit();
/*STATUS parseFit(const QModelIndex & index);
STATUS findFitRecursive(const QModelIndex & index, QModelIndex & found);*/
// Internal operations
BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);

View File

@ -20,10 +20,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#pragma pack(push,1)
// Memory address of a pointer to FIT, 40h back from the end of flash chip
#define FIT_POINTER_ADDRESS 0xFFFFFFC0
// FIT can reside in the last 1 MB of the flash chip
#define FIT_TABLE_LOWEST_ADDRESS 0xFF000000
#define FIT_POINTER_OFFSET 0x40
// Entry types
#define FIT_TYPE_HEADER 0x00
@ -35,7 +32,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define FIT_TYPE_TXT_CONF_POLICY 0x0A
#define FIT_TYPE_AC_KEY_MANIFEST 0x0B
#define FIT_TYPE_AC_BOOT_POLICY 0x0C
#define FIT_TYPE_EMPTY 0xFF
#define FIT_TYPE_EMPTY 0x7F
#define FIT_HEADER_VERSION 0x0100
#define FIT_MICROCODE_VERSION 0x0100
@ -45,10 +42,9 @@ const QByteArray FIT_SIGNATURE
typedef struct _FIT_ENTRY {
UINT64 Address;
UINT64 ReservedSize;
UINT32 Size;
UINT16 Version;
UINT8 ChecksumValid : 1;
UINT8 Type : 7;
UINT8 Type;
UINT8 Checksum;
} FIT_ENTRY;

152
common/fitparser.cpp Normal file
View File

@ -0,0 +1,152 @@
/* fitparser.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "fitparser.h"
#include "types.h"
#include "treemodel.h"
FitParser::FitParser(TreeModel* treeModel, QObject *parent)
: QObject(parent), model(treeModel)
{
}
FitParser::~FitParser()
{
}
STATUS FitParser::parse(const QModelIndex & index, const QModelIndex & lastVtfIndex)
{
// Check sanity
if (!index.isValid() || !lastVtfIndex.isValid())
return EFI_INVALID_PARAMETER;
// Store lastVtfIndex
lastVtf = lastVtfIndex;
// Search for FIT
QModelIndex fitIndex;
UINT32 fitOffset;
STATUS result = findFitRecursive(index, fitIndex, fitOffset);
if (result)
return result;
// FIT not found
if (!fitIndex.isValid())
return ERR_SUCCESS;
// Get parsing data for the current item
PARSING_DATA pdata = parsingDataFromQModelIndex(fitIndex);
// Explicitly set the item as fixed
pdata.fixed = TRUE;
// Set modified parsing data
model->setParsingData(fitIndex, parsingDataToQByteArray(pdata));
// Add all FIT entries into QVector
const FIT_ENTRY* fitHeader = (const FIT_ENTRY*)(model->body(fitIndex).constData() + fitOffset);
// Special case of FIT header
QString remark;
// Check FIT checksum, if present
if (fitHeader->Type & 0x80) {
// Calculate FIT entry checksum
UINT32 fitSize = (fitHeader->Size & 0xFFFFFF) << 4;
UINT8 calculated = calculateChecksum8((const UINT8*)fitHeader, fitSize);
if (calculated) {
remark.append(tr("Invalid FIT table checksum, ").hexarg2(calculated, 2));
}
}
// Check fit header version and type
if (fitHeader->Version != FIT_HEADER_VERSION) {
remark.append(tr("Invalid FIT header version, "));
}
if ((fitHeader->Type & 0x7F) != FIT_TYPE_HEADER) {
remark.append(tr("Invalid FIT header type, "));
}
// Remove the last ", " from remark string, if needed
if (!remark.isEmpty())
remark = remark.left(remark.length() - 2);
// Add FIT header to fitEntries vector
fitEntries.append(QPair<FIT_ENTRY, QString>(*fitHeader, remark));
// Process all other entries
for (UINT32 i = 1; i < fitHeader->Size; i++) {
remark.clear();
const FIT_ENTRY* currentEntry = fitHeader + i;
// Check entry type
switch (currentEntry->Type & 0x7F) {
case FIT_TYPE_HEADER:
remark.append(tr("Second FIT header found, the table is damaged"));
break;
case FIT_TYPE_EMPTY:
case FIT_TYPE_MICROCODE:
break;
case FIT_TYPE_BIOS_AC_MODULE:
case FIT_TYPE_BIOS_INIT_MODULE:
case FIT_TYPE_TPM_POLICY:
case FIT_TYPE_BIOS_POLICY_DATA:
case FIT_TYPE_TXT_CONF_POLICY:
case FIT_TYPE_AC_KEY_MANIFEST:
case FIT_TYPE_AC_BOOT_POLICY:
default:
remark.append(tr("Modified image may not work"));
break;
}
fitEntries.append(QPair<FIT_ENTRY, QString>(*currentEntry, remark));
}
return ERR_SUCCESS;
}
STATUS FitParser::findFitRecursive(const QModelIndex & index, QModelIndex & found, UINT32 & fitOffset)
{
// Sanity check
if (!index.isValid())
return EFI_SUCCESS;
// Process child items
for (int i = 0; i < model->rowCount(index); i++) {
findFitRecursive(index.child(i, 0), found, fitOffset);
if (found.isValid())
return EFI_SUCCESS;
}
// Get parsing data for the current item
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Check item's address to be in required range
INT32 offset = model->body(index).indexOf(FIT_SIGNATURE);
// Check for FIT signature in item's body
if (offset >= 0) {
// FIT candidate found, calculate it's physical address
UINT32 fitAddress = pdata.address + model->header(index).size() + (UINT32)offset;
// Check FIT address to be in the last VTF
QByteArray lastVtfBody = model->body(lastVtf);
if (*(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - FIT_POINTER_OFFSET) == fitAddress) {
found = index;
fitOffset = offset;
return ERR_SUCCESS;
}
}
return ERR_SUCCESS;
}

50
common/fitparser.h Normal file
View File

@ -0,0 +1,50 @@
/* fitparser.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __FITPARSER_H__
#define __FITPARSER_H__
#include <QObject>
#include <QModelIndex>
#include <QByteArray>
#include <QStringList>
#include <QVector>
#include "basetypes.h"
#include "treemodel.h"
#include "utility.h"
#include "parsingdata.h"
#include "fit.h"
class TreeModel;
class FitParser : public QObject
{
Q_OBJECT
public:
// Default constructor and destructor
FitParser(TreeModel* treeModel, QObject *parent = 0);
~FitParser();
STATUS parse(const QModelIndex & index, const QModelIndex & lastVtf);
QVector<QPair<FIT_ENTRY, QString> > getFitEntries() const { return fitEntries; }
private:
TreeModel *model;
QModelIndex lastVtf;
QVector<QPair<FIT_ENTRY, QString> > fitEntries;
STATUS findFitRecursive(const QModelIndex & index, QModelIndex & found, UINT32 & fitOffset);
};
#endif

View File

@ -34,7 +34,8 @@ typedef struct _VOLUME_PARSING_DATA {
UINT32 alignment;
UINT8 revision;
BOOLEAN hasExtendedHeader;
BOOLEAN hasZeroVectorCRC32;
BOOLEAN hasAppleCrc32;
BOOLEAN hasAppleFSO;
BOOLEAN isWeakAligned;
} VOLUME_PARSING_DATA;

View File

@ -20,7 +20,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "LZMA/LzmaDecompress.h"
// Returns either new parsing data instance or obtains it from index
PARSING_DATA parsingDataFromQByteArray(const QModelIndex & index)
PARSING_DATA parsingDataFromQModelIndex(const QModelIndex & index)
{
if (index.isValid()) {
TreeModel* model = (TreeModel*)index.model();
@ -257,3 +257,34 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
}
}
// 8bit checksum calculation routine
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
UINT8 counter = 0;
while (bufferSize--)
counter += buffer[bufferSize];
return (UINT8)(0x100 - counter);
}
// 16bit checksum calculation routine
UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
UINT16 counter = 0;
UINT32 index = 0;
bufferSize /= sizeof(UINT16);
for (; index < bufferSize; index++) {
counter = (UINT16)(counter + buffer[index]);
}
return (UINT16)(0x10000 - counter);
}

View File

@ -20,7 +20,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "parsingdata.h"
// Returns either new parsing data instance or obtains it from index
PARSING_DATA parsingDataFromQByteArray(const QModelIndex & index);
PARSING_DATA parsingDataFromQModelIndex(const QModelIndex & index);
// Converts parsing data to byte array
QByteArray parsingDataToQByteArray(const PARSING_DATA & pdata);
@ -34,7 +34,13 @@ extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByte
// Compression routine
//STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);
// CRC32
// CRC32 calculation routine
extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);
// 8bit checksum calculation routine
extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
// 16bit checksum calculation routine
extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
#endif