First commit of the new_engine branch

- new ffsParser is done, supports FFSv3, non-UEFI data everywhere, fixed
files, offsets for uncompressed data and many other things
- command-line utilities are removed until the end of new engine's
development
This commit is contained in:
Nikolaj Schlej 2015-03-13 07:48:53 +01:00
parent 29a41e880c
commit 1f0a80d035
31 changed files with 3121 additions and 5444 deletions

View File

@ -1,49 +0,0 @@
/* uefiextract.cpp
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "uefiextract.h"
UEFIExtract::UEFIExtract(QObject *parent) :
QObject(parent)
{
ffsEngine = new FfsEngine(this);
}
UEFIExtract::~UEFIExtract()
{
delete ffsEngine;
}
UINT8 UEFIExtract::init(const QString & path)
{
fileInfo = QFileInfo(path);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly))
return ERR_FILE_OPEN;
QByteArray buffer = inputFile.readAll();
inputFile.close();
return ffsEngine->parseImageFile(buffer);
}
UINT8 UEFIExtract::extract(QString guid)
{
return ffsEngine->dump(ffsEngine->treeModel()->index(0, 0), fileInfo.fileName().append(".dump"), guid);
}

View File

@ -1,43 +0,0 @@
/* uefiextract.h
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __UEFIEXTRACT_H__
#define __UEFIEXTRACT_H__
#include <QObject>
#include <QByteArray>
#include <QString>
#include <QDir>
#include <QFileInfo>
#include "../basetypes.h"
#include "../ffsengine.h"
class UEFIExtract : public QObject
{
Q_OBJECT
public:
explicit UEFIExtract(QObject *parent = 0);
~UEFIExtract();
UINT8 init(const QString & path);
UINT8 extract(QString guid = QString());
private:
FfsEngine* ffsEngine;
QFileInfo fileInfo;
};
#endif

View File

@ -1,43 +0,0 @@
QT += core
QT -= gui
TARGET = UEFIExtract
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
DEFINES += _CONSOLE
SOURCES += uefiextract_main.cpp \
uefiextract.cpp \
../types.cpp \
../descriptor.cpp \
../ffs.cpp \
../ffsengine.cpp \
../peimage.cpp \
../treeitem.cpp \
../treemodel.cpp \
../LZMA/LzmaCompress.c \
../LZMA/LzmaDecompress.c \
../LZMA/SDK/C/LzFind.c \
../LZMA/SDK/C/LzmaDec.c \
../LZMA/SDK/C/LzmaEnc.c \
../Tiano/EfiTianoDecompress.c \
../Tiano/EfiTianoCompress.c \
../Tiano/EfiTianoCompressLegacy.c
HEADERS += uefiextract.h \
../basetypes.h \
../descriptor.h \
../gbe.h \
../me.h \
../ffs.h \
../peimage.h \
../types.h \
../ffsengine.h \
../treeitem.h \
../treemodel.h \
../LZMA/LzmaCompress.h \
../LZMA/LzmaDecompress.h \
../Tiano/EfiTianoDecompress.h \
../Tiano/EfiTianoCompress.h

View File

@ -1,60 +0,0 @@
/* uefiextract_main.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <iostream>
#include "uefiextract.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIExtract");
UEFIExtract w;
UINT8 result = ERR_SUCCESS;
UINT32 returned = 0;
if (a.arguments().length() > 32) {
std::cout << "Too many arguments" << std::endl;
return 1;
}
if (a.arguments().length() > 1 ) {
if (w.init(a.arguments().at(1)))
return 1;
if (a.arguments().length() == 2) {
result = w.extract();
if (result)
return 2;
}
else {
for (int i = 2; i < a.arguments().length(); i++) {
result = w.extract(a.arguments().at(i));
if (result)
returned |= (1 << (i - 1));
}
return returned;
}
}
else {
std::cout << "UEFIExtract 0.4.4" << std::endl << std::endl <<
"Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl <<
"Returned value is a bit mask where 0 on position N meant File with GUID_N was found and unpacked, 1 otherwise" << std::endl;
return 1;
}
}

View File

@ -1,160 +0,0 @@
/* uefifind.cpp
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "uefifind.h"
UEFIFind::UEFIFind(QObject *parent) :
QObject(parent)
{
ffsEngine = new FfsEngine(this);
model = ffsEngine->treeModel();
initDone = false;
}
UEFIFind::~UEFIFind()
{
model = NULL;
delete ffsEngine;
}
UINT8 UEFIFind::init(const QString & path)
{
UINT8 result;
fileInfo = QFileInfo(path);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly))
return ERR_FILE_OPEN;
QByteArray buffer = inputFile.readAll();
inputFile.close();
result = ffsEngine->parseImageFile(buffer);
if (result)
return result;
initDone = true;
return ERR_SUCCESS;
}
QString UEFIFind::guidToQString(const UINT8* guid)
{
const UINT32 u32 = *(const UINT32*)guid;
const UINT16 u16_1 = *(const UINT16*)(guid + 4);
const UINT16 u16_2 = *(const UINT16*)(guid + 6);
const UINT8 u8_1 = *(const UINT8*)(guid + 8);
const UINT8 u8_2 = *(const UINT8*)(guid + 9);
const UINT8 u8_3 = *(const UINT8*)(guid + 10);
const UINT8 u8_4 = *(const UINT8*)(guid + 11);
const UINT8 u8_5 = *(const UINT8*)(guid + 12);
const UINT8 u8_6 = *(const UINT8*)(guid + 13);
const UINT8 u8_7 = *(const UINT8*)(guid + 14);
const UINT8 u8_8 = *(const UINT8*)(guid + 15);
return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11").hexarg2(u32, 8).hexarg2(u16_1, 4).hexarg2(u16_2, 4).hexarg2(u8_1, 2).hexarg2(u8_2, 2)
.hexarg2(u8_3, 2).hexarg2(u8_4, 2).hexarg2(u8_5, 2).hexarg2(u8_6, 2).hexarg2(u8_7, 2).hexarg2(u8_8, 2);
}
UINT8 UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result)
{
QModelIndex root = model->index(0, 0);
QSet<QPair<QModelIndex, QModelIndex> > files;
result.clear();
UINT8 returned = findFileRecursive(root, hexPattern, mode, files);
if (returned)
return returned;
if (count) {
if (files.count())
result.append(QString("%1\n").arg(files.count()));
return ERR_SUCCESS;
}
QPair<QModelIndex, QModelIndex> indexes;
Q_FOREACH(indexes, files) {
QByteArray data = model->header(indexes.first).left(16);
result.append(guidToQString((const UINT8*)data.constData()));
// Special case of freeform subtype GUID files
if (indexes.second.isValid() && model->subtype(indexes.second) == EFI_SECTION_FREEFORM_SUBTYPE_GUID) {
data = model->header(indexes.second).left(sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
result.append(" ").append(guidToQString((const UINT8*)data.constData() + sizeof(EFI_COMMON_SECTION_HEADER)));
}
result.append("\n");
}
return ERR_SUCCESS;
}
UINT8 UEFIFind::findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet<QPair<QModelIndex, QModelIndex> > & files)
{
if (!index.isValid())
return ERR_SUCCESS;
if (hexPattern.isEmpty())
return ERR_INVALID_PARAMETER;
// Check for "all substrings" pattern
if (hexPattern.count('.') == hexPattern.length())
return ERR_SUCCESS;
bool hasChildren = (model->rowCount(index) > 0);
for (int i = 0; i < model->rowCount(index); i++) {
findFileRecursive(index.child(i, index.column()), hexPattern, mode, files);
}
QByteArray data;
if (hasChildren) {
if (mode == SEARCH_MODE_HEADER || mode == SEARCH_MODE_ALL)
data.append(model->header(index));
}
else {
if (mode == SEARCH_MODE_HEADER)
data.append(model->header(index));
else if (mode == SEARCH_MODE_BODY)
data.append(model->body(index));
else
data.append(model->header(index)).append(model->body(index));
}
QString hexBody = QString(data.toHex());
QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive);
INT32 offset = regexp.indexIn(hexBody);
while (offset >= 0) {
if (offset % 2 == 0) {
if (model->type(index) != Types::File) {
QModelIndex ffs = model->findParentOfType(index, Types::File);
if (model->type(index) == Types::Section && model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID)
files.insert(QPair<QModelIndex, QModelIndex>(ffs, index));
else
files.insert(QPair<QModelIndex, QModelIndex>(ffs, QModelIndex()));
}
else
files.insert(QPair<QModelIndex, QModelIndex>(index, QModelIndex()));
break;
}
offset = regexp.indexIn(hexBody, offset + 1);
}
return ERR_SUCCESS;
}

View File

@ -1,52 +0,0 @@
/* uefifind.h
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __UEFIFIND_H__
#define __UEFIFIND_H__
#include <QObject>
#include <QByteArray>
#include <QString>
#include <QDir>
#include <QFileInfo>
#include <QPair>
#include <QSet>
#include <QString>
#include <QUuid>
#include "../basetypes.h"
#include "../ffsengine.h"
#include "../ffs.h"
class UEFIFind : public QObject
{
Q_OBJECT
public:
explicit UEFIFind(QObject *parent = 0);
~UEFIFind();
UINT8 init(const QString & path);
UINT8 find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result);
private:
UINT8 findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet<QPair<QModelIndex, QModelIndex> > & files);
QString guidToQString(const UINT8* guid);
FfsEngine* ffsEngine;
TreeModel* model;
QFileInfo fileInfo;
bool initDone;
};
#endif

View File

@ -1,43 +0,0 @@
QT += core
QT -= gui
TARGET = UEFIFind
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
DEFINES += _CONSOLE _DISABLE_ENGINE_MESSAGES
SOURCES += uefifind_main.cpp \
uefifind.cpp \
../types.cpp \
../descriptor.cpp \
../ffs.cpp \
../ffsengine.cpp \
../peimage.cpp \
../treeitem.cpp \
../treemodel.cpp \
../LZMA/LzmaCompress.c \
../LZMA/LzmaDecompress.c \
../LZMA/SDK/C/LzFind.c \
../LZMA/SDK/C/LzmaDec.c \
../LZMA/SDK/C/LzmaEnc.c \
../Tiano/EfiTianoDecompress.c \
../Tiano/EfiTianoCompress.c \
../Tiano/EfiTianoCompressLegacy.c
HEADERS += uefifind.h \
../basetypes.h \
../descriptor.h \
../gbe.h \
../me.h \
../ffs.h \
../peimage.h \
../types.h \
../ffsengine.h \
../treeitem.h \
../treemodel.h \
../LZMA/LzmaCompress.h \
../LZMA/LzmaDecompress.h \
../Tiano/EfiTianoDecompress.h \
../Tiano/EfiTianoCompress.h

View File

@ -1,72 +0,0 @@
/* uefifind_main.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <QCoreApplication>
#include <iostream>
#include "uefifind.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIFind");
UEFIFind w;
UINT8 result;
if (a.arguments().length() == 5) {
result = w.init(a.arguments().at(4));
if (result)
return result;
// Get search mode
UINT8 mode;
if (a.arguments().at(1) == QString("header"))
mode = SEARCH_MODE_HEADER;
else if (a.arguments().at(1) == QString("body"))
mode = SEARCH_MODE_BODY;
else if (a.arguments().at(1) == QString("all"))
mode = SEARCH_MODE_ALL;
else
return ERR_INVALID_PARAMETER;
// Get result type
bool count;
if (a.arguments().at(2) == QString("list"))
count = false;
else if (a.arguments().at(2) == QString("count"))
count = true;
else
return ERR_INVALID_PARAMETER;
// Go find the supplied pattern
QString found;
result = w.find(mode, count, a.arguments().at(3), found);
if (result)
return result;
// Nothing was found
if (found.isEmpty())
return ERR_ITEM_NOT_FOUND;
// Print result
std::cout << found.toStdString();
return ERR_SUCCESS;
}
else {
std::cout << "UEFIFind 0.3.4" << std::endl << std::endl <<
"Usage: uefifind {header | body | all} {list | count} pattern imagefile\n";
return ERR_INVALID_PARAMETER;
}
}

View File

@ -1,42 +0,0 @@
# Patch string format
# FileGuid SectionType PatchType:FindPatternOrOffset:ReplacePattern
# Please ensure that the latest symbol in patch string is space
# Possible section types:
# PE32 image 10
# Position-independent code 11
# TE Image 12
# DXE Dependency 13
# Version information 14
# User interface string 15
# 16-bit code 16
# Guided freeform 18
# Raw data 19
# PEI Dependency 1B
# SMM Dependency 1C
# Please do not try another section types, it can make the resulting image broken
# Possible patch types:
# P - pattern-based, first parameter is a pattern to find, second - a pattern to replace
# O - offset-based, first parameter is hexadecimal offset, second - a pattern to replace
# Patterns can have . as "any possible value" symbol
#----------------------------------------------------------------------------------
# OSX CPU Power Management patches
# Remove lock from MSR 0xE2 register
#----------------------------------------------------------------------------------
# PowerMgmtDxe | Haswell
F7731B4C-58A2-4DF4-8980-5645D39ECE58 10 P:75080FBAE80F89442430:EB080FBAE80F89442430
# PowerMgmtDxe | Haswell-E
F7731B4C-58A2-4DF4-8980-5645D39ECE58 10 P:0FBA6C24380F:0FBA7424380F
# PowerManagement | Sandy Bridge with ME 8.xx, Ivy Bridge
8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:75080FBAE80F89442430:EB080FBAE80F89442430
# PowerManagement | New SB-E/IB-E
8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:0FBA6C24380F:0FBA7424380F
# CpuPei | Sandy Bridge with ME 7.xx, old SB-E/IB-E
2BB5AFA9-FF33-417B-8497-CB773C2B93BF 10 P:800018EB050D0080:000018EB050D0000

View File

@ -1,149 +0,0 @@
/* uefipatch.cpp
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "uefipatch.h"
UEFIPatch::UEFIPatch(QObject *parent) :
QObject(parent)
{
ffsEngine = new FfsEngine(this);
model = ffsEngine->treeModel();
}
UEFIPatch::~UEFIPatch()
{
delete ffsEngine;
}
UINT8 UEFIPatch::patchFromFile(QString path)
{
QFileInfo patchInfo = QFileInfo("patches.txt");
if (!patchInfo.exists())
return ERR_INVALID_FILE;
QFile file;
file.setFileName("patches.txt");
if (!file.open(QFile::ReadOnly | QFile::Text))
return ERR_INVALID_FILE;
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly))
return ERR_FILE_READ;
QByteArray buffer = inputFile.readAll();
inputFile.close();
UINT8 result = ffsEngine->parseImageFile(buffer);
if (result)
return result;
UINT8 counter = 0;
while (!file.atEnd()) {
QByteArray line = file.readLine();
// Use sharp sign as commentary
if (line.count() == 0 || line[0] == '#')
continue;
QList<QByteArray> list = line.split(' ');
if (list.count() < 3)
continue;
QUuid uuid = QUuid(list.at(0));
QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID));
bool converted;
UINT8 sectionType = (UINT8)list.at(1).toUShort(&converted, 16);
if (!converted)
return ERR_INVALID_PARAMETER;
QVector<PatchData> patches;
for (int i = 2; i < list.count(); i++) {
QList<QByteArray> patchList = list.at(i).split(':');
PatchData patch;
patch.type = *(UINT8*)patchList.at(0).constData();
if (patch.type == PATCH_TYPE_PATTERN) {
patch.offset = 0xFFFFFFFF;
patch.hexFindPattern = patchList.at(1);
patch.hexReplacePattern = patchList.at(2);
patches.append(patch);
}
else if (patch.type == PATCH_TYPE_OFFSET) {
patch.offset = patchList.at(1).toUInt(NULL, 16);
patch.hexReplacePattern = patchList.at(2);
patches.append(patch);
}
else {
// Ignore unknown patch type
continue;
}
}
result = patchFile(model->index(0, 0), guid, sectionType, patches);
if (result && result != ERR_NOTHING_TO_PATCH)
return result;
counter++;
}
QByteArray reconstructed;
result = ffsEngine->reconstructImageFile(reconstructed);
if (result)
return result;
if (reconstructed == buffer)
return ERR_NOTHING_TO_PATCH;
QFile outputFile;
outputFile.setFileName(path.append(".patched"));
if (!outputFile.open(QFile::WriteOnly))
return ERR_FILE_WRITE;
outputFile.resize(0);
outputFile.write(reconstructed);
outputFile.close();
return ERR_SUCCESS;
}
UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches)
{
if (!model || !index.isValid())
return ERR_INVALID_PARAMETER;
if (model->type(index) == Types::Section && model->subtype(index) == sectionType) {
QModelIndex fileIndex = model->findParentOfType(index, Types::File);
if (model->type(fileIndex) == Types::File &&
model->header(fileIndex).left(sizeof(EFI_GUID)) == fileGuid)
{
return ffsEngine->patch(index, patches);
}
}
if (model->rowCount(index) > 0) {
for (int i = 0; i < model->rowCount(index); i++) {
UINT8 result = patchFile(index.child(i, 0), fileGuid, sectionType, patches);
if (!result)
break;
else if (result != ERR_NOTHING_TO_PATCH)
return result;
}
}
return ERR_NOTHING_TO_PATCH;
}

View File

@ -1,45 +0,0 @@
/* uefipatch.h
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __UEFIPATCH_H__
#define __UEFIPATCH_H__
#include <QObject>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QFileInfo>
#include <QUuid>
#include "../basetypes.h"
#include "../ffs.h"
#include "../ffsengine.h"
class UEFIPatch : public QObject
{
Q_OBJECT
public:
explicit UEFIPatch(QObject *parent = 0);
~UEFIPatch();
UINT8 patchFromFile(QString path);
UINT8 patch(QString path, QString fileGuid, QString findPattern, QString replacePattern);
private:
UINT8 patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches);
FfsEngine* ffsEngine;
TreeModel* model;
};
#endif

View File

@ -1,43 +0,0 @@
QT += core
QT -= gui
TARGET = UEFIPatch
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
DEFINES += _CONSOLE
SOURCES += uefipatch_main.cpp \
uefipatch.cpp \
../types.cpp \
../descriptor.cpp \
../ffs.cpp \
../ffsengine.cpp \
../peimage.cpp \
../treeitem.cpp \
../treemodel.cpp \
../LZMA/LzmaCompress.c \
../LZMA/LzmaDecompress.c \
../LZMA/SDK/C/LzFind.c \
../LZMA/SDK/C/LzmaDec.c \
../LZMA/SDK/C/LzmaEnc.c \
../Tiano/EfiTianoDecompress.c \
../Tiano/EfiTianoCompress.c \
../Tiano/EfiTianoCompressLegacy.c
HEADERS += uefipatch.h \
../basetypes.h \
../descriptor.h \
../gbe.h \
../me.h \
../ffs.h \
../peimage.h \
../types.h \
../ffsengine.h \
../treeitem.h \
../treemodel.h \
../LZMA/LzmaCompress.h \
../LZMA/LzmaDecompress.h \
../Tiano/EfiTianoDecompress.h \
../Tiano/EfiTianoCompress.h

View File

@ -1,76 +0,0 @@
/* uefipatch_main.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <iostream>
#include "uefipatch.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIPatch");
UEFIPatch w;
UINT8 result = ERR_SUCCESS;
UINT32 argumentsCount = a.arguments().length();
if (argumentsCount == 2) {
result = w.patchFromFile(a.arguments().at(1));
}
else {
std::cout << "UEFIPatch 0.3.4 - UEFI image file patching utility" << std::endl << std::endl <<
"Usage: UEFIPatch image_file" << std::endl << std::endl <<
"Patches will be read from patches.txt file\n";
return ERR_SUCCESS;
}
switch (result) {
case ERR_SUCCESS:
std::cout << "Image patched" << std::endl;
break;
case ERR_INVALID_PARAMETER:
std::cout << "Function called with invalid parameter" << std::endl;
break;
case ERR_NOTHING_TO_PATCH:
std::cout << "No patches can be applied to input file" << std::endl;
break;
case ERR_UNKNOWN_PATCH_TYPE:
std::cout << "Unknown patch type" << std::endl;
break;
case ERR_PATCH_OFFSET_OUT_OF_BOUNDS:
std::cout << "Patch offset out of bounds" << std::endl;
break;
case ERR_INVALID_SYMBOL:
std::cout << "Pattern format mismatch" << std::endl;
break;
case ERR_INVALID_FILE:
std::cout << "patches.txt file not found or can't be read" << std::endl;
break;
case ERR_FILE_OPEN:
std::cout << "Input file not found" << std::endl;
break;
case ERR_FILE_READ:
std::cout << "Input file can't be read" << std::endl;
break;
case ERR_FILE_WRITE:
std::cout << "Output file can't be written" << std::endl;
break;
default:
std::cout << "Error " << result << std::endl;
}
return result;
}

View File

@ -42,6 +42,7 @@ typedef unsigned int UINTN;
#define FALSE ((BOOLEAN)(0==1))
#endif
typedef UINT8 STATUS;
#define ERR_SUCCESS 0
#define ERR_INVALID_PARAMETER 1
#define ERR_BUFFER_TOO_SMALL 2
@ -68,7 +69,7 @@ typedef unsigned int UINTN;
#define ERR_CUSTOMIZED_COMPRESSION_FAILED 23
#define ERR_STANDARD_DECOMPRESSION_FAILED 24
#define ERR_CUSTOMIZED_DECOMPRESSION_FAILED 25
#define ERR_UNKNOWN_COMPRESSION_ALGORITHM 26
#define ERR_UNKNOWN_COMPRESSION_TYPE 26
#define ERR_UNKNOWN_EXTRACT_MODE 27
#define ERR_UNKNOWN_INSERT_MODE 28
#define ERR_UNKNOWN_IMAGE_TYPE 29

94
ffs.cpp
View File

@ -40,7 +40,7 @@ UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
while (bufferSize--)
counter += buffer[bufferSize];
return (UINT8)0x100 - counter;
return (UINT8)(0x100 - counter);
}
UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
@ -57,7 +57,7 @@ UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
counter = (UINT16)(counter + buffer[index]);
}
return (UINT16)0x10000 - counter;
return (UINT16)(0x10000 - counter);
}
VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
@ -69,38 +69,23 @@ VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
UINT32 uint24ToUint32(const UINT8* ffsSize)
{
return (ffsSize[2] << 16) +
(ffsSize[1] << 8) +
ffsSize[0];
return *(UINT32*)ffsSize & 0x00FFFFFF;
}
QString guidToQString(const EFI_GUID & guid)
{
QByteArray baGuid = QByteArray::fromRawData((const char*)guid.Data, sizeof(EFI_GUID));
const UINT32 i32 = *(const UINT32*)baGuid.left(4).constData();
const UINT16 i16_0 = *(const UINT16*)baGuid.mid(4, 2).constData();
const UINT16 i16_1 = *(const UINT16*)baGuid.mid(6, 2).constData();
const UINT8 i8_0 = *(const UINT8*)baGuid.mid(8, 1).constData();
const UINT8 i8_1 = *(const UINT8*)baGuid.mid(9, 1).constData();
const UINT8 i8_2 = *(const UINT8*)baGuid.mid(10, 1).constData();
const UINT8 i8_3 = *(const UINT8*)baGuid.mid(11, 1).constData();
const UINT8 i8_4 = *(const UINT8*)baGuid.mid(12, 1).constData();
const UINT8 i8_5 = *(const UINT8*)baGuid.mid(13, 1).constData();
const UINT8 i8_6 = *(const UINT8*)baGuid.mid(14, 1).constData();
const UINT8 i8_7 = *(const UINT8*)baGuid.mid(15, 1).constData();
return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11")
.arg(i32, 8, 16, QChar('0'))
.arg(i16_0, 4, 16, QChar('0'))
.arg(i16_1, 4, 16, QChar('0'))
.arg(i8_0, 2, 16, QChar('0'))
.arg(i8_1, 2, 16, QChar('0'))
.arg(i8_2, 2, 16, QChar('0'))
.arg(i8_3, 2, 16, QChar('0'))
.arg(i8_4, 2, 16, QChar('0'))
.arg(i8_5, 2, 16, QChar('0'))
.arg(i8_6, 2, 16, QChar('0'))
.arg(i8_7, 2, 16, QChar('0')).toUpper();
.arg(*(const UINT32*)&guid.Data[0], 8, 16, QChar('0'))
.arg(*(const UINT16*)&guid.Data[4], 4, 16, QChar('0'))
.arg(*(const UINT16*)&guid.Data[6], 4, 16, QChar('0'))
.arg(guid.Data[8], 2, 16, QChar('0'))
.arg(guid.Data[9], 2, 16, QChar('0'))
.arg(guid.Data[10], 2, 16, QChar('0'))
.arg(guid.Data[11], 2, 16, QChar('0'))
.arg(guid.Data[12], 2, 16, QChar('0'))
.arg(guid.Data[13], 2, 16, QChar('0'))
.arg(guid.Data[14], 2, 16, QChar('0'))
.arg(guid.Data[15], 2, 16, QChar('0')).toUpper();
}
QString fileTypeToQString(const UINT8 type)
@ -137,7 +122,7 @@ QString sectionTypeToQString(const UINT8 type)
case EFI_SECTION_TE: return QObject::tr("TE image");
case EFI_SECTION_DXE_DEPEX: return QObject::tr("DXE dependency");
case EFI_SECTION_VERSION: return QObject::tr("Version");
case EFI_SECTION_USER_INTERFACE: return QObject::tr("User interface");
case EFI_SECTION_USER_INTERFACE: return QObject::tr("UI");
case EFI_SECTION_COMPATIBILITY16: return QObject::tr("16-bit image");
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return QObject::tr("Volume image");
case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return QObject::tr("Freeform subtype GUID");
@ -150,52 +135,3 @@ QString sectionTypeToQString(const UINT8 type)
}
}
UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header)
{
if (!header)
return 0;
bool extended = false;
/*if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) {
extended = true;
}*/
switch (header->Type)
{
case EFI_SECTION_GUID_DEFINED: {
if (!extended) {
const EFI_GUID_DEFINED_SECTION* gdsHeader = (const EFI_GUID_DEFINED_SECTION*)header;
if (QByteArray((const char*)&gdsHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) {
const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)(gdsHeader + 1);
return gdsHeader->DataOffset + certificateHeader->Length;
}
return gdsHeader->DataOffset;
}
else {
const EFI_GUID_DEFINED_SECTION2* gdsHeader = (const EFI_GUID_DEFINED_SECTION2*)header;
if (QByteArray((const char*)&gdsHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) {
const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)(gdsHeader + 1);
return gdsHeader->DataOffset + certificateHeader->Length;
}
return gdsHeader->DataOffset;
}
}
case EFI_SECTION_COMPRESSION: return extended ? sizeof(EFI_COMPRESSION_SECTION2) : sizeof(EFI_COMPRESSION_SECTION);
case EFI_SECTION_DISPOSABLE: return extended ? sizeof(EFI_DISPOSABLE_SECTION2) : sizeof(EFI_DISPOSABLE_SECTION);
case EFI_SECTION_PE32: return extended ? sizeof(EFI_PE32_SECTION2) : sizeof(EFI_PE32_SECTION);
case EFI_SECTION_PIC: return extended ? sizeof(EFI_PIC_SECTION2) : sizeof(EFI_PIC_SECTION);
case EFI_SECTION_TE: return extended ? sizeof(EFI_TE_SECTION2) : sizeof(EFI_TE_SECTION);
case EFI_SECTION_DXE_DEPEX: return extended ? sizeof(EFI_DXE_DEPEX_SECTION2) : sizeof(EFI_DXE_DEPEX_SECTION);
case EFI_SECTION_VERSION: return extended ? sizeof(EFI_VERSION_SECTION2) : sizeof(EFI_VERSION_SECTION);
case EFI_SECTION_USER_INTERFACE: return extended ? sizeof(EFI_USER_INTERFACE_SECTION2) : sizeof(EFI_USER_INTERFACE_SECTION);
case EFI_SECTION_COMPATIBILITY16: return extended ? sizeof(EFI_COMPATIBILITY16_SECTION2) : sizeof(EFI_COMPATIBILITY16_SECTION);
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return extended ? sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION2) : sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION);
case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return extended ? sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2) : sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION);
case EFI_SECTION_RAW: return extended ? sizeof(EFI_RAW_SECTION2) : sizeof(EFI_RAW_SECTION);
case EFI_SECTION_PEI_DEPEX: return extended ? sizeof(EFI_PEI_DEPEX_SECTION2) : sizeof(EFI_PEI_DEPEX_SECTION);
case EFI_SECTION_SMM_DEPEX: return extended ? sizeof(EFI_SMM_DEPEX_SECTION2) : sizeof(EFI_SMM_DEPEX_SECTION);
case INSYDE_SECTION_POSTCODE: return extended ? sizeof(POSTCODE_SECTION2) : sizeof(POSTCODE_SECTION);
case SCT_SECTION_POSTCODE: return extended ? sizeof(POSTCODE_SECTION2) : sizeof(POSTCODE_SECTION);
default: return extended ? sizeof(EFI_COMMON_SECTION_HEADER2) : sizeof(EFI_COMMON_SECTION_HEADER);
}
}

