diff --git a/UEFIFind/uefifind.cpp b/UEFIFind/uefifind.cpp new file mode 100644 index 0000000..ca360bf --- /dev/null +++ b/UEFIFind/uefifind.cpp @@ -0,0 +1,160 @@ +/* uefifind.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 "uefifind.h" + +UEFIFind::UEFIFind(QObject *parent) : + QObject(parent) +{ + model = new TreeModel(); + ffsParser = new FfsParser(model, this); + initDone = false; +} + +UEFIFind::~UEFIFind() +{ + delete ffsParser; + delete model; + model = NULL; +} + +STATUS UEFIFind::init(const QString & path) +{ + STATUS 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 = ffsParser->parseImageFile(buffer, model->index(0,0)); + 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); +} + +STATUS UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result) +{ + QModelIndex root = model->index(0, 0); + QSet > files; + + result.clear(); + + STATUS 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 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; +} + +STATUS 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)); + } + + 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(ffs, index)); + else + files.insert(QPair(ffs, QModelIndex())); + } + else + files.insert(QPair(index, QModelIndex())); + + 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..bf50d57 --- /dev/null +++ b/UEFIFind/uefifind.h @@ -0,0 +1,52 @@ +/* uefifind.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. + +*/ + +#ifndef __UEFIFIND_H__ +#define __UEFIFIND_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/basetypes.h" +#include "../common/ffsparser.h" +#include "../common/ffs.h" + +class UEFIFind : public QObject +{ + Q_OBJECT + +public: + explicit UEFIFind(QObject *parent = 0); + ~UEFIFind(); + + STATUS init(const QString & path); + STATUS find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result); + +private: + STATUS findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet > & files); + QString guidToQString(const UINT8* guid); + + FfsParser* ffsParser; + TreeModel* model; + QFileInfo fileInfo; + bool initDone; +}; + +#endif diff --git a/UEFIFind/uefifind.pro b/UEFIFind/uefifind.pro new file mode 100644 index 0000000..53b1a07 --- /dev/null +++ b/UEFIFind/uefifind.pro @@ -0,0 +1,37 @@ +QT += core +QT -= gui + +TARGET = UEFIFind +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle + +SOURCES += uefifind_main.cpp \ + uefifind.cpp \ + ../common/types.cpp \ + ../common/descriptor.cpp \ + ../common/ffs.cpp \ + ../common/ffsparser.cpp \ + ../common/peimage.cpp \ + ../common/treeitem.cpp \ + ../common/treemodel.cpp \ + ../common/utility.cpp \ + ../common/LZMA/LzmaDecompress.c \ + ../common/LZMA/SDK/C/LzmaDec.c \ + ../common/Tiano/EfiTianoDecompress.c \ + +HEADERS += uefifind.h \ + ../common/basetypes.h \ + ../common/descriptor.h \ + ../common/gbe.h \ + ../common/me.h \ + ../common/ffs.h \ + ../common/ffsparser.h \ + ../common/peimage.h \ + ../common/types.h \ + ../common/treeitem.h \ + ../common/treemodel.h \ + ../common/utility.h \ + ../common/LZMA/LzmaDecompress.h \ + ../common/Tiano/EfiTianoDecompress.h + diff --git a/UEFIFind/uefifind_main.cpp b/UEFIFind/uefifind_main.cpp new file mode 100644 index 0000000..b739874 --- /dev/null +++ b/UEFIFind/uefifind_main.cpp @@ -0,0 +1,157 @@ +/* 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 +#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) { + // 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; + + // Parse input file + result = w.init(a.arguments().at(4)); + if (result) + return result; + + // Go find the supplied pattern + QString found; + result = w.find(mode, count, a.arguments().at(3), found); + if (result) + return result; + + // Nothing is found + if (found.isEmpty()) + return ERR_ITEM_NOT_FOUND; + + // Print result + std::cout << found.toStdString(); + return ERR_SUCCESS; + } + else if (a.arguments().length() == 4) { + // Get search mode + if (a.arguments().at(1) != QString("file")) + return ERR_INVALID_PARAMETER; + + // Open patterns file + QFileInfo fileInfo(a.arguments().at(2)); + if (!fileInfo.exists()) + return ERR_FILE_OPEN; + + QFile patternsFile; + patternsFile.setFileName(a.arguments().at(2)); + if (!patternsFile.open(QFile::ReadOnly)) + return ERR_FILE_OPEN; + + // Parse input file + result = w.init(a.arguments().at(3)); + if (result) + return result; + + // Perform searches + bool somethingFound = false; + while (!patternsFile.atEnd()) { + QByteArray line = patternsFile.readLine(); + // Use sharp symbol as commentary + if (line.count() == 0 || line[0] == '#') + continue; + + // Split the read line + QList list = line.split(' '); + if (list.count() < 3) { + std::cout << line.toStdString() << "skipped, too few arguments" << std::endl; + continue; + } + // Get search mode + UINT8 mode; + if (list.at(0) == QString("header")) + mode = SEARCH_MODE_HEADER; + else if (list.at(0) == QString("body")) + mode = SEARCH_MODE_BODY; + else if (list.at(0) == QString("all")) + mode = SEARCH_MODE_ALL; + else { + std::cout << line.toStdString() << "skipped, invalid search mode" << std::endl; + continue; + } + + // Get result type + bool count; + if (list.at(1) == QString("list")) + count = false; + else if (list.at(1) == QString("count")) + count = true; + else { + std::cout << line.toStdString() << "skipped, invalid result type" << std::endl; + continue; + } + + // Go find the supplied pattern + QString found; + result = w.find(mode, count, list.at(2), found); + if (result) { + std::cout << line.toStdString() << "skipped, find failed with error " << result << std::endl; + continue; + } + + if (found.isEmpty()) { + // Nothing is found + std::cout << line.toStdString() << "nothing found" << std::endl; + } + else { + // Print result + std::cout << line.toStdString() << found.toStdString() << std::endl; + somethingFound = true; + } + } + + // Nothing is found + if (!somethingFound) + return ERR_ITEM_NOT_FOUND; + + return ERR_SUCCESS; + } + else { + std::cout << "UEFIFind 0.10.0" << std::endl << std::endl << + "Usage: uefifind {header | body | all} {list | count} pattern imagefile" << std::endl << + " or uefitool file patternsfile imagefile" << std::endl; + return ERR_INVALID_PARAMETER; + } +} +