UT NE A19

Thanks to lordkag for #41:
- improved parsing of Intel flash descriptor
- improved detection of Tiano/EFI 1.1 compression type
- added 2 UEFI capsule GUIDs used by Lenovo
- solved potential crash on very low memory available
- UEFIExtract and UEFIFind update to include the latest parser changes
This commit is contained in:
Nikolaj Schlej 2016-02-02 02:08:08 +01:00
parent 61a1e98403
commit 4cf6b4f37b
16 changed files with 463 additions and 394 deletions

View file

@ -71,7 +71,7 @@ STATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path,
QString info = tr("Type: %1\nSubtype: %2\n%3%4") QString info = tr("Type: %1\nSubtype: %2\n%3%4")
.arg(itemTypeToQString(model->type(index))) .arg(itemTypeToQString(model->type(index)))
.arg(itemSubtypeToQString(model->type(index), model->subtype(index))) .arg(itemSubtypeToQString(model->type(index), model->subtype(index)))
.arg(model->text(index).isEmpty() ? "" : tr("Text: %1\n").arg(model->text(index))) .arg(model->text(index).isEmpty() ? tr("") : tr("Text: %1\n").arg(model->text(index)))
.arg(model->info(index)); .arg(model->info(index));
file.setFileName(tr("%1/info.txt").arg(path)); file.setFileName(tr("%1/info.txt").arg(path));
if (!file.open(QFile::Text | QFile::WriteOnly)) if (!file.open(QFile::Text | QFile::WriteOnly))

View file