6
ffs.h
View File

@ -240,9 +240,6 @@ typedef struct _EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE {
//UINT8 Data[];
} EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE;
//!TODO: add proper NVRAM parsing
//const QByteArray EFI_FIRMWARE_VOLUME_NVRAM_SIGNATURE("$VSS", 4);
// Volume header 16bit checksum calculation routine
extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
@ -512,9 +509,6 @@ typedef EFI_COMMON_SECTION_HEADER2 EFI_FIRMWARE_VOLUME_IMAGE_SECTION2;
typedef EFI_COMMON_SECTION_HEADER EFI_USER_INTERFACE_SECTION;
typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2;
//Section routines
extern UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header);
//*****************************************************************************
// EFI Dependency Expression
//*****************************************************************************

File diff suppressed because it is too large Load Diff

View File

@ -1,153 +0,0 @@
/* ffsengine.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __FFSENGINE_H__
#define __FFSENGINE_H__
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QObject>
#include <QModelIndex>
#include <QByteArray>
#include <QQueue>
#include <QVector>
#include "basetypes.h"
#include "treemodel.h"
#include "peimage.h"
#ifndef _CONSOLE
#include "messagelistitem.h"
#endif
class TreeModel;
QString errorMessage(UINT8 errorCode);
struct PatchData {
UINT8 type;
UINT32 offset;
QByteArray hexFindPattern;
QByteArray hexReplacePattern;
};
class FfsEngine : public QObject
{
Q_OBJECT
public:
// Default constructor and destructor
FfsEngine(QObject *parent = 0);
~FfsEngine(void);
// Returns model for Qt view classes
TreeModel* treeModel() const;
#ifndef _CONSOLE
// Returns message items queue
QQueue<MessageListItem> messages() const;
// Clears message items queue
void clearMessages();
#endif
// Firmware image parsing
UINT8 parseImageFile(const QByteArray & buffer);
UINT8 parseIntelImage(const QByteArray & intelImage, QModelIndex & index, const QModelIndex & parent = QModelIndex());
UINT8 parseGbeRegion(const QByteArray & gbe, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex());
UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseSections(const QByteArray & body, const QModelIndex & parent = QModelIndex());
UINT8 parseSection(const QByteArray & section, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
// Compression routines
UINT8 decompress(const QByteArray & compressed, const UINT8 compressionType, QByteArray & decompressedData, UINT8 * algorithm = NULL);
UINT8 compress(const QByteArray & data, const UINT8 algorithm, QByteArray & compressedData);
// Construction routines
UINT8 reconstructImageFile(QByteArray &reconstructed);
UINT8 reconstruct(const QModelIndex &index, QByteArray & reconstructed);
UINT8 reconstructIntelImage(const QModelIndex& index, QByteArray & reconstructed);
UINT8 reconstructRegion(const QModelIndex& index, QByteArray & reconstructed);
UINT8 reconstructBios(const QModelIndex& index, QByteArray & reconstructed);
UINT8 reconstructVolume(const QModelIndex& index, QByteArray & reconstructed);
UINT8 reconstructFile(const QModelIndex& index, const UINT8 revision, const UINT8 erasePolarity, const UINT32 base, QByteArray& reconstructed);
UINT8 reconstructSection(const QModelIndex& index, const UINT32 base, QByteArray & reconstructed);
// Operations on tree items
UINT8 extract(const QModelIndex & index, QByteArray & extracted, const UINT8 mode);
UINT8 create(const QModelIndex & index, const UINT8 type, const QByteArray & header, const QByteArray & body, const UINT8 mode, const UINT8 action, const UINT8 algorithm = COMPRESSION_ALGORITHM_NONE);
UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 mode);
UINT8 replace(const QModelIndex & index, const QByteArray & object, const UINT8 mode);
UINT8 remove(const QModelIndex & index);
UINT8 rebuild(const QModelIndex & index);
UINT8 dump(const QModelIndex & index, const QString & path, const QString & filter = QString());
UINT8 patch(const QModelIndex & index, const QVector<PatchData> & patches);
// Search routines
UINT8 findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode);
UINT8 findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode);
UINT8 findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive);
private:
TreeModel *model;
// PEI Core entry point
UINT32 oldPeiCoreEntryPoint;
UINT32 newPeiCoreEntryPoint;
// Parsing helpers
UINT32 getPaddingType(const QByteArray & padding);
void parseAprioriRawSection(const QByteArray & body, QString & parsed);
UINT8 parseDepexSection(const QByteArray & body, QString & parsed);
UINT8 findNextVolume(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize);
UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize);
// Reconstruction helpers
UINT8 constructPadFile(const QByteArray &guid, const UINT32 size, const UINT8 revision, const UINT8 erasePolarity, QByteArray & pad);
UINT8 growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize);
// Rebase routines
UINT8 getBase(const QByteArray& file, UINT32& base);
UINT8 getEntryPoint(const QByteArray& file, UINT32 &entryPoint);
UINT8 rebase(QByteArray & executable, const UINT32 base);
void rebasePeiFiles(const QModelIndex & index);
// Patch routines
UINT8 patchVtf(QByteArray &vtf);
// Patch helpers
UINT8 patchViaOffset(QByteArray & data, const UINT32 offset, const QByteArray & hexReplacePattern);
UINT8 patchViaPattern(QByteArray & data, const QByteArray & hexFindPattern, const QByteArray & hexReplacePattern);
#ifndef _CONSOLE
QQueue<MessageListItem> messageItems;
#endif
// Message helper
void msg(const QString & message, const QModelIndex &index = QModelIndex());
// Internal operations
bool hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);
// Recursive dump
bool dumped;
UINT8 recursiveDump(const QModelIndex & index, const QString & path, const QString & filter);
};
#endif

2549
ffsparser.cpp Normal file

File diff suppressed because it is too large Load Diff

188
ffsparser.h Normal file
View File

@ -0,0 +1,188 @@
/* ffsparser.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef __FFSPARSER_H__
#define __FFSPARSER_H__
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QObject>
#include <QModelIndex>
#include <QByteArray>
#include <QQueue>
#include <QVector>
#include "basetypes.h"
#include "treemodel.h"
#include "utility.h"
#include "peimage.h"
#ifndef _CONSOLE
#include "messagelistitem.h"
#endif
class TreeModel;
//The whole parsing data is an information needed for each level of image reconstruction
//routines without the need of backward traversal
//typedef struct _CAPSULE_PARSING_DATA {
//} CAPSULE_PARSING_DATA;
//typedef struct _IMAGE_PARSING_DATA {
//} IMAGE_PARSING_DATA;
//typedef struct _PADDING_PARSING_DATA {
//} PADDING_PARSING_DATA;
typedef struct _VOLUME_PARSING_DATA {
EFI_GUID extendedHeaderGuid;
UINT32 alignment;
UINT8 revision;
BOOLEAN hasExtendedHeader;
BOOLEAN hasZeroVectorCRC32;
BOOLEAN isWeakAligned;
} VOLUME_PARSING_DATA;
//typedef struct _FREE_SPACE_PARSING_DATA {
//} FREE_SPACE_PARSING_DATA;
typedef struct _FILE_PARSING_DATA {
UINT16 tail;
BOOLEAN hasTail;
} FILE_PARSING_DATA;
typedef struct _COMPRESSED_SECTION_PARSING_DATA {
UINT32 uncompressedSize;
UINT8 compressionType;
UINT8 algorithm;
} COMPRESSED_SECTION_PARSING_DATA;
typedef struct _GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid;
UINT32 attributes;
} GUIDED_SECTION_PARSING_DATA;
typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid;
} FREEFORM_GUIDED_SECTION_PARSING_DATA;
typedef struct _SECTION_PARSING_DATA {
union {
COMPRESSED_SECTION_PARSING_DATA compressed;
GUIDED_SECTION_PARSING_DATA guidDefined;
FREEFORM_GUIDED_SECTION_PARSING_DATA freeformSubtypeGuid;
};
} SECTION_PARSING_DATA;
typedef struct _PARSING_DATA {
BOOLEAN fixed;
BOOLEAN isOnFlash;
UINT8 emptyByte;
UINT8 ffsVersion;
UINT32 offset;
UINT64 address;
union {
//CAPSULE_PARSING_DATA capsule;
//IMAGE_PARSING_DATA image;
//PADDING_PARSING_DATA padding;
VOLUME_PARSING_DATA volume;
//FREE_SPACE_PARSING_DATA freeSpace;
FILE_PARSING_DATA file;
SECTION_PARSING_DATA section;
};
} PARSING_DATA;
class FfsParser : public QObject
{
Q_OBJECT
public:
// Default constructor and destructor
FfsParser(QObject *parent = 0);
~FfsParser(void);
// Returns model for Qt view classes
TreeModel* treeModel() const;
#ifndef _CONSOLE
// Returns message items queue
QQueue<MessageListItem> messages() const;
// Clears message items queue
void clearMessages();
#endif
// Firmware image parsing
STATUS parseImageFile(const QByteArray & imageFile);
STATUS parseRawArea(const QByteArray & bios, const QModelIndex & index);
STATUS parseVolumeHeader(const QByteArray & volume, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseVolumeBody(const QModelIndex & index);
STATUS parseFileHeader(const QByteArray & file, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseFileBody(const QModelIndex & index);
STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseSectionBody(const QModelIndex & index);
// Search routines TODO: move to another class
STATUS findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode);
STATUS findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode);
STATUS findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive);
STATUS extract(const QModelIndex & index, QString & name, QByteArray & extracted, const UINT8 mode);
private:
TreeModel *model;
STATUS parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & index);
STATUS parseGbeRegion(const QByteArray & gbe, 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 parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePadFileBody(const QModelIndex & index);
STATUS parseSections(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);
STATUS parseGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseFreeformGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseVersionSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePostcodeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseCompressedSectionBody(const QModelIndex & index);
STATUS parseGuidedSectionBody(const QModelIndex & index);
STATUS parseVersionSectionBody(const QModelIndex & index);
STATUS parseDepexSectionBody(const QModelIndex & index);
STATUS parseUiSectionBody(const QModelIndex & index);
STATUS parseRawSectionBody(const QModelIndex & index);
UINT8 getPaddingType(const QByteArray & padding);
STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed);
STATUS findNextVolume(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
STATUS getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion);
UINT32 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion);
// Internal operations
BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
PARSING_DATA getParsingData(const QModelIndex & index = QModelIndex());
QByteArray convertParsingData(const PARSING_DATA & pdata);
#ifndef _CONSOLE
QQueue<MessageListItem> messageItems;
#endif
// Message helper
void msg(const QString & message, const QModelIndex &index = QModelIndex());
};
#endif

View File

@ -25,6 +25,6 @@ QString machineTypeToQString(UINT16 machineType)
case IMAGE_FILE_MACHINE_I386: return QObject::tr("x86");
case IMAGE_FILE_MACHINE_IA64: return QObject::tr("IA64");
case IMAGE_FILE_MACHINE_THUMB: return QObject::tr("Thumb");
default: return QObject::tr("Unknown %1").hexarg2(machineType, 4);
default: return QObject::tr("Unknown %1h").hexarg2(machineType, 4);
}
}

View File

@ -15,14 +15,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "treeitem.h"
#include "types.h"
TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT8 compression,
TreeItem::TreeItem(const UINT8 type, const UINT8 subtype,
const QString & name, const QString & text, const QString & info,
const QByteArray & header, const QByteArray & body, const QByteArray & parsingData,
TreeItem *parent) :
itemAction(Actions::NoAction),
itemType(type),
itemSubtype(subtype),
itemCompression(compression),
itemName(name),
itemText(text),
itemInfo(info),
@ -168,12 +167,6 @@ void TreeItem::setSubtype(const UINT8 subtype)
itemSubtype = subtype;
}
UINT8 TreeItem::compression() const
{
return itemCompression;
}
QByteArray TreeItem::header() const
{
return itemHeader;

View File

@ -24,8 +24,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
class TreeItem
{
public:
TreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE,
const QString &name = QString(), const QString &text = QString(), const QString &info = QString(),
TreeItem(const UINT8 type, const UINT8 subtype = 0, const QString &name = QString(), const QString &text = QString(), const QString &info = QString(),
const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & parsingData = QByteArray(),
TreeItem *parent = 0);
~TreeItem();
@ -74,14 +73,11 @@ public:
UINT8 action() const;
void setAction(const UINT8 action);
UINT8 compression() const;
private:
QList<TreeItem*> childItems;
UINT8 itemAction;
UINT8 itemType;
UINT8 itemSubtype;
UINT8 itemCompression;
QString itemName;
QString itemText;
QString itemInfo;

View File

@ -226,14 +226,6 @@ UINT8 TreeModel::action(const QModelIndex &index) const
return item->action();
}
UINT8 TreeModel::compression(const QModelIndex &index) const
{
if (!index.isValid())
return COMPRESSION_ALGORITHM_UNKNOWN;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->compression();
}
void TreeModel::setSubtype(const QModelIndex & index, const UINT8 subtype)
{
if (!index.isValid())
@ -274,6 +266,26 @@ void TreeModel::setText(const QModelIndex &index, const QString &data)
emit dataChanged(index, index);
}
void TreeModel::setInfo(const QModelIndex &index, const QString &data)
{
if (!index.isValid())
return;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->setInfo(data);
emit dataChanged(index, index);
}
void TreeModel::addInfo(const QModelIndex &index, const QString &data)
{
if (!index.isValid())
return;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->addInfo(data);
emit dataChanged(index, index);
}
void TreeModel::setAction(const QModelIndex &index, const UINT8 action)
{
if (!index.isValid())
@ -294,7 +306,7 @@ void TreeModel::setParsingData(const QModelIndex &index, const QByteArray &data)
emit dataChanged(this->index(0, 0), index);
}
QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT8 compression,
QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype,
const QString & name, const QString & text, const QString & info,
const QByteArray & header, const QByteArray & body, const QByteArray & parsingData,
const QModelIndex & parent, const UINT8 mode)
@ -318,7 +330,7 @@ QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT
}
}
TreeItem *newItem = new TreeItem(type, subtype, compression, name, text, info, header, body, parsingData, parentItem);
TreeItem *newItem = new TreeItem(type, subtype, name, text, info, header, body, parsingData, parentItem);
if (mode == CREATE_MODE_APPEND) {
emit layoutAboutToBeChanged();
parentItem->appendChild(newItem);

View File

@ -47,6 +47,8 @@ public:
void setSubtype(const QModelIndex &index, const UINT8 subtype);
void setName(const QModelIndex &index, const QString &name);
void setText(const QModelIndex &index, const QString &text);
void setInfo(const QModelIndex &index, const QString &info);
void addInfo(const QModelIndex &index, const QString &info);
void setParsingData(const QModelIndex &index, const QByteArray &data);
QString name(const QModelIndex &index) const;
@ -61,9 +63,8 @@ public:
QByteArray parsingData(const QModelIndex &index) const;
bool hasEmptyParsingData(const QModelIndex &index) const;
UINT8 action(const QModelIndex &index) const;
UINT8 compression(const QModelIndex &index) const;
QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE,
QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0,
const QString & name = QString(), const QString & text = QString(), const QString & info = QString(),
const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QByteArray & parsingData = QByteArray(),
const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);

21
types.h
View File

@ -85,25 +85,4 @@ extern QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype);
extern QString compressionTypeToQString(const UINT8 algorithm);
extern QString regionTypeToQString(const UINT8 type);
enum ParsingDataTypes {
UnknownParsingData,
VolumeParsingData,
FileParsingData
};
typedef union _PARSING_DATA_UNION {
struct _PARSING_DATA_UNION_VOLUME {
bool HasZeroVectorCRC;
} Volume;
struct _PARSING_DATA_UNION_FILE {
UINT32 Offset;
} File;
} PARSING_DATA_UNION;
typedef struct _PARSING_DATA {
UINT8 Type;
PARSING_DATA_UNION Data;
} PARSING_DATA;
#endif

View File

@ -17,14 +17,14 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("0.20.4"))
version(tr("0.30.0_alpha_parser_only"))
{
clipboard = QApplication::clipboard();
// Create UI
ui->setupUi(this);
searchDialog = new SearchDialog(this);
ffsEngine = NULL;
ffsParser = NULL;
// Set window title
this->setWindowTitle(tr("UEFITool %1").arg(version));
@ -79,7 +79,7 @@ version(tr("0.20.4"))
UEFITool::~UEFITool()
{
delete ui;
delete ffsEngine;
delete ffsParser;
delete searchDialog;
}
@ -104,10 +104,10 @@ void UEFITool::init()
ui->actionMessagesCopyAll->setDisabled(true);
// Make new ffsEngine
if (ffsEngine)
delete ffsEngine;
ffsEngine = new FfsEngine(this);
ui->structureTreeView->setModel(ffsEngine->treeModel());
if (ffsParser)
delete ffsParser;
ffsParser = new FfsParser(this);
ui->structureTreeView->setModel(ffsParser->treeModel());
// Connect
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
@ -121,9 +121,9 @@ void UEFITool::populateUi(const QModelIndex &current)
if (!current.isValid())
return;
TreeModel* model = ffsEngine->treeModel();
TreeModel* model = ffsParser->treeModel();
UINT8 type = model->type(current);
UINT8 subtype = model->subtype(current);
//UINT8 subtype = model->subtype(current);
// Set info text
ui->infoEdit->setPlainText(model->info(current));
@ -139,16 +139,16 @@ void UEFITool::populateUi(const QModelIndex &current)
// Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
ui->actionRebuild->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
//ui->actionRebuild->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionExtractBody->setDisabled(model->hasEmptyBody(current));
ui->actionRemove->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionInsertInto->setEnabled((type == Types::Volume && subtype != Subtypes::UnknownVolume) ||
(type == Types::File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD) ||
(type == Types::Section && (subtype == EFI_SECTION_COMPRESSION || subtype == EFI_SECTION_GUID_DEFINED || subtype == EFI_SECTION_DISPOSABLE)));
ui->actionInsertBefore->setEnabled(type == Types::File || type == Types::Section);
ui->actionInsertAfter->setEnabled(type == Types::File || type == Types::Section);
ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
//ui->actionRemove->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
//ui->actionInsertInto->setEnabled((type == Types::Volume && subtype != Subtypes::UnknownVolume) ||
// (type == Types::File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD) ||
// (type == Types::Section && (subtype == EFI_SECTION_COMPRESSION || subtype == EFI_SECTION_GUID_DEFINED || subtype == EFI_SECTION_DISPOSABLE)));
//ui->actionInsertBefore->setEnabled(type == Types::File || type == Types::Section);
//ui->actionInsertAfter->setEnabled(type == Types::File || type == Types::Section);
//ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::Volume || type == Types::File || type == Types::Section);
//ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionMessagesCopy->setEnabled(false);
}
@ -157,7 +157,7 @@ void UEFITool::search()
if (searchDialog->exec() != QDialog::Accepted)
return;
QModelIndex rootIndex = ffsEngine->treeModel()->index(0, 0);
QModelIndex rootIndex = ffsParser->treeModel()->index(0, 0);
int index = searchDialog->ui->tabWidget->currentIndex();
if (index == 0) { // Hex pattern
@ -172,7 +172,7 @@ void UEFITool::search()
mode = SEARCH_MODE_BODY;
else
mode = SEARCH_MODE_ALL;
ffsEngine->findHexPattern(rootIndex, pattern, mode);
ffsParser->findHexPattern(rootIndex, pattern, mode);
showMessages();
}
else if (index == 1) { // GUID
@ -188,7 +188,7 @@ void UEFITool::search()
mode = SEARCH_MODE_BODY;
else
mode = SEARCH_MODE_ALL;
ffsEngine->findGuidPattern(rootIndex, pattern, mode);
ffsParser->findGuidPattern(rootIndex, pattern, mode);
showMessages();
}
else if (index == 2) { // Text string
@ -196,7 +196,7 @@ void UEFITool::search()
QString pattern = searchDialog->ui->textEdit->text();
if (pattern.isEmpty())
return;
ffsEngine->findTextPattern(rootIndex, pattern, searchDialog->ui->textUnicodeCheckBox->isChecked(),
ffsParser->findTextPattern(rootIndex, pattern, searchDialog->ui->textUnicodeCheckBox->isChecked(),
(Qt::CaseSensitivity) searchDialog->ui->textCaseSensitiveCheckBox->isChecked());
showMessages();
}
@ -208,10 +208,10 @@ void UEFITool::rebuild()
if (!index.isValid())
return;
UINT8 result = ffsEngine->rebuild(index);
/*UINT8 result = ffsEngine->rebuild(index);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::remove()
@ -220,10 +220,10 @@ void UEFITool::remove()
if (!index.isValid())
return;
UINT8 result = ffsEngine->remove(index);
/*UINT8 result = ffsEngine->remove(index);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::insert(const UINT8 mode)
@ -232,7 +232,7 @@ void UEFITool::insert(const UINT8 mode)
if (!index.isValid())
return;
TreeModel* model = ffsEngine->treeModel();
TreeModel* model = ffsParser->treeModel();
UINT8 type;
if (mode == CREATE_MODE_BEFORE || mode == CREATE_MODE_AFTER)
@ -273,12 +273,12 @@ void UEFITool::insert(const UINT8 mode)
QByteArray buffer = inputFile.readAll();
inputFile.close();
UINT8 result = ffsEngine->insert(index, buffer, mode);
/*UINT8 result = ffsEngine->insert(index, buffer, mode);
if (result) {
QMessageBox::critical(this, tr("Insertion failed"), errorMessage(result), QMessageBox::Ok);
return;
}
ui->actionSaveImageFile->setEnabled(true);
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::insertInto()
@ -312,7 +312,7 @@ void UEFITool::replace(const UINT8 mode)
if (!index.isValid())
return;
TreeModel* model = ffsEngine->treeModel();
TreeModel* model = ffsParser->treeModel();
QString path;
if (model->type(index) == Types::Region) {
if (mode == REPLACE_MODE_AS_IS) {
@ -387,12 +387,12 @@ void UEFITool::replace(const UINT8 mode)
QByteArray buffer = inputFile.readAll();
inputFile.close();
UINT8 result = ffsEngine->replace(index, buffer, mode);
/*UINT8 result = ffsEngine->replace(index, buffer, mode);
if (result) {
QMessageBox::critical(this, tr("Replacing failed"), errorMessage(result), QMessageBox::Ok);
return;
}
ui->actionSaveImageFile->setEnabled(true);
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::extractAsIs()
@ -411,80 +411,83 @@ void UEFITool::extract(const UINT8 mode)
if (!index.isValid())
return;
TreeModel* model = ffsEngine->treeModel();
UINT8 type = model->type(index);
TreeModel* model = ffsParser->treeModel();
QByteArray extracted;
QString name;
UINT8 result = ffsParser->extract(index, name, extracted, mode);
if (result) {
QMessageBox::critical(this, tr("Extraction failed"), errorCodeToQString(result), QMessageBox::Ok);
return;
}
name = currentDir + QDir::separator() + name;
UINT8 type = model->type(index);
QString path;
if (mode == EXTRACT_MODE_AS_IS) {
switch (type) {
case Types::Capsule:
path = QFileDialog::getSaveFileName(this, tr("Save capsule to file"), currentDir, "Capsule files (*.cap *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save capsule to file"), name + ".cap", "Capsule files (*.cap *.bin);;All files (*)");
break;
case Types::Image:
path = QFileDialog::getSaveFileName(this, tr("Save image to file"), currentDir, "Image files (*.rom *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save image to file"), name + ".rom", "Image files (*.rom *.bin);;All files (*)");
break;
case Types::Region:
path = QFileDialog::getSaveFileName(this, tr("Save region to file"), currentDir, "Region files (*.rgn *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save region to file"), name + ".rgn", "Region files (*.rgn *.bin);;All files (*)");
break;
case Types::Padding:
path = QFileDialog::getSaveFileName(this, tr("Save padding to file"), currentDir, "Padding files (*.pad *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save padding to file"), name + ".pad", "Padding files (*.pad *.bin);;All files (*)");
break;
case Types::Volume:
path = QFileDialog::getSaveFileName(this, tr("Save volume to file"), currentDir, "Volume files (*.vol *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save volume to file"), name + ".vol", "Volume files (*.vol *.bin);;All files (*)");
break;
case Types::File:
path = QFileDialog::getSaveFileName(this, tr("Save FFS file to file"), currentDir, "FFS files (*.ffs *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save FFS file to file"), name + ".ffs", "FFS files (*.ffs *.bin);;All files (*)");
break;
case Types::Section:
path = QFileDialog::getSaveFileName(this, tr("Save section file to file"), currentDir, "Section files (*.sct *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save section file to file"), name + ".sct", "Section files (*.sct *.bin);;All files (*)");
break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), currentDir, "Binary files (*.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
}
else if (mode == EXTRACT_MODE_BODY) {
switch (type) {
case Types::Capsule:
path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), currentDir, "Image files (*.rom *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), name + ".rom", "Image files (*.rom *.bin);;All files (*)");
break;
case Types::Volume:
path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), currentDir, "Volume body files (*.vbd *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), name + ".vbd", "Volume body files (*.vbd *.bin);;All files (*)");
break;
case Types::File: {
if (model->subtype(index) == EFI_FV_FILETYPE_ALL || model->subtype(index) == EFI_FV_FILETYPE_RAW)
path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to raw file"), currentDir, "Raw files (*.raw *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to raw file"), name + ".raw", "Raw files (*.raw *.bin);;All files (*)");
else
path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to file"), currentDir, "FFS file body files (*.fbd *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to file"), name + ".fbd", "FFS file body files (*.fbd *.bin);;All files (*)");
}
break;
case Types::Section: {
if (model->subtype(index) == EFI_SECTION_COMPRESSION || model->subtype(index) == EFI_SECTION_GUID_DEFINED || model->subtype(index) == EFI_SECTION_DISPOSABLE)
path = QFileDialog::getSaveFileName(this, tr("Save encapsulation section body to FFS body file"), currentDir, "FFS file body files (*.fbd *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save encapsulation section body to FFS body file"), name + ".fbd", "FFS file body files (*.fbd *.bin);;All files (*)");
else if (model->subtype(index) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE)
path = QFileDialog::getSaveFileName(this, tr("Save section body to volume file"), currentDir, "Volume files (*.vol *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save section body to volume file"), name + ".vol", "Volume files (*.vol *.bin);;All files (*)");
else if (model->subtype(index) == EFI_SECTION_RAW)
path = QFileDialog::getSaveFileName(this, tr("Save section body to raw file"), currentDir, "Raw files (*.raw *.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save section body to raw file"), name + ".raw", "Raw files (*.raw *.bin);;All files (*)");
else
path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), currentDir, "Binary files (*.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), currentDir, "Binary files (*.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
}
else
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), currentDir, "Binary files (*.bin);;All files (*)");
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
if (path.trimmed().isEmpty())
return;
QByteArray extracted;
UINT8 result = ffsEngine->extract(index, extracted, mode);
if (result) {
QMessageBox::critical(this, tr("Extraction failed"), errorMessage(result), QMessageBox::Ok);
return;
}
QFile outputFile;
outputFile.setFileName(path);
if (!outputFile.open(QFile::WriteOnly)) {
@ -521,7 +524,7 @@ void UEFITool::exit()
void UEFITool::saveImageFile()
{
QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi *.dec);;All files (*)");
/*QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi *.dec);;All files (*)");
if (path.isEmpty())
return;
@ -547,7 +550,7 @@ void UEFITool::saveImageFile()
outputFile.close();
if (QMessageBox::information(this, tr("Image reconstruction successful"), tr("Open reconstructed file?"), QMessageBox::Yes, QMessageBox::No)
== QMessageBox::Yes)
openImageFile(path);
openImageFile(path);*/
}
void UEFITool::openImageFile()
@ -582,10 +585,10 @@ void UEFITool::openImageFile(QString path)
init();
this->setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName()));
UINT8 result = ffsEngine->parseImageFile(buffer);
UINT8 result = ffsParser->parseImageFile(buffer);
showMessages();
if (result)
QMessageBox::critical(this, tr("Image parsing failed"), errorMessage(result), QMessageBox::Ok);
QMessageBox::critical(this, tr("Image parsing failed"), errorCodeToQString(result), QMessageBox::Ok);
else
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
@ -621,7 +624,7 @@ void UEFITool::enableMessagesCopyActions(QListWidgetItem* item)
void UEFITool::clearMessages()
{
ffsEngine->clearMessages();
ffsParser->clearMessages();
messageItems.clear();
ui->messageListWidget->clear();
ui->actionMessagesCopy->setEnabled(false);
@ -643,10 +646,10 @@ void UEFITool::dropEvent(QDropEvent* event)
void UEFITool::showMessages()
{
ui->messageListWidget->clear();
if (!ffsEngine)
if (!ffsParser)
return;
messageItems = ffsEngine->messages();
messageItems = ffsParser->messages();
for (int i = 0; i < messageItems.count(); i++) {
ui->messageListWidget->addItem(new MessageListItem(messageItems.at(i)));
}
@ -680,7 +683,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
if (!index.isValid())
return;
TreeModel* model = ffsEngine->treeModel();
TreeModel* model = ffsParser->treeModel();
switch (model->type(index))
{
case Types::Capsule:

View File

@ -34,8 +34,9 @@
#include <QUrl>
#include "basetypes.h"
#include "utility.h"
#include "ffs.h"
#include "ffsengine.h"
#include "ffsparser.h"
#include "searchdialog.h"
namespace Ui {
@ -91,7 +92,7 @@ public:
private:
Ui::UEFITool* ui;
FfsEngine* ffsEngine;
FfsParser* ffsParser;
SearchDialog* searchDialog;
QClipboard* clipboard;
QString currentDir;

View File

@ -11,7 +11,8 @@ SOURCES += uefitool_main.cpp \
descriptor.cpp \
ffs.cpp \
peimage.cpp \
ffsengine.cpp \
utility.cpp \
ffsparser.cpp \
treeitem.cpp \
treemodel.cpp \
messagelistitem.cpp \
@ -34,7 +35,8 @@ HEADERS += uefitool.h \
ffs.h \
peimage.h \
types.h \
ffsengine.h \
utility.h \
ffsparser.h \
treeitem.h \
treemodel.h \
messagelistitem.h \

234
utility.cpp Normal file
View File

@ -0,0 +1,234 @@
/* utility.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <QObject>
#include "utility.h"
#include "ffs.h"
#include "Tiano/EfiTianoCompress.h"
#include "Tiano/EfiTianoDecompress.h"
#include "LZMA/LzmaCompress.h"
#include "LZMA/LzmaDecompress.h"
// Returns text representation of error code
QString errorCodeToQString(UINT8 errorCode)
{
switch (errorCode) {
case ERR_SUCCESS: return QObject::tr("Success");
case ERR_NOT_IMPLEMENTED: return QObject::tr("Not implemented");
case ERR_INVALID_PARAMETER: return QObject::tr("Function called with invalid parameter");
case ERR_BUFFER_TOO_SMALL: return QObject::tr("Buffer too small");
case ERR_OUT_OF_RESOURCES: return QObject::tr("Out of resources");
case ERR_OUT_OF_MEMORY: return QObject::tr("Out of memory");
case ERR_FILE_OPEN: return QObject::tr("File can't be opened");
case ERR_FILE_READ: return QObject::tr("File can't be read");
case ERR_FILE_WRITE: return QObject::tr("File can't be written");
case ERR_ITEM_NOT_FOUND: return QObject::tr("Item not found");
case ERR_UNKNOWN_ITEM_TYPE: return QObject::tr("Unknown item type");
case ERR_INVALID_FLASH_DESCRIPTOR: return QObject::tr("Invalid flash descriptor");
case ERR_INVALID_REGION: return QObject::tr("Invalid region");
case ERR_EMPTY_REGION: return QObject::tr("Empty region");
case ERR_BIOS_REGION_NOT_FOUND: return QObject::tr("BIOS region not found");
case ERR_VOLUMES_NOT_FOUND: return QObject::tr("UEFI volumes not found");
case ERR_INVALID_VOLUME: return QObject::tr("Invalid UEFI volume");
case ERR_VOLUME_REVISION_NOT_SUPPORTED: return QObject::tr("Volume revision not supported");
case ERR_VOLUME_GROW_FAILED: return QObject::tr("Volume grow failed");
case ERR_UNKNOWN_FFS: return QObject::tr("Unknown file system");
case ERR_INVALID_FILE: return QObject::tr("Invalid file");
case ERR_INVALID_SECTION: return QObject::tr("Invalid section");
case ERR_UNKNOWN_SECTION: return QObject::tr("Unknown section");
case ERR_STANDARD_COMPRESSION_FAILED: return QObject::tr("Standard compression failed");
case ERR_CUSTOMIZED_COMPRESSION_FAILED: return QObject::tr("Customized compression failed");
case ERR_STANDARD_DECOMPRESSION_FAILED: return QObject::tr("Standard decompression failed");
case ERR_CUSTOMIZED_DECOMPRESSION_FAILED: return QObject::tr("Customized compression failed");
case ERR_UNKNOWN_COMPRESSION_TYPE: return QObject::tr("Unknown compression type");
case ERR_UNKNOWN_EXTRACT_MODE: return QObject::tr("Unknown extract mode");
case ERR_UNKNOWN_INSERT_MODE: return QObject::tr("Unknown insert mode");
case ERR_UNKNOWN_IMAGE_TYPE: return QObject::tr("Unknown executable image type");
case ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE: return QObject::tr("Unknown PE optional header type");
case ERR_UNKNOWN_RELOCATION_TYPE: return QObject::tr("Unknown relocation type");
case ERR_GENERIC_CALL_NOT_SUPPORTED: return QObject::tr("Generic call not supported");
case ERR_VOLUME_BASE_NOT_FOUND: return QObject::tr("Volume base address not found");
case ERR_PEI_CORE_ENTRY_POINT_NOT_FOUND: return QObject::tr("PEI core entry point not found");
case ERR_COMPLEX_BLOCK_MAP: return QObject::tr("Block map structure too complex for correct analysis");
case ERR_DIR_ALREADY_EXIST: return QObject::tr("Directory already exists");
case ERR_DIR_CREATE: return QObject::tr("Directory can't be created");
case ERR_UNKNOWN_PATCH_TYPE: return QObject::tr("Unknown patch type");
case ERR_PATCH_OFFSET_OUT_OF_BOUNDS: return QObject::tr("Patch offset out of bounds");
case ERR_INVALID_SYMBOL: return QObject::tr("Invalid symbol");
case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
default: return QObject::tr("Unknown error %1").arg(errorCode);
}
}
// CRC32 implementation
UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
{
static const UINT32 crcTable[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,
0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,
0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,
0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,
0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,
0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,
0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
UINT32 crc32;
UINT32 i;
// Accumulate crc32 for buffer
crc32 = initial ^ 0xFFFFFFFF;
for (i = 0; i < length; i++) {
crc32 = (crc32 >> 8) ^ crcTable[(crc32 ^ buffer[i]) & 0xFF];
}
return(crc32 ^ 0xFFFFFFFF);
}
// Compression routines
STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArray & decompressedData)
{
const UINT8* data;
UINT32 dataSize;
UINT8* decompressed;
UINT32 decompressedSize = 0;
UINT8* scratch;
UINT32 scratchSize = 0;
const EFI_TIANO_HEADER* header;
switch (algorithm)
{
case EFI_NOT_COMPRESSED:
decompressedData = compressedData;
algorithm = COMPRESSION_ALGORITHM_NONE;
return ERR_SUCCESS;
case EFI_STANDARD_COMPRESSION:
// Set default algorithm to unknown
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
// Get buffer sizes
data = (UINT8*)compressedData.data();
dataSize = compressedData.size();
// Check header to be valid
header = (const EFI_TIANO_HEADER*)data;
if (header->CompSize + sizeof(EFI_TIANO_HEADER) != dataSize)
return ERR_STANDARD_DECOMPRESSION_FAILED;
// Get info function is the same for both algorithms
if (ERR_SUCCESS != EfiTianoGetInfo(data, dataSize, &decompressedSize, &scratchSize))
return ERR_STANDARD_DECOMPRESSION_FAILED;
// Allocate memory
decompressed = new UINT8[decompressedSize];
scratch = new UINT8[scratchSize];
// Decompress section data
//TODO: separate EFI1.1 from Tiano another way
// Try Tiano decompression first
if (ERR_SUCCESS != TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
// Not Tiano, try EFI 1.1
if (ERR_SUCCESS != EfiDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
delete[] decompressed;
delete[] scratch;
return ERR_STANDARD_DECOMPRESSION_FAILED;
}
else algorithm = COMPRESSION_ALGORITHM_EFI11;
}
else algorithm = COMPRESSION_ALGORITHM_TIANO;
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
delete[] decompressed;
delete[] scratch;
return ERR_SUCCESS;
case EFI_CUSTOMIZED_COMPRESSION:
// Set default algorithm to unknown
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
// Get buffer sizes
data = (const UINT8*)compressedData.constData();
dataSize = compressedData.size();
// Get info
if (ERR_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize))
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
// Allocate memory
decompressed = new UINT8[decompressedSize];
// Decompress section data
if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
//TODO: implement it again, if needed
// Intel modified LZMA workaround
// Decompress section data once again
data += sizeof(UINT32);
// Get info again
if (ERR_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) {
delete[] decompressed;
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
}
// Decompress section data again
if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
delete[] decompressed;
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
}
else {
algorithm = COMPRESSION_ALGORITHM_IMLZMA;
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
}
}
else {
algorithm = COMPRESSION_ALGORITHM_LZMA;
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
}
delete[] decompressed;
return ERR_SUCCESS;
default:
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
return ERR_UNKNOWN_COMPRESSION_TYPE;
}
}

26
utility.h Normal file
View File

@ -0,0 +1,26 @@
/* utility.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <QString>
#include "basetypes.h"
// Converts error code to QString
extern QString errorCodeToQString(UINT8 errorCode);
// Decompression routine
extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByteArray & decompressed);
// Compression routine
//STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);
// CRC32
extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);