From 6d8e5976f77df61b93a103d746da4634e3258ef9 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sat, 19 Sep 2015 10:08:26 +0200 Subject: [PATCH] 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 --- UEFITool/uefitool.cpp | 9 ++-- common/ffsparser.cpp | 96 ++++++++++++++++++++++++++++++------------- common/ffsparser.h | 3 +- common/fitparser.cpp | 18 ++++---- 4 files changed, 84 insertions(+), 42 deletions(-) diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index 68683b9..13fa0e0 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_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); diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 9218b4a..2ccc59f 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -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()) diff --git a/common/ffsparser.h b/common/ffsparser.h index 7ef0341..8a28ee3 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -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); diff --git a/common/fitparser.cpp b/common/fitparser.cpp index 37c8f26..1723821 100644 --- a/common/fitparser.cpp +++ b/common/fitparser.cpp @@ -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;