From 4988ea8a9faa59e5693ec85bf08d4b6a382bfee4 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Fri, 19 Dec 2014 09:20:36 +0100 Subject: [PATCH] UEFIFind 0.1.0 - added UEFIFind utility to find a count or a list of FFS files with a specified pattern. The utility is developed for UBU Project. --- UEFIFind/uefifind.cpp | 146 +++++++++++++++++++++++++++++++++++++ UEFIFind/uefifind.h | 49 +++++++++++++ UEFIFind/uefifind.pro | 42 +++++++++++ UEFIFind/uefifind_main.cpp | 72 ++++++++++++++++++ ffsengine.cpp | 33 +++++---- 5 files changed, 328 insertions(+), 14 deletions(-) create mode 100644 UEFIFind/uefifind.cpp create mode 100644 UEFIFind/uefifind.h create mode 100644 UEFIFind/uefifind.pro create mode 100644 UEFIFind/uefifind_main.cpp diff --git a/UEFIFind/uefifind.cpp b/UEFIFind/uefifind.cpp new file mode 100644 index 0000000..f9663c9 --- /dev/null +++ b/UEFIFind/uefifind.cpp @@ -0,0 +1,146 @@ +/* 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; +} + +UINT8 UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result) +{ + QModelIndex root = model->index(0, 0); + QSet 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; + } + + QModelIndex index; + Q_FOREACH(index, files) { + QByteArray data = model->header(index).left(16); + + UINT32 u32 = *(UINT32*)data.constData(); + UINT16 u16_1 = *(UINT16*)(data.constData() + 4); + UINT16 u16_2 = *(UINT16*)(data.constData() + 6); + UINT8 u8_1 = *(UINT8*)(data.constData() + 8); + UINT8 u8_2 = *(UINT8*)(data.constData() + 9); + UINT8 u8_3 = *(UINT8*)(data.constData() + 10); + UINT8 u8_4 = *(UINT8*)(data.constData() + 11); + UINT8 u8_5 = *(UINT8*)(data.constData() + 12); + UINT8 u8_6 = *(UINT8*)(data.constData() + 13); + UINT8 u8_7 = *(UINT8*)(data.constData() + 14); + UINT8 u8_8 = *(UINT8*)(data.constData() + 15); + + QString guid = QString("%1-%2-%3-%4%5%6%7%8%9%10%11\n").hexarg(u32, 8).hexarg(u16_1, 4).hexarg(u16_2, 4).hexarg(u8_1, 2).hexarg(u8_2, 2) + .hexarg(u8_3, 2).hexarg(u8_4, 2).hexarg(u8_5, 2).hexarg(u8_6, 2).hexarg(u8_7, 2).hexarg(u8_8, 2); + + result.append(guid); + } + return ERR_SUCCESS; +} + +UINT8 UEFIFind::findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet & 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)).append(model->tail(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); + files.insert(ffs); + } + else + files.insert(index); + + break; + } + offset = regexp.indexIn(hexBody, offset + 1); + } + + return ERR_SUCCESS; +} \ No newline at end of file diff --git a/UEFIFind/uefifind.h b/UEFIFind/uefifind.h new file mode 100644 index 0000000..374b56d --- /dev/null +++ b/UEFIFind/uefifind.h @@ -0,0 +1,49 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include + +#include "../basetypes.h" +#include "../ffsengine.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 & files); + + FfsEngine* ffsEngine; + TreeModel* model; + QFileInfo fileInfo; + bool initDone; +}; + +#endif diff --git a/UEFIFind/uefifind.pro b/UEFIFind/uefifind.pro new file mode 100644 index 0000000..6f9f12f --- /dev/null +++ b/UEFIFind/uefifind.pro @@ -0,0 +1,42 @@ +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 \ + ../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 + diff --git a/UEFIFind/uefifind_main.cpp b/UEFIFind/uefifind_main.cpp new file mode 100644 index 0000000..bc353f2 --- /dev/null +++ b/UEFIFind/uefifind_main.cpp @@ -0,0 +1,72 @@ +/* uefifind_main.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 +#include +#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.1.0" << std::endl << std::endl << + "Usage: uefifind {header | body | all} {list | count} pattern imagefile\n"; + return ERR_INVALID_PARAMETER; + } +} + diff --git a/ffsengine.cpp b/ffsengine.cpp index 42bff44..3bbf606 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -194,12 +194,17 @@ TreeModel* FfsEngine::treeModel() const void FfsEngine::msg(const QString & message, const QModelIndex & index) { +#ifndef _DISABLE_ENGINE_MESSAGES #ifndef _CONSOLE messageItems.enqueue(MessageListItem(message, NULL, 0, index)); #else (void) index; std::cout << message.toLatin1().constData() << std::endl; #endif +#else + (void)message; + (void)index; +#endif } #ifndef _CONSOLE @@ -3271,10 +3276,14 @@ UINT8 FfsEngine::reconstructImageFile(QByteArray & reconstructed) // Search routines UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode) { + if (!index.isValid()) + return ERR_SUCCESS; + if (hexPattern.isEmpty()) return ERR_INVALID_PARAMETER; - if (!index.isValid()) + // Check for "all substrings" pattern + if (hexPattern.count('.') == hexPattern.length()) return ERR_SUCCESS; bool hasChildren = (model->rowCount(index) > 0); @@ -3289,17 +3298,13 @@ UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & he } else { if (mode == SEARCH_MODE_HEADER) - data.append(model->header(index)).append(model->tail(index)); + 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)).append(model->tail(index)); } - // Check for "all substrings" pattern - if (hexPattern.count('.') == hexPattern.length()) - return ERR_SUCCESS; - QString hexBody = QString(data.toHex()); QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive); INT32 offset = regexp.indexIn(hexBody); @@ -3339,7 +3344,7 @@ UINT8 FfsEngine::findGuidPattern(const QModelIndex & index, const QByteArray & g } else { if (mode == SEARCH_MODE_HEADER) - data.append(model->header(index)).append(model->tail(index)); + data.append(model->header(index)); else if (mode == SEARCH_MODE_BODY) data.append(model->body(index)); else @@ -3495,13 +3500,13 @@ UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) return ERR_SUCCESS; } - EFI_IMAGE_BASE_RELOCATION *RelocBase; - EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; - UINT16 *Reloc; - UINT16 *RelocEnd; - UINT16 *F16; - UINT32 *F32; - UINT64 *F64; + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + UINT16 *F16; + UINT32 *F32; + UINT64 *F64; // Run the whole relocation block RelocBase = (EFI_IMAGE_BASE_RELOCATION*)(file.data() + relocOffset - teFixup);