@ -1,6 +1,6 @@
/* uefiextract_main.cpp /* uefiextract_main.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -49,7 +49,7 @@ int main(int argc, char *argv[])
TreeModel model; TreeModel model;
FfsParser ffsParser(&model); FfsParser ffsParser(&model);
STATUS result = ffsParser.parseImageFile(buffer, model.index(0, 0)); STATUS result = ffsParser.parse(buffer);
if (result) if (result)
return result; return result;
@ -75,8 +75,8 @@ int main(int argc, char *argv[])
} }
} }
else { else {
std::cout << "UEFIExtract 0.10.6" << std::endl << std::endl std::cout << "UEFIExtract 0.10.7" << std::endl << std::endl
<< "Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl << "Usage: UEFIExtract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl
<< "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise" << std::endl; << "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise" << std::endl;
return 1; return 1;
} }

View file

@ -1,6 +1,6 @@
/* uefifind.cpp /* uefifind.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -46,7 +46,7 @@ STATUS UEFIFind::init(const QString & path)
QByteArray buffer = inputFile.readAll(); QByteArray buffer = inputFile.readAll();
inputFile.close(); inputFile.close();
result = ffsParser->parseImageFile(buffer, model->index(0,0)); result = ffsParser->parse(buffer);
if (result) if (result)
return result; return result;

View file

@ -1,6 +1,6 @@
/* uefifind_main.cpp /* uefifind_main.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -148,9 +148,9 @@ int main(int argc, char *argv[])
return ERR_SUCCESS; return ERR_SUCCESS;
} }
else { else {
std::cout << "UEFIFind 0.10.4.1" << std::endl << std::endl << std::cout << "UEFIFind 0.10.5" << std::endl << std::endl <<
"Usage: uefifind {header | body | all} {list | count} pattern imagefile" << std::endl << "Usage: UEFIFind {header | body | all} {list | count} pattern imagefile" << std::endl <<
" or uefifind file patternsfile imagefile" << std::endl; " or UEFIFind file patternsfile imagefile" << std::endl;
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
} }
} }

View file

@ -1,6 +1,6 @@
/* uefitool.cpp /* uefitool.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -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_alpha18")) version(tr("0.30.0_alpha19"))
{ {
clipboard = QApplication::clipboard(); clipboard = QApplication::clipboard();
@ -566,7 +566,7 @@ void UEFITool::extract(const UINT8 mode)
void UEFITool::about() void UEFITool::about()
{ {
QMessageBox::about(this, tr("About UEFITool"), tr( QMessageBox::about(this, tr("About UEFITool"), tr(
"Copyright (c) 2015, Nikolaj Schlej aka <b>CodeRush</b>.<br>" "Copyright (c) 2016, Nikolaj Schlej aka <b>CodeRush</b>.<br>"
"Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br><br>" "Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br><br>"
"The program is dedicated to <b>RevoGirl</b>. Rest in peace, young genius.<br><br>" "The program is dedicated to <b>RevoGirl</b>. Rest in peace, young genius.<br><br>"
"The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.<br>" "The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.<br>"
@ -657,7 +657,7 @@ void UEFITool::openImageFile(QString path)
init(); init();
setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName())); setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName()));
UINT8 result = ffsParser->parseImageFile(buffer, model->index(0,0)); UINT8 result = ffsParser->parse(buffer);
showParserMessages(); showParserMessages();
if (result) { if (result) {
QMessageBox::critical(this, tr("Image parsing failed"), errorCodeToQString(result), QMessageBox::Ok); QMessageBox::critical(this, tr("Image parsing failed"), errorCodeToQString(result), QMessageBox::Ok);

View file

@ -506,6 +506,7 @@ Returns:
UINT32 i; UINT32 i;
mText = malloc (WNDSIZ * 2 + MAXMATCH); mText = malloc (WNDSIZ * 2 + MAXMATCH);
if (!mText) return EFI_OUT_OF_RESOURCES;
for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) { for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) {
mText[i] = 0; mText[i] = 0;
} }

View file

@ -1,6 +1,6 @@
/* basetypes.h /* basetypes.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -93,12 +93,13 @@ typedef UINT8 STATUS;
#define EFI_ERROR(X) (X) #define EFI_ERROR(X) (X)
// Compression algorithms // Compression algorithms
#define COMPRESSION_ALGORITHM_UNKNOWN 0 #define COMPRESSION_ALGORITHM_UNKNOWN 0
#define COMPRESSION_ALGORITHM_NONE 1 #define COMPRESSION_ALGORITHM_NONE 1
#define COMPRESSION_ALGORITHM_EFI11 2 #define COMPRESSION_ALGORITHM_EFI11 2
#define COMPRESSION_ALGORITHM_TIANO 3 #define COMPRESSION_ALGORITHM_TIANO 3
#define COMPRESSION_ALGORITHM_LZMA 4 #define COMPRESSION_ALGORITHM_UNDECIDED 4
#define COMPRESSION_ALGORITHM_IMLZMA 5 #define COMPRESSION_ALGORITHM_LZMA 5
#define COMPRESSION_ALGORITHM_IMLZMA 6
// Item create modes // Item create modes
#define CREATE_MODE_APPEND 0 #define CREATE_MODE_APPEND 0

View file

@ -1,6 +1,6 @@
/* descriptor.h /* descriptor.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -21,7 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// Flash descriptor header // Flash descriptor header
typedef struct _FLASH_DESCRIPTOR_HEADER { typedef struct _FLASH_DESCRIPTOR_HEADER {
UINT8 FfVector[16]; // Must be 16 0xFFs UINT8 ReservedVector[16]; // Reserved for ARM ResetVector, 0xFFs on x86/x86-64 machines
UINT32 Signature; // 0x0FF0A55A UINT32 Signature; // 0x0FF0A55A
} FLASH_DESCRIPTOR_HEADER; } FLASH_DESCRIPTOR_HEADER;
@ -98,7 +98,7 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION {
UINT8 InvalidInstruction2; // UINT8 InvalidInstruction2; //
UINT8 InvalidInstruction3; // UINT8 InvalidInstruction3; //
UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000 UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen UINT16 : 16;
} FLASH_DESCRIPTOR_COMPONENT_SECTION; } FLASH_DESCRIPTOR_COMPONENT_SECTION;
// Region section // Region section
@ -115,16 +115,16 @@ typedef struct _FLASH_DESCRIPTOR_REGION_SECTION {
UINT16 GbeLimit; // UINT16 GbeLimit; //
UINT16 PdrBase; // PDR UINT16 PdrBase; // PDR
UINT16 PdrLimit; // UINT16 PdrLimit; //
UINT16 Region5Base; // Reserved region UINT16 Reserved1Base; // Reserved1
UINT16 Region5Limit; // UINT16 Reserved1Limit; //
UINT16 Region6Base; // Reserved region UINT16 Reserved2Base; // Reserved2
UINT16 Region6Limit; // UINT16 Reserved2Limit; //
UINT16 Region7Base; // Reserved region UINT16 Reserved3Base; // Reserved3
UINT16 Region7Limit; // UINT16 Reserved3Limit; //
UINT16 EcBase; // EC UINT16 EcBase; // EC
UINT16 EcLimit; // UINT16 EcLimit; //
UINT16 Region9Base; // Reserved region UINT16 Reserved4Base; // Reserved4
UINT16 Region9Limit; // UINT16 Reserved4Limit; //
} FLASH_DESCRIPTOR_REGION_SECTION; } FLASH_DESCRIPTOR_REGION_SECTION;
// Master section // Master section

View file

@ -1,6 +1,6 @@
/* ffs.h /* ffs.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -53,6 +53,14 @@ const QByteArray EFI_CAPSULE_GUID
const QByteArray INTEL_CAPSULE_GUID const QByteArray INTEL_CAPSULE_GUID
("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16); ("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16);
// Lenovo capsule GUID
const QByteArray LENOVO_CAPSULE_GUID
("\xD3\xAF\x0B\xE2\x14\x99\x4F\x4F\x95\x37\x31\x29\xE0\x90\xEB\x3C", 16);
// Another Lenovo capsule GUID
const QByteArray LENOVO2_CAPSULE_GUID
("\x76\xFE\xB5\x25\x43\x82\x5C\x4A\xA9\xBD\x7E\xE3\x24\x61\x98\xB5", 16);
// Toshiba EFI Capsule header // Toshiba EFI Capsule header
typedef struct _TOSHIBA_CAPSULE_HEADER { typedef struct _TOSHIBA_CAPSULE_HEADER {
EFI_GUID CapsuleGuid; EFI_GUID CapsuleGuid;

View file

@ -1,6 +1,6 @@
/* fssbuilder.h /* fssbuilder.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -19,11 +19,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <QString> #include <QString>
#include <QModelIndex> #include <QModelIndex>
#include "../common/basetypes.h" #include "basetypes.h"
#include "../common/treemodel.h" #include "treemodel.h"
#include "../common/descriptor.h" #include "descriptor.h"
#include "../common/ffs.h" #include "ffs.h"
#include "../common/utility.h" #include "utility.h"
class FfsBuilder : public QObject class FfsBuilder : public QObject
{ {

View file

@ -1,6 +1,6 @@
/* ffsparser.cpp /* ffsparser.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -10,16 +10,18 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/ */
#include "ffsparser.h"
#include <math.h> #include <math.h>
#include "ffsparser.h" // Region info structure definition
#include "types.h" struct REGION_INFO {
#include "treemodel.h" UINT32 offset;
#include "descriptor.h" UINT32 length;
#include "ffs.h" UINT8 type;
#include "gbe.h" QByteArray data;
#include "me.h" friend bool operator< (const REGION_INFO & lhs, const REGION_INFO & rhs){ return lhs.offset < rhs.offset; }
#include "fit.h" };
FfsParser::FfsParser(TreeModel* treeModel, QObject *parent) FfsParser::FfsParser(TreeModel* treeModel, QObject *parent)
: QObject(parent), model(treeModel), capsuleOffsetFixup(0) : QObject(parent), model(treeModel), capsuleOffsetFixup(0)
@ -45,47 +47,53 @@ void FfsParser::clearMessages()
messagesVector.clear(); messagesVector.clear();
} }
BOOLEAN FfsParser::hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2) // Firmware image parsing functions
STATUS FfsParser::parse(const QByteArray & buffer)
{ {
if (begin1 < begin2 && begin2 < end1) QModelIndex root;
return TRUE; STATUS result = performFirstPass(buffer, root);
if (begin1 < end2 && end2 < end1) addOffsetsRecursive(root);
return TRUE; if (result)
if (begin2 < begin1 && begin1 < end2) return result;
return TRUE;
if (begin2 < end1 && end1 < end2) if (lastVtf.isValid()) {
return TRUE; result = performSecondPass(root);
return FALSE; }
else {
msg(tr("parse: not a single Volume Top File is found, the image may be corrupted"));
}
return result;
} }
// Firmware image parsing functions STATUS FfsParser::performFirstPass(const QByteArray & buffer, QModelIndex & index)
STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex & root)
{ {
// Reset capsule offset fixeup value // Reset capsule offset fixup value
capsuleOffsetFixup = 0; capsuleOffsetFixup = 0;
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER // Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) { if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
msg(tr("parseImageFile: image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER))); msg(tr("performFirstPass: image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
} }
QModelIndex index;
UINT32 capsuleHeaderSize = 0; UINT32 capsuleHeaderSize = 0;
// Check buffer for being normal EFI capsule header // Check buffer for being normal EFI capsule header
if (buffer.startsWith(EFI_CAPSULE_GUID) if (buffer.startsWith(EFI_CAPSULE_GUID)
|| buffer.startsWith(INTEL_CAPSULE_GUID)) { || buffer.startsWith(INTEL_CAPSULE_GUID)
|| buffer.startsWith(LENOVO_CAPSULE_GUID)
|| buffer.startsWith(LENOVO2_CAPSULE_GUID)) {
// Get info // Get info
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData(); const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
// Check sanity of HeaderSize and CapsuleImageSize values // Check sanity of HeaderSize and CapsuleImageSize values
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->CapsuleImageSize) { if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->CapsuleImageSize) {
msg(tr("parseImageFile: UEFI capsule header size of %1h (%2) bytes is invalid") msg(tr("performFirstPass: UEFI capsule header size of %1h (%2) bytes is invalid")
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)); .hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
return ERR_INVALID_CAPSULE; return ERR_INVALID_CAPSULE;
} }
if (capsuleHeader->CapsuleImageSize == 0 || capsuleHeader->CapsuleImageSize > (UINT32)buffer.size()) { if (capsuleHeader->CapsuleImageSize == 0 || capsuleHeader->CapsuleImageSize > (UINT32)buffer.size()) {
msg(tr("parseImageFile: UEFI capsule image size of %1h (%2) bytes is invalid") msg(tr("performFirstPass: UEFI capsule image size of %1h (%2) bytes is invalid")
.hexarg(capsuleHeader->CapsuleImageSize).arg(capsuleHeader->CapsuleImageSize)); .hexarg(capsuleHeader->CapsuleImageSize).arg(capsuleHeader->CapsuleImageSize));
return ERR_INVALID_CAPSULE; return ERR_INVALID_CAPSULE;
} }
@ -105,7 +113,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
capsuleOffsetFixup = capsuleHeaderSize; capsuleOffsetFixup = capsuleHeaderSize;
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, TRUE, QByteArray(), root); index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, true);
} }
// Check buffer for being Toshiba capsule header // Check buffer for being Toshiba capsule header
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) { else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
@ -114,12 +122,12 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
// Check sanity of HeaderSize and FullSize values // Check sanity of HeaderSize and FullSize values
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->FullSize) { if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->FullSize) {
msg(tr("parseImageFile: Toshiba capsule header size of %1h (%2) bytes is invalid") msg(tr("performFirstPass: Toshiba capsule header size of %1h (%2) bytes is invalid")
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)); .hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
return ERR_INVALID_CAPSULE; return ERR_INVALID_CAPSULE;
} }
if (capsuleHeader->FullSize == 0 || capsuleHeader->FullSize > (UINT32)buffer.size()) { if (capsuleHeader->FullSize == 0 || capsuleHeader->FullSize > (UINT32)buffer.size()) {
msg(tr("parseImageFile: Toshiba capsule full size of %1h (%2) bytes is invalid") msg(tr("performFirstPass: Toshiba capsule full size of %1h (%2) bytes is invalid")
.hexarg(capsuleHeader->FullSize).arg(capsuleHeader->FullSize)); .hexarg(capsuleHeader->FullSize).arg(capsuleHeader->FullSize));
return ERR_INVALID_CAPSULE; return ERR_INVALID_CAPSULE;
} }
@ -139,14 +147,14 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
capsuleOffsetFixup = capsuleHeaderSize; capsuleOffsetFixup = capsuleHeaderSize;
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, TRUE, QByteArray(), root); index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, true);
} }
// Check buffer for being extended Aptio signed capsule header // Check buffer for being extended Aptio capsule header
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) { else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID); bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID);
if ((UINT32)buffer.size() <= sizeof(APTIO_CAPSULE_HEADER)) { if ((UINT32)buffer.size() <= sizeof(APTIO_CAPSULE_HEADER)) {
msg(tr("parseImageFile: AMI capsule image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(APTIO_CAPSULE_HEADER)).arg(sizeof(APTIO_CAPSULE_HEADER))); msg(tr("performFirstPass: AMI capsule image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(APTIO_CAPSULE_HEADER)).arg(sizeof(APTIO_CAPSULE_HEADER)));
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
} }
@ -155,11 +163,11 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
// Check sanity of RomImageOffset and CapsuleImageSize values // Check sanity of RomImageOffset and CapsuleImageSize values
if (capsuleHeader->RomImageOffset == 0 || capsuleHeader->RomImageOffset > (UINT32)buffer.size() || capsuleHeader->RomImageOffset > capsuleHeader->CapsuleHeader.CapsuleImageSize) { if (capsuleHeader->RomImageOffset == 0 || capsuleHeader->RomImageOffset > (UINT32)buffer.size() || capsuleHeader->RomImageOffset > capsuleHeader->CapsuleHeader.CapsuleImageSize) {
msg(tr("parseImageFile: AMI capsule image offset of %1h (%2) bytes is invalid").hexarg(capsuleHeader->RomImageOffset).arg(capsuleHeader->RomImageOffset)); msg(tr("performFirstPass: AMI capsule image offset of %1h (%2) bytes is invalid").hexarg(capsuleHeader->RomImageOffset).arg(capsuleHeader->RomImageOffset));
return ERR_INVALID_CAPSULE; return ERR_INVALID_CAPSULE;
} }
if (capsuleHeader->CapsuleHeader.CapsuleImageSize == 0 || capsuleHeader->CapsuleHeader.CapsuleImageSize > (UINT32)buffer.size()) { if (capsuleHeader->CapsuleHeader.CapsuleImageSize == 0 || capsuleHeader->CapsuleHeader.CapsuleImageSize > (UINT32)buffer.size()) {
msg(tr("parseImageFile: AMI capsule image size of %1h (%2) bytes is invalid").hexarg(capsuleHeader->CapsuleHeader.CapsuleImageSize).arg(capsuleHeader->CapsuleHeader.CapsuleImageSize)); msg(tr("performFirstPass: AMI capsule image size of %1h (%2) bytes is invalid").hexarg(capsuleHeader->CapsuleHeader.CapsuleImageSize).arg(capsuleHeader->CapsuleHeader.CapsuleImageSize));
return ERR_INVALID_CAPSULE; return ERR_INVALID_CAPSULE;
} }
@ -178,17 +186,13 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
capsuleOffsetFixup = capsuleHeaderSize; capsuleOffsetFixup = capsuleHeaderSize;
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, QString(), info, header, body, TRUE, QByteArray(), root); index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, QString(), info, header, body, true);
// Show message about possible Aptio signature break // Show message about possible Aptio signature break
if (signedCapsule) { if (signedCapsule) {
msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index); msg(tr("performFirstPass: Aptio capsule signature may become invalid after image modifications"), index);
} }
} }
// Other cases
else {
index = root;
}
// Skip capsule header to have flash chip image // Skip capsule header to have flash chip image
QByteArray flashImage = buffer.mid(capsuleHeaderSize); QByteArray flashImage = buffer.mid(capsuleHeaderSize);
@ -202,13 +206,16 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
// Parse as Intel image // Parse as Intel image
QModelIndex imageIndex; QModelIndex imageIndex;
result = parseIntelImage(flashImage, capsuleHeaderSize, index, imageIndex); result = parseIntelImage(flashImage, capsuleHeaderSize, index, imageIndex);
if (result != ERR_INVALID_FLASH_DESCRIPTOR) if (result != ERR_INVALID_FLASH_DESCRIPTOR) {
if (!index.isValid())
index = imageIndex;
return result; return result;
}
} }
// Get info // Get info
QString name = tr("UEFI image"); QString name = tr("UEFI image");
QString info = tr("Full size: %2h (%3)").hexarg(flashImage.size()).arg(flashImage.size()); QString info = tr("Full size: %1h (%2)").hexarg(flashImage.size()).arg(flashImage.size());
// Construct parsing data // Construct parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(index); PARSING_DATA pdata = parsingDataFromQModelIndex(index);
@ -219,21 +226,9 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
// Parse the image // Parse the image
result = parseRawArea(flashImage, biosIndex); result = parseRawArea(flashImage, biosIndex);
if (result) if (!index.isValid())
return result; index = biosIndex;
return result;
// Add offsets
addOffsetsRecursive(index);
// Check if the last VTF is found
if (!lastVtf.isValid()) {
msg(tr("parseImageFile: not a single Volume Top File is found, the image may be corrupted"), biosIndex);
}
else {
return performSecondPass(biosIndex);
}
return ERR_SUCCESS;
} }
STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
@ -247,8 +242,6 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
// Store the beginning of descriptor as descriptor base address // Store the beginning of descriptor as descriptor base address
const UINT8* descriptor = (const UINT8*)intelImage.constData(); const UINT8* descriptor = (const UINT8*)intelImage.constData();
UINT32 descriptorBegin = 0;
UINT32 descriptorEnd = FLASH_DESCRIPTOR_SIZE;
// Check for buffer size to be greater or equal to descriptor region size // Check for buffer size to be greater or equal to descriptor region size
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) { if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
@ -258,7 +251,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
// Parse descriptor map // Parse descriptor map
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE); const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
// Check sanity of base values // Check sanity of base values
if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
@ -291,43 +284,47 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
return ERR_INVALID_FLASH_DESCRIPTOR; return ERR_INVALID_FLASH_DESCRIPTOR;
} }
// Regions
QVector<REGION_INFO> regions;
// ME region // ME region
QByteArray me; REGION_INFO me;
UINT32 meBegin = 0; me.type = Subtypes::MeRegion;
UINT32 meEnd = 0; me.offset = 0;
me.length = 0;
if (regionSection->MeLimit) { if (regionSection->MeLimit) {
meBegin = calculateRegionOffset(regionSection->MeBase); me.offset = calculateRegionOffset(regionSection->MeBase);
meEnd = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); me.length = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit);
me = intelImage.mid(meBegin, meEnd); me.data = intelImage.mid(me.offset, me.length);
meEnd += meBegin; regions.append(me);
} }
// BIOS region // BIOS region
QByteArray bios; REGION_INFO bios;
UINT32 biosBegin = 0; bios.type = Subtypes::BiosRegion;
UINT32 biosEnd = 0; bios.offset = 0;
bios.length = 0;
if (regionSection->BiosLimit) { if (regionSection->BiosLimit) {
biosBegin = calculateRegionOffset(regionSection->BiosBase); bios.offset = calculateRegionOffset(regionSection->BiosBase);
biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit);
// Check for Gigabyte specific descriptor map // Check for Gigabyte specific descriptor map
if (biosEnd - biosBegin == (UINT32)intelImage.size()) { if (bios.length == (UINT32)intelImage.size()) {
if (!meEnd) { if (!me.offset) {
msg(tr("parseIntelImage: can't determine BIOS region start from Gigabyte-specific descriptor")); msg(tr("parseIntelImage: can't determine BIOS region start from Gigabyte-specific descriptor"));
return ERR_INVALID_FLASH_DESCRIPTOR; return ERR_INVALID_FLASH_DESCRIPTOR;
} }
biosBegin = meEnd; // Use ME region end as BIOS region offset
bios = intelImage.mid(biosBegin, biosEnd); bios.offset = me.offset + me.length;
// biosEnd will point to the end of the image file bios.length = (UINT32)intelImage.size() - bios.offset;
// it may be wrong, but it's pretty hard to detect a padding after BIOS region bios.data = intelImage.mid(bios.offset, bios.length);
// with malformed descriptor
} }
// Normal descriptor map // Normal descriptor map
else { else {
bios = intelImage.mid(biosBegin, biosEnd); bios.data = intelImage.mid(bios.offset, bios.length);
// Calculate biosEnd
biosEnd += biosBegin;
} }
regions.append(bios);
} }
else { else {
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor"));
@ -335,107 +332,148 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
} }
// GbE region // GbE region
QByteArray gbe; REGION_INFO gbe;
UINT32 gbeBegin = 0; gbe.type = Subtypes::GbeRegion;
UINT32 gbeEnd = 0; gbe.offset = 0;
gbe.length = 0;
if (regionSection->GbeLimit) { if (regionSection->GbeLimit) {
gbeBegin = calculateRegionOffset(regionSection->GbeBase); gbe.offset = calculateRegionOffset(regionSection->GbeBase);
gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); gbe.length = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit);
gbe = intelImage.mid(gbeBegin, gbeEnd); gbe.data = intelImage.mid(gbe.offset, gbe.length);
gbeEnd += gbeBegin; regions.append(gbe);
} }
// PDR region // PDR region
QByteArray pdr; REGION_INFO pdr;
UINT32 pdrBegin = 0; pdr.type = Subtypes::PdrRegion;
UINT32 pdrEnd = 0; pdr.offset = 0;
pdr.length = 0;
if (regionSection->PdrLimit) { if (regionSection->PdrLimit) {
pdrBegin = calculateRegionOffset(regionSection->PdrBase); pdr.offset = calculateRegionOffset(regionSection->PdrBase);
pdrEnd = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); pdr.length = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit);
pdr = intelImage.mid(pdrBegin, pdrEnd); pdr.data = intelImage.mid(pdr.offset, pdr.length);
pdrEnd += pdrBegin; regions.append(pdr);
} }
// Reserved1 region
REGION_INFO reserved1;
reserved1.type = Subtypes::Reserved1Region;
reserved1.offset = 0;
reserved1.length = 0;
if (regionSection->Reserved1Limit && regionSection->Reserved1Base != 0xFFFF && regionSection->Reserved1Limit != 0xFFFF) {
reserved1.offset = calculateRegionOffset(regionSection->Reserved1Base);
reserved1.length = calculateRegionSize(regionSection->Reserved1Base, regionSection->Reserved1Limit);
reserved1.data = intelImage.mid(reserved1.offset, reserved1.length);
regions.append(reserved1);
}
// Reserved2 region
REGION_INFO reserved2;
reserved2.type = Subtypes::Reserved2Region;
reserved2.offset = 0;
reserved2.length = 0;
if (regionSection->Reserved2Limit && regionSection->Reserved2Base != 0xFFFF && regionSection->Reserved2Limit != 0xFFFF) {
reserved2.offset = calculateRegionOffset(regionSection->Reserved2Base);
reserved2.length = calculateRegionSize(regionSection->Reserved2Base, regionSection->Reserved2Limit);
reserved2.data = intelImage.mid(reserved2.offset, reserved2.length);
regions.append(reserved2);
}
// Reserved3 region
REGION_INFO reserved3;
reserved3.type = Subtypes::Reserved3Region;
reserved3.offset = 0;
reserved3.length = 0;
// EC region // EC region
QByteArray ec; REGION_INFO ec;
UINT32 ecBegin = 0; ec.type = Subtypes::EcRegion;
UINT32 ecEnd = 0; ec.offset = 0;
ec.length = 0;
// Reserved4 region
REGION_INFO reserved4;
reserved3.type = Subtypes::Reserved4Region;
reserved4.offset = 0;
reserved4.length = 0;
// Check for EC and reserved region 4 only for v2 descriptor
if (descriptorVersion == 2) { if (descriptorVersion == 2) {
if (regionSection->Reserved3Limit) {
reserved3.offset = calculateRegionOffset(regionSection->Reserved3Base);
reserved3.length = calculateRegionSize(regionSection->Reserved3Base, regionSection->Reserved3Limit);
reserved3.data = intelImage.mid(reserved3.offset, reserved3.length);
regions.append(reserved3);
}
if (regionSection->EcLimit) { if (regionSection->EcLimit) {
pdrBegin = calculateRegionOffset(regionSection->EcBase); ec.offset = calculateRegionOffset(regionSection->EcBase);
pdrEnd = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit); ec.length = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit);
pdr = intelImage.mid(ecBegin, ecEnd); ec.data = intelImage.mid(ec.offset, ec.length);
ecEnd += ecBegin; regions.append(ec);
}
if (regionSection->Reserved4Limit) {
reserved4.offset = calculateRegionOffset(regionSection->Reserved4Base);
reserved4.length = calculateRegionSize(regionSection->Reserved4Base, regionSection->Reserved4Limit);
reserved4.data = intelImage.mid(reserved4.offset, reserved4.length);
regions.append(reserved4);
} }
} }
// Check for intersections between regions // Sort regions in ascending order
// Descriptor qSort(regions);
if (hasIntersection(descriptorBegin, descriptorEnd, gbeBegin, gbeEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (hasIntersection(descriptorBegin, descriptorEnd, meBegin, meEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with ME region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (hasIntersection(descriptorBegin, descriptorEnd, biosBegin, biosEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with BIOS region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (hasIntersection(descriptorBegin, descriptorEnd, pdrBegin, pdrEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(descriptorBegin, descriptorEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// GbE
if (hasIntersection(gbeBegin, gbeEnd, meBegin, meEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (hasIntersection(gbeBegin, gbeEnd, biosBegin, biosEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with BIOS region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (hasIntersection(gbeBegin, gbeEnd, pdrBegin, pdrEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(gbeBegin, gbeEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// ME
if (hasIntersection(meBegin, meEnd, biosBegin, biosEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (hasIntersection(meBegin, meEnd, pdrBegin, pdrEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(meBegin, meEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// BIOS
if (hasIntersection(biosBegin, biosEnd, pdrBegin, pdrEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(biosBegin, biosEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// PDR
if (descriptorVersion == 2 && hasIntersection(pdrBegin, pdrEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, PDR region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// Check for intersections and paddings between regions
REGION_INFO region;
// Check intersection with the descriptor
if (regions.first().offset < FLASH_DESCRIPTOR_SIZE) {
msg(tr("parseIntelImage: %1 region has intersection with flash descriptor").arg(itemSubtypeToQString(Types::Region, regions.first().type)), index);
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// Check for padding between descriptor and the first region
else if (regions.first().offset > FLASH_DESCRIPTOR_SIZE) {
region.offset = FLASH_DESCRIPTOR_SIZE;
region.length = regions.first().offset - FLASH_DESCRIPTOR_SIZE;
region.data = intelImage.mid(region.offset, region.length);
region.type = getPaddingType(region.data);
regions.prepend(region);
}
// Check for intersections/paddings between regions
for (int i = 1; i < regions.count(); i++) {
UINT32 previousRegionEnd = regions[i-1].offset + regions[i-1].length;
// Check that current region is fully present in the image
if (regions[i].offset + regions[i].length > (UINT32)intelImage.size()) {
msg(tr("parseIntelImage: %1 region is located outside of opened image, if your system uses dual-chip storage, please append another part to the opened image")
.arg(itemSubtypeToQString(Types::Region, regions[i].type)), index);
return ERR_TRUNCATED_IMAGE;
}
// Check for intersection with previous region
if (regions[i].offset < previousRegionEnd) {
msg(tr("parseIntelImage: %1 region has intersection with %2 region")
.arg(itemSubtypeToQString(Types::Region, regions[i].type))
.arg(itemSubtypeToQString(Types::Region, regions[i-1].type)), index);
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// Check for padding between current and previous regions
else if (regions[i].offset > previousRegionEnd) {
region.offset = previousRegionEnd;
region.length = regions[i].offset - previousRegionEnd;
region.data = intelImage.mid(region.offset, region.length);
region.type = getPaddingType(region.data);
regions.insert(i - 1, region);
}
}
// Check for padding after the last region
if (regions.last().offset + regions.last().length < (UINT32)intelImage.size()) {
region.offset = regions.last().offset + regions.last().length;
region.length = intelImage.size() - region.offset;
region.data = intelImage.mid(region.offset, region.length);
region.type = getPaddingType(region.data);
regions.append(region);
}
// Region map is consistent // Region map is consistent
// Intel image // Intel image
@ -459,24 +497,11 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
QByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE); QByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
name = tr("Descriptor region"); name = tr("Descriptor region");
info = tr("Full size: %1h (%2)").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE); info = tr("Full size: %1h (%2)").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE);
// Check regions presence once again // Add offsets of actual regions
QVector<UINT32> offsets; for (int i = 0; i < regions.count(); i++) {
if (regionSection->GbeLimit) { if (regions[i].type != Subtypes::ZeroPadding && regions[i].type != Subtypes::OnePadding && regions[i].type != Subtypes::DataPadding)
offsets.append(gbeBegin); info += tr("\n%1 region offset: %2h").arg(itemSubtypeToQString(Types::Region, regions[i].type)).hexarg(regions[i].offset + parentOffset);
info += tr("\nGbE region offset: %1h").hexarg(gbeBegin + parentOffset);
}
if (regionSection->MeLimit) {
offsets.append(meBegin);
info += tr("\nME region offset: %1h").hexarg(meBegin + parentOffset);
}
if (regionSection->BiosLimit) {
offsets.append(biosBegin);
info += tr("\nBIOS region offset: %1h").hexarg(biosBegin + parentOffset);
}
if (regionSection->PdrLimit) {
offsets.append(pdrBegin);
info += tr("\nPDR region offset: %1h").hexarg(pdrBegin + parentOffset);
} }
// Region access settings // Region access settings
@ -555,93 +580,63 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
} }
// Add descriptor tree item // Add descriptor tree item
model->addItem(Types::Region, Subtypes::DescriptorRegion, name, QString(), info, QByteArray(), body, TRUE, parsingDataToQByteArray(pdata), index); QModelIndex regionIndex = model->addItem(Types::Region, Subtypes::DescriptorRegion, name, QString(), info, QByteArray(), body, TRUE, parsingDataToQByteArray(pdata), index);
// Sort regions in ascending order
qSort(offsets);
// Parse regions // Parse regions
UINT8 result = 0; UINT8 result = ERR_SUCCESS;
for (int i = 0; i < offsets.count(); i++) { UINT8 parseResult = ERR_SUCCESS;
// Parse GbE region Q_FOREACH(region, regions) {
if (offsets.at(i) == gbeBegin) { switch (region.type) {
QModelIndex gbeIndex; case Subtypes::BiosRegion:
result = parseGbeRegion(gbe, gbeBegin, index, gbeIndex); result = parseBiosRegion(region.data, region.offset, index, regionIndex);
break;
case Subtypes::MeRegion:
result = parseMeRegion(region.data, region.offset, index, regionIndex);
break;
case Subtypes::GbeRegion:
result = parseGbeRegion(region.data, region.offset, index, regionIndex);
break;
case Subtypes::PdrRegion:
result = parsePdrRegion(region.data, region.offset, index, regionIndex);
break;
case Subtypes::Reserved1Region:
case Subtypes::Reserved2Region:
case Subtypes::Reserved3Region:
case Subtypes::EcRegion:
case Subtypes::Reserved4Region:
result = parseGeneralRegion(region.type, region.data, region.offset, index, regionIndex);
break;
case Subtypes::ZeroPadding:
case Subtypes::OnePadding:
case Subtypes::DataPadding: {
// Add padding between regions
QByteArray padding = intelImage.mid(region.offset, region.length);
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Get info
name = tr("Padding");
info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size());
// Construct parsing data
pdata.offset = parentOffset + region.offset;
// Add tree item
regionIndex = model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
result = ERR_SUCCESS;
} break;
default:
msg(tr("parseIntelImage: region of unknown type found"), index);
result = ERR_INVALID_FLASH_DESCRIPTOR;
} }
// Parse ME region // Store the first failed result as a final result
else if (offsets.at(i) == meBegin) { if (!parseResult && result)
QModelIndex meIndex; parseResult = result;
result = parseMeRegion(me, meBegin, index, meIndex);
}
// Parse BIOS region
else if (offsets.at(i) == biosBegin) {
QModelIndex biosIndex;
result = parseBiosRegion(bios, biosBegin, index, biosIndex);
}
// Parse PDR region
else if (offsets.at(i) == pdrBegin) {
QModelIndex pdrIndex;
result = parsePdrRegion(pdr, pdrBegin, index, pdrIndex);
}
// Parse EC region
else if (descriptorVersion == 2 && offsets.at(i) == ecBegin) {
QModelIndex ecIndex;
result = parseEcRegion(ec, ecBegin, index, ecIndex);
}
if (result)
return result;
} }
// Add the data after the last region as padding return parseResult;
UINT32 IntelDataEnd = 0;
UINT32 LastRegionOffset = offsets.last();
if (LastRegionOffset == gbeBegin)
IntelDataEnd = gbeEnd;
else if (LastRegionOffset == meBegin)
IntelDataEnd = meEnd;
else if (LastRegionOffset == biosBegin)
IntelDataEnd = biosEnd;
else if (LastRegionOffset == pdrBegin)
IntelDataEnd = pdrEnd;
else if (descriptorVersion == 2 && LastRegionOffset == ecBegin)
IntelDataEnd = ecEnd;
if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated
msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged")
.hexarg(intelImage.size()).arg(intelImage.size())
.hexarg(IntelDataEnd).arg(IntelDataEnd), index);
return ERR_TRUNCATED_IMAGE;
}
else if (IntelDataEnd < (UINT32)intelImage.size()) { // Insert padding
QByteArray padding = intelImage.mid(IntelDataEnd);
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
// Get info
name = tr("Padding");
info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size());
// Construct parsing data
pdata.offset = IntelDataEnd;
// Add tree item
model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
}
// Add offsets
addOffsetsRecursive(index);
// Check if the last VTF is found
if (!lastVtf.isValid()) {
msg(tr("parseIntelImage: not a single Volume Top File is found, the image may be corrupted"), index);
}
else {
return performSecondPass(index);
}
return ERR_SUCCESS;
} }
STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
@ -774,25 +769,25 @@ STATUS FfsParser::parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffs
return ERR_SUCCESS; return ERR_SUCCESS;
} }
STATUS FfsParser::parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) STATUS FfsParser::parseGeneralRegion(const UINT8 subtype, const QByteArray & region, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{ {
// Check sanity // Check sanity
if (ec.isEmpty()) if (region.isEmpty())
return ERR_EMPTY_REGION; return ERR_EMPTY_REGION;
// Get parent's parsing data // Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(parent); PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get info // Get info
QString name = tr("EC region"); QString name = tr("%1 region").arg(itemSubtypeToQString(Types::Region, subtype));
QString info = tr("Full size: %1h (%2)"). QString info = tr("Full size: %1h (%2)").
hexarg(ec.size()).arg(ec.size()); hexarg(region.size()).arg(region.size());
// Construct parsing data // Construct parsing data
pdata.offset += parentOffset; pdata.offset += parentOffset;
// Add tree item // Add tree item
index = model->addItem(Types::Region, Subtypes::EcRegion, name, QString(), info, QByteArray(), ec, TRUE, parsingDataToQByteArray(pdata), parent); index = model->addItem(Types::Region, subtype, name, QString(), info, QByteArray(), region, TRUE, parsingDataToQByteArray(pdata), parent);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -1190,7 +1185,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
return ERR_SUCCESS; return ERR_SUCCESS;
} }
STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset) STATUS FfsParser::findNextVolume(const QModelIndex & index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset)
{ {
int nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset); int nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset);
if (nextIndex < EFI_FV_SIGNATURE_OFFSET) if (nextIndex < EFI_FV_SIGNATURE_OFFSET)
@ -1745,7 +1740,7 @@ STATUS FfsParser::parsePadFileBody(const QModelIndex & index)
return ERR_SUCCESS; return ERR_SUCCESS;
} }
STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex & index) STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex & index, const bool preparse)
{ {
// Sanity check // Sanity check
if (!index.isValid()) if (!index.isValid())
@ -1759,6 +1754,7 @@ STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex &
UINT32 headerSize = model->header(index).size(); UINT32 headerSize = model->header(index).size();
UINT32 sectionOffset = 0; UINT32 sectionOffset = 0;
STATUS result = ERR_SUCCESS;
while (sectionOffset < bodySize) { while (sectionOffset < bodySize) {
// Get section size // Get section size
UINT32 sectionSize = getSectionSize(sections, sectionOffset, pdata.ffsVersion); UINT32 sectionSize = getSectionSize(sections, sectionOffset, pdata.ffsVersion);
@ -1773,27 +1769,36 @@ STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex &
// Constuct parsing data // Constuct parsing data
pdata.offset += headerSize + sectionOffset; pdata.offset += headerSize + sectionOffset;
// Add tree item // Final parsing
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index); if (!preparse) {
// Add tree item
// Show message QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
msg(tr("parseSections: non-UEFI data found in sections area"), dataIndex);
// Show message
msg(tr("parseSections: non-UEFI data found in sections area"), dataIndex);
}
// Preparsing
else {
return ERR_INVALID_SECTION;
}
break; // Exit from parsing loop break; // Exit from parsing loop
} }
// Parse section header // Parse section header
QModelIndex sectionIndex; QModelIndex sectionIndex;
STATUS result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex); result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex);
if (result) if (result) {
msg(tr("parseSections: section header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index); if (!preparse)
msg(tr("parseSections: section header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
else
return ERR_INVALID_SECTION;
}
// Move to next section // Move to next section
sectionOffset += sectionSize; sectionOffset += sectionSize;
sectionOffset = ALIGN4(sectionOffset); sectionOffset = ALIGN4(sectionOffset);
} }
//Parse bodies //Parse bodies, will be skipped on preparse phase
for (int i = 0; i < model->rowCount(index); i++) { for (int i = 0; i < model->rowCount(index); i++) {
QModelIndex current = index.child(i, 0); QModelIndex current = index.child(i, 0);
switch (model->type(current)) { switch (model->type(current)) {
@ -2013,7 +2018,7 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
// Check certificate type // Check certificate type
if (certType == WIN_CERT_TYPE_EFI_GUID) { if (certType == WIN_CERT_TYPE_EFI_GUID) {
additionalInfo += tr("\nCertificate type: UEFI").hexarg2(certType, 4); additionalInfo += tr("\nCertificate type: UEFI");
// Get certificate GUID // Get certificate GUID
const WIN_CERTIFICATE_UEFI_GUID* winCertificateUefiGuid = (const WIN_CERTIFICATE_UEFI_GUID*)(section.constData() + nextHeaderOffset); const WIN_CERTIFICATE_UEFI_GUID* winCertificateUefiGuid = (const WIN_CERTIFICATE_UEFI_GUID*)(section.constData() + nextHeaderOffset);
@ -2256,7 +2261,8 @@ STATUS FfsParser::parseCompressedSectionBody(const QModelIndex & index)
// Decompress section // Decompress section
QByteArray decompressed; QByteArray decompressed;
STATUS result = decompress(model->body(index), algorithm, decompressed); QByteArray efiDecompressed;
STATUS result = decompress(model->body(index), algorithm, decompressed, efiDecompressed);
if (result) { if (result) {
msg(tr("parseCompressedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index); msg(tr("parseCompressedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
return ERR_SUCCESS; return ERR_SUCCESS;
@ -2272,6 +2278,22 @@ STATUS FfsParser::parseCompressedSectionBody(const QModelIndex & index)
model->addInfo(index, tr("\nActual decompressed size: %1h (%2)").hexarg(decompressed.size()).arg(decompressed.size())); model->addInfo(index, tr("\nActual decompressed size: %1h (%2)").hexarg(decompressed.size()).arg(decompressed.size()));
} }
// Check for undecided compression algorithm, this is a special case
if (algorithm == COMPRESSION_ALGORITHM_UNDECIDED) {
// Try preparse of sections decompressed with Tiano algorithm
if (ERR_SUCCESS == parseSections(decompressed, index, true)) {
algorithm = COMPRESSION_ALGORITHM_TIANO;
}
// Try preparse of sections decompressed with EFI 1.1 algorithm
else if (ERR_SUCCESS == parseSections(efiDecompressed, index, true)) {
algorithm = COMPRESSION_ALGORITHM_EFI11;
decompressed = efiDecompressed;
}
else {
msg(tr("parseCompressedSectionBody: can't guess the correct decompression algorithm, both preparse steps are failed"), index);
}
}
// Add info // Add info
model->addInfo(index, tr("\nCompression algorithm: %1").arg(compressionTypeToQString(algorithm))); model->addInfo(index, tr("\nCompression algorithm: %1").arg(compressionTypeToQString(algorithm)));
@ -2302,24 +2324,33 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE; UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
// Tiano compressed section // Tiano compressed section
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) { if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
QByteArray efiDecompressed;
algorithm = EFI_STANDARD_COMPRESSION; algorithm = EFI_STANDARD_COMPRESSION;
STATUS result = decompress(model->body(index), algorithm, processed); STATUS result = decompress(model->body(index), algorithm, processed, efiDecompressed);
if (result) { if (result) {
parseCurrentSection = false; parseCurrentSection = false;
msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index); msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
if (algorithm == COMPRESSION_ALGORITHM_TIANO) { // Check for undecided compression algorithm, this is a special case
info += tr("\nCompression algorithm: Tiano"); if (algorithm == COMPRESSION_ALGORITHM_UNDECIDED) {
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length()); // Try preparse of sections decompressed with Tiano algorithm
if (ERR_SUCCESS == parseSections(processed, index, true)) {
algorithm = COMPRESSION_ALGORITHM_TIANO;
}
// Try preparse of sections decompressed with EFI 1.1 algorithm
else if (ERR_SUCCESS == parseSections(efiDecompressed, index, true)) {
algorithm = COMPRESSION_ALGORITHM_EFI11;
processed = efiDecompressed;
}
else {
msg(tr("parseGuidedSectionBody: can't guess the correct decompression algorithm, both preparse steps are failed"), index);
}
} }
else if (algorithm == COMPRESSION_ALGORITHM_EFI11) {
info += tr("\nCompression algorithm: EFI 1.1"); info += tr("\nCompression algorithm: %1").arg(compressionTypeToQString(algorithm));
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length()); info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
}
else
info += tr("\nCompression type: unknown");
} }
// LZMA compressed section // LZMA compressed section
else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) { else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) {

View file

@ -1,6 +1,6 @@
/* ffsparser.h /* ffsparser.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -26,6 +26,13 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "utility.h" #include "utility.h"
#include "peimage.h" #include "peimage.h"
#include "parsingdata.h" #include "parsingdata.h"
#include "types.h"
#include "treemodel.h"
#include "descriptor.h"
#include "ffs.h"
#include "gbe.h"
#include "me.h"
#include "fit.h"
class TreeModel; class TreeModel;
@ -44,7 +51,7 @@ public:
void clearMessages(); void clearMessages();
// Firmware image parsing // Firmware image parsing
STATUS parseImageFile(const QByteArray & imageFile, const QModelIndex & index); STATUS parse(const QByteArray &buffer);
STATUS parseRawArea(const QByteArray & data, const QModelIndex & index); STATUS parseRawArea(const QByteArray & data, const QModelIndex & index);
STATUS parseVolumeHeader(const QByteArray & volume, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseVolumeHeader(const QByteArray & volume, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseVolumeBody(const QModelIndex & index); STATUS parseVolumeBody(const QModelIndex & index);
@ -67,11 +74,11 @@ private:
STATUS parseMeRegion(const QByteArray & me, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseMeRegion(const QByteArray & me, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseGeneralRegion(const UINT8 subtype, const QByteArray & region, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePadFileBody(const QModelIndex & index); STATUS parsePadFileBody(const QModelIndex & index);
STATUS parseVolumeNonUefiData(const QByteArray & data, const UINT32 parentOffset, const QModelIndex & index); STATUS parseVolumeNonUefiData(const QByteArray & data, const UINT32 parentOffset, const QModelIndex & index);
STATUS parseSections(const QByteArray & sections, const QModelIndex & index); STATUS parseSections(const QByteArray & sections, const QModelIndex & index, const bool preparse = false);
STATUS parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, 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); STATUS parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
@ -91,21 +98,18 @@ private:
UINT8 getPaddingType(const QByteArray & padding); UINT8 getPaddingType(const QByteArray & padding);
STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed); STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed);
STATUS findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset); STATUS findNextVolume(const QModelIndex & index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
STATUS getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize); STATUS getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
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 performFirstPass(const QByteArray & imageFile, QModelIndex & index);
STATUS performSecondPass(const QModelIndex & index); STATUS performSecondPass(const QModelIndex & index);
STATUS addOffsetsRecursive(const QModelIndex & index); STATUS addOffsetsRecursive(const QModelIndex & index);
STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff); STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff);
// Internal operations
BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
// Message helper // Message helper
void msg(const QString & message, const QModelIndex &index = QModelIndex()); void msg(const QString & message, const QModelIndex &index = QModelIndex());
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
/* types.cpp /* types.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -21,16 +21,24 @@ QString regionTypeToQString(const UINT8 type)
{ {
case Subtypes::DescriptorRegion: case Subtypes::DescriptorRegion:
return QObject::tr("Descriptor"); return QObject::tr("Descriptor");
case Subtypes::GbeRegion:
return QObject::tr("GbE");
case Subtypes::MeRegion:
return QObject::tr("ME");
case Subtypes::BiosRegion: case Subtypes::BiosRegion:
return QObject::tr("BIOS"); return QObject::tr("BIOS");
case Subtypes::MeRegion:
return QObject::tr("ME");
case Subtypes::GbeRegion:
return QObject::tr("GbE");
case Subtypes::PdrRegion: case Subtypes::PdrRegion:
return QObject::tr("PDR"); return QObject::tr("PDR");
case Subtypes::Reserved1Region:
return QObject::tr("Reserved1");
case Subtypes::Reserved2Region:
return QObject::tr("Reserved2");
case Subtypes::Reserved3Region:
return QObject::tr("Reserved3");
case Subtypes::EcRegion: case Subtypes::EcRegion:
return QObject::tr("EC"); return QObject::tr("EC");
case Subtypes::Reserved4Region:
return QObject::tr("Reserved4");
default: default:
return QObject::tr("Unknown"); return QObject::tr("Unknown");
}; };
@ -124,6 +132,8 @@ QString compressionTypeToQString(const UINT8 algorithm)
return QObject::tr("EFI 1.1"); return QObject::tr("EFI 1.1");
case COMPRESSION_ALGORITHM_TIANO: case COMPRESSION_ALGORITHM_TIANO:
return QObject::tr("Tiano"); return QObject::tr("Tiano");
case COMPRESSION_ALGORITHM_UNDECIDED:
return QObject::tr("Undecided Tiano/EFI 1.1");
case COMPRESSION_ALGORITHM_LZMA: case COMPRESSION_ALGORITHM_LZMA:
return QObject::tr("LZMA"); return QObject::tr("LZMA");
case COMPRESSION_ALGORITHM_IMLZMA: case COMPRESSION_ALGORITHM_IMLZMA:

View file

@ -1,6 +1,6 @@
/* types.h /* types.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -66,12 +66,16 @@ namespace Subtypes {
}; };
enum RegionSubtypes { enum RegionSubtypes {
DescriptorRegion = 100, DescriptorRegion = 0,
GbeRegion,
MeRegion,
BiosRegion, BiosRegion,
MeRegion,
GbeRegion,
PdrRegion, PdrRegion,
EcRegion Reserved1Region,
Reserved2Region,
Reserved3Region,
EcRegion,
Reserved4Region
}; };
enum PaddingSubtypes { enum PaddingSubtypes {

View file

@ -1,6 +1,6 @@
/* utility.cpp /* utility.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -151,11 +151,12 @@ UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
} }
// Compression routines // Compression routines
STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArray & decompressedData) STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArray & decompressedData, QByteArray & efiDecompressedData)
{ {
const UINT8* data; const UINT8* data;
UINT32 dataSize; UINT32 dataSize;
UINT8* decompressed; UINT8* decompressed;
UINT8* efiDecompressed;
UINT32 decompressedSize = 0; UINT32 decompressedSize = 0;
UINT8* scratch; UINT8* scratch;
UINT32 scratchSize = 0; UINT32 scratchSize = 0;
@ -167,7 +168,7 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
decompressedData = compressedData; decompressedData = compressedData;
algorithm = COMPRESSION_ALGORITHM_NONE; algorithm = COMPRESSION_ALGORITHM_NONE;
return ERR_SUCCESS; return ERR_SUCCESS;
case EFI_STANDARD_COMPRESSION: case EFI_STANDARD_COMPRESSION: {
// Set default algorithm to unknown // Set default algorithm to unknown
algorithm = COMPRESSION_ALGORITHM_UNKNOWN; algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
@ -185,34 +186,45 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
return ERR_STANDARD_DECOMPRESSION_FAILED; return ERR_STANDARD_DECOMPRESSION_FAILED;
// Allocate memory // Allocate memory
try { decompressed = (UINT8*)malloc(decompressedSize);
decompressed = new UINT8[decompressedSize]; efiDecompressed = (UINT8*)malloc(decompressedSize);
scratch = new UINT8[scratchSize]; scratch = (UINT8*)malloc(scratchSize);
} if (!decompressed || !efiDecompressed || !scratch) {
catch (std::bad_alloc) { if (decompressed) free(decompressed);
if (efiDecompressed) free(efiDecompressed);
if (scratch) free(scratch);
return ERR_STANDARD_DECOMPRESSION_FAILED; return ERR_STANDARD_DECOMPRESSION_FAILED;
} }
// Decompress section data // Decompress section data using both algorithms
STATUS result = ERR_SUCCESS;
// Try Tiano
STATUS TianoResult = TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize);
// Try EFI 1.1
STATUS EfiResult = EfiDecompress(data, dataSize, efiDecompressed, decompressedSize, scratch, scratchSize);
//TODO: separate EFI1.1 from Tiano another way if (EfiResult == ERR_SUCCESS && TianoResult == ERR_SUCCESS) { // Both decompressions are OK
// Try Tiano decompression first algorithm = COMPRESSION_ALGORITHM_UNDECIDED;
if (ERR_SUCCESS != TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) { decompressedData = QByteArray((const char*)decompressed, decompressedSize);
// Not Tiano, try EFI 1.1 efiDecompressedData = QByteArray((const char*)efiDecompressed, decompressedSize);
if (ERR_SUCCESS != EfiDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) { }
delete[] decompressed; else if (TianoResult == ERR_SUCCESS) { // Only Tiano is OK
delete[] scratch; algorithm = COMPRESSION_ALGORITHM_TIANO;
return ERR_STANDARD_DECOMPRESSION_FAILED; decompressedData = QByteArray((const char*)decompressed, decompressedSize);
} }
else algorithm = COMPRESSION_ALGORITHM_EFI11; else if (EfiResult == ERR_SUCCESS) { // Only EFI 1.1 is OK
algorithm = COMPRESSION_ALGORITHM_EFI11;
decompressedData = QByteArray((const char*)efiDecompressed, decompressedSize);
}
else { // Both decompressions failed
result = ERR_STANDARD_DECOMPRESSION_FAILED;
} }
else algorithm = COMPRESSION_ALGORITHM_TIANO;
decompressedData = QByteArray((const char*)decompressed, decompressedSize); free(decompressed);
free(efiDecompressed);
delete[] decompressed; free(scratch);
delete[] scratch; return result;
return ERR_SUCCESS; }
case EFI_CUSTOMIZED_COMPRESSION: case EFI_CUSTOMIZED_COMPRESSION:
// Set default algorithm to unknown // Set default algorithm to unknown
algorithm = COMPRESSION_ALGORITHM_UNKNOWN; algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
@ -226,10 +238,8 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED; return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
// Allocate memory // Allocate memory
try { decompressed = (UINT8*)malloc(decompressedSize);
decompressed = new UINT8[decompressedSize]; if (!decompressed) {
}
catch (std::bad_alloc) {
return ERR_STANDARD_DECOMPRESSION_FAILED; return ERR_STANDARD_DECOMPRESSION_FAILED;
} }
@ -241,13 +251,13 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
// Get info again // Get info again
if (ERR_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) { if (ERR_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) {
delete[] decompressed; free(decompressed);
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED; return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
} }
// Decompress section data again // Decompress section data again
if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
delete[] decompressed; free(decompressed);
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED; return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
} }
else { else {
@ -260,7 +270,7 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
decompressedData = QByteArray((const char*)decompressed, decompressedSize); decompressedData = QByteArray((const char*)decompressed, decompressedSize);
} }
delete[] decompressed; free(decompressed);
return ERR_SUCCESS; return ERR_SUCCESS;
default: default:
algorithm = COMPRESSION_ALGORITHM_UNKNOWN; algorithm = COMPRESSION_ALGORITHM_UNKNOWN;

View file

@ -1,6 +1,6 @@
/* utility.h /* utility.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -29,7 +29,7 @@ QByteArray parsingDataToQByteArray(const PARSING_DATA & pdata);
extern QString errorCodeToQString(UINT8 errorCode); extern QString errorCodeToQString(UINT8 errorCode);
// Decompression routine // Decompression routine
extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByteArray & decompressed); extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByteArray & decompressed, QByteArray & efiDecompressed = QByteArray());
// Compression routine // Compression routine
//STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm); //STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);