UT NE A12

- added detection of VTF inside volume's non-UEFI data
- corrected ImageSize information for EFI capsule
- *.scap is added to the list of known Image file extensions
- all FIT candidates in a tree item are checked for being referenced
from the last VTF now
This commit is contained in:
Nikolaj Schlej 2015-09-19 10:08:26 +02:00
parent 788397f60c
commit 6d8e5976f7
4 changed files with 84 additions and 42 deletions

View file

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("0.30.0_alpha11"))
version(tr("0.30.0_alpha12"))
{
clipboard = QApplication::clipboard();
@ -619,13 +619,13 @@ void UEFITool::saveImageFile()
void UEFITool::openImageFile()
{
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)");
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)");
openImageFile(path);
}
void UEFITool::openImageFileInNewWindow()
{
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)");
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, "BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)");
if (path.trimmed().isEmpty())
return;
QProcess::startDetached(currentProgramPath, QStringList(path));
@ -695,7 +695,7 @@ void UEFITool::copyMessage()
clipboard->setText(ui->parserMessagesListWidget->currentItem()->text());
else if (ui->messagesTabWidget->currentIndex() == 1) // Search tab
clipboard->setText(ui->finderMessagesListWidget->currentItem()->text());
else if (ui->messagesTabWidget->currentIndex() == 2) // Search tab
else if (ui->messagesTabWidget->currentIndex() == 2) // FIT tab
clipboard->setText(ui->fitMessagesListWidget->currentItem()->text());
}
@ -898,7 +898,6 @@ void UEFITool::showFitTable()
ui->fitTableWidget->clear();
ui->fitTableWidget->setRowCount(fitTable.length());
ui->fitTableWidget->setColumnCount(5);
//ui->fitTableWidget->verticalHeader()->setVisible(false);
ui->fitTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Address") << tr("Size") << tr("Version") << tr("Type") << tr("Checksum"));
ui->fitTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->fitTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);

View file

@ -85,7 +85,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
.arg(guidToQString(capsuleHeader->CapsuleGuid))
.hexarg(buffer.size()).arg(buffer.size())
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
.hexarg(capsuleHeader->CapsuleImageSize).arg(capsuleHeader->CapsuleImageSize)
.hexarg(capsuleHeader->CapsuleImageSize - capsuleHeader->HeaderSize).arg(capsuleHeader->CapsuleImageSize - capsuleHeader->HeaderSize)
.hexarg2(capsuleHeader->Flags, 8);
// Construct parsing data
@ -1178,6 +1178,66 @@ STATUS FfsParser::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UI
return ERR_SUCCESS;
}
STATUS FfsParser::parseVolumeNonUefiData(const QByteArray & data, const UINT32 parentOffset, const QModelIndex & index)
{
// Sanity check
if (!index.isValid())
return ERR_INVALID_PARAMETER;
// Get parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Modify it
pdata.fixed = TRUE; // Non-UEFI data is fixed
pdata.offset += parentOffset;
// Search for VTF GUID backwards in received data
QByteArray padding = data;
QByteArray vtf;
INT32 vtfIndex = data.lastIndexOf(EFI_FFS_VOLUME_TOP_FILE_GUID);
if (vtfIndex > 0) { // VTF found inside non-UEFI data
padding = data.left(vtfIndex);
vtf = data.mid(vtfIndex);
}
// Add non-UEFI data first
// Get info
QString info = tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size());
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add padding tree item
QModelIndex paddingIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, parsingDataToQByteArray(pdata), index);
msg(tr("parseVolumeNonUefiData: non-UEFI data found in volume's free space"), paddingIndex);
if (vtfIndex > 0) {
// Get VTF file header
QByteArray header = vtf.left(sizeof(EFI_FFS_FILE_HEADER));
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
if (pdata.ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
header = vtf.left(sizeof(EFI_FFS_FILE_HEADER2));
}
//Parse VTF file header
QModelIndex fileIndex;
STATUS result = parseFileHeader(vtf, parentOffset + vtfIndex, index, fileIndex);
if (result) {
msg(tr("parseVolumeNonUefiData: VTF file header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
// Add the rest as non-UEFI data too
pdata.offset += vtfIndex;
// Get info
QString info = tr("Full size: %1h (%2)").hexarg(vtf.size()).arg(vtf.size());
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add padding tree item
QModelIndex paddingIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), vtf, parsingDataToQByteArray(pdata), index);
msg(tr("parseVolumeNonUefiData: non-UEFI data found in volume's free space"), paddingIndex);
}
}
return ERR_SUCCESS;
}
STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
{
// Sanity check
@ -1227,7 +1287,7 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
pdata.fixed = FALSE; // Free space is not fixed
pdata.offset = offset + volumeHeaderSize + fileOffset;
// Add all bytes before as free space...
// Add all bytes before as free space
if (i > 0) {
QByteArray free = freeSpace.left(i);
@ -1238,18 +1298,9 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
// Add free space item
model->addItem(Types::FreeSpace, 0, tr("Volume free space"), "", info, QByteArray(), free, parsingDataToQByteArray(pdata), index);
}
// ... and all bytes after as a padding
pdata.fixed = TRUE; // Non-UEFI data is fixed
pdata.offset += i;
QByteArray padding = freeSpace.mid(i);
// Get info
QString info = tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size());
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add padding tree item
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, parsingDataToQByteArray(pdata), index);
msg(tr("parseVolumeBody: non-UEFI data found in volume's free space"), dataIndex);
// Parse non-UEFI data
parseVolumeNonUefiData(freeSpace.mid(i), volumeHeaderSize + fileOffset + i, index);
}
else {
// Construct parsing data
@ -1266,21 +1317,8 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
break; // Exit from parsing loop
}
else { //File space
// Add padding to the end of the volume
pdata.fixed = TRUE; // Non-UEFI data is fixed
pdata.offset = offset + volumeHeaderSize + fileOffset;
QByteArray padding = volumeBody.mid(fileOffset);
// Get info
QString info = tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size());
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add padding tree item
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, parsingDataToQByteArray(pdata), index);
// Show message
msg(tr("parseVolumeBody: non-UEFI data found inside volume's file space"), dataIndex);
// Parse non-UEFI data
parseVolumeNonUefiData(volumeBody.mid(fileOffset), volumeHeaderSize + fileOffset, index);
break; // Exit from parsing loop
}
}
@ -1614,7 +1652,7 @@ STATUS FfsParser::parsePadFileBody(const QModelIndex & index)
return ERR_SUCCESS;
}
STATUS FfsParser::parseSections(QByteArray sections, const QModelIndex & index)
STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex & index)
{
// Sanity check
if (!index.isValid())

View file

@ -70,7 +70,8 @@ private:
STATUS parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePadFileBody(const QModelIndex & index);
STATUS parseSections(QByteArray sections, const QModelIndex & index);
STATUS parseVolumeNonUefiData(const QByteArray & data, const UINT32 parentOffset, const QModelIndex & index);
STATUS parseSections(const QByteArray & sections, const QModelIndex & index);
STATUS parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);

View file

@ -69,14 +69,17 @@ STATUS FitParser::parse(const QModelIndex & index, const QModelIndex & lastVtfIn
// Special case of FIT header
const FIT_ENTRY* fitHeader = (const FIT_ENTRY*)(model->body(fitIndex).constData() + fitOffset);
// Check FIT checksum, if present
UINT32 fitSize = (fitHeader->Size & 0xFFFFFF) << 4;
if (fitHeader->Type & 0x80) {
// Calculate FIT entry checksum
UINT8 calculated = calculateChecksum8((const UINT8*)fitHeader, fitSize);
if (calculated) {
msg(tr("Invalid FIT table checksum"), fitIndex);
QByteArray tempFIT = model->body(fitIndex).mid(fitOffset, fitSize);
FIT_ENTRY* tempFitHeader = (FIT_ENTRY*)tempFIT.data();
tempFitHeader->Checksum = 0;
UINT8 calculated = calculateChecksum8((const UINT8*)tempFitHeader, fitSize);
if (calculated != fitHeader->Checksum) {
msg(tr("Invalid FIT table checksum %1h, should be %2h").hexarg2(fitHeader->Checksum, 2).hexarg2(calculated, 2), fitIndex);
}
}
@ -170,9 +173,10 @@ STATUS FitParser::findFitRecursive(const QModelIndex & index, QModelIndex & foun
// Get parsing data for the current item
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Check for FIT signature in item's body
INT32 offset = model->body(index).indexOf(FIT_SIGNATURE);
if (offset >= 0) {
// Check for all FIT signatures in item's body
for (INT32 offset = model->body(index).indexOf(FIT_SIGNATURE);
offset >= 0;
offset = model->body(index).indexOf(FIT_SIGNATURE, offset + 1)) {
// FIT candidate found, calculate it's physical address
UINT32 fitAddress = pdata.address + model->header(index).size() + (UINT32)offset;