diff --git a/.gitignore b/.gitignore index c7191ed..910d521 100644 --- a/.gitignore +++ b/.gitignore @@ -233,4 +233,5 @@ Makefile UEFIExtract/UEFIExtract UEFIFind/UEFIFind UEFIPatch/UEFIPatch -UEFITool \ No newline at end of file +UEFIReplace/UEFIReplace +UEFITool diff --git a/UEFIReplace/uefireplace.cpp b/UEFIReplace/uefireplace.cpp new file mode 100644 index 0000000..f4ff1ea --- /dev/null +++ b/UEFIReplace/uefireplace.cpp @@ -0,0 +1,108 @@ +/* uefireplace.cpp + +Copyright (c) 2017, mxxxc. 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 "uefireplace.h" + +UEFIReplace::UEFIReplace(QObject *parent) : + QObject(parent) +{ + ffsEngine = new FfsEngine(this); + model = ffsEngine->treeModel(); +} + +UEFIReplace::~UEFIReplace() +{ + delete ffsEngine; +} + +UINT8 UEFIReplace::replace(QString inPath, const QByteArray & guid, const UINT8 sectionType, const QString contentPath) +{ + QFileInfo fileInfo = QFileInfo(inPath); + if (!fileInfo.exists()) + return ERR_FILE_OPEN; + + fileInfo = QFileInfo(contentPath); + if (!fileInfo.exists()) + return ERR_FILE_OPEN; + + QFile inputFile; + inputFile.setFileName(inPath); + + if (!inputFile.open(QFile::ReadOnly)) + return ERR_FILE_READ; + + QByteArray buffer = inputFile.readAll(); + inputFile.close(); + + UINT8 result = ffsEngine->parseImageFile(buffer); + if (result) + return result; + + QFile contentFile; + contentFile.setFileName(contentPath); + + if (!contentFile.open(QFile::ReadOnly)) + return ERR_FILE_READ; + + QByteArray contents = contentFile.readAll(); + contentFile.close(); + + result = replaceInFile(model->index(0, 0), guid, sectionType, contents); + if (result) + return result; + + QByteArray reconstructed; + result = ffsEngine->reconstructImageFile(reconstructed); + if (result) + return result; + if (reconstructed == buffer) + return ERR_NOTHING_TO_PATCH; + + QFile outputFile; + outputFile.setFileName(inPath.append(".patched")); + if (!outputFile.open(QFile::WriteOnly)) + return ERR_FILE_WRITE; + + outputFile.resize(0); + outputFile.write(reconstructed); + outputFile.close(); + + return ERR_SUCCESS; +} + +UINT8 UEFIReplace::replaceInFile(const QModelIndex & index, const QByteArray & guid, const UINT8 sectionType, const QByteArray & newData) +{ + if (!model || !index.isValid()) + return ERR_INVALID_PARAMETER; + if (model->subtype(index) == sectionType) { + QModelIndex fileIndex = model->findParentOfType(index, Types::File); + QByteArray fileGuid = model->header(fileIndex).left(sizeof(EFI_GUID)); + if (fileGuid == guid) { + return ffsEngine->replace(index, newData, REPLACE_MODE_BODY); + } + } + + bool patched = false; + if (model->rowCount(index) > 0) { + for (int i = 0; i < model->rowCount(index); i++) { + UINT8 result = replaceInFile(index.child(i, 0), guid, sectionType, newData); + if (!result) { + patched = true; + break; + } else if (result != ERR_NOTHING_TO_PATCH) + return result; + } + } + + return patched ? ERR_SUCCESS : ERR_NOTHING_TO_PATCH; +} diff --git a/UEFIReplace/uefireplace.h b/UEFIReplace/uefireplace.h new file mode 100644 index 0000000..682a1f6 --- /dev/null +++ b/UEFIReplace/uefireplace.h @@ -0,0 +1,41 @@ +/* uefireplace.h +Copyright (c) 2017, mxxxc. 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 __UEFIREPLACE_H__ +#define __UEFIREPLACE_H__ + +#include +#include +#include +#include +#include +#include + +#include "../basetypes.h" +#include "../ffs.h" +#include "../ffsengine.h" + +class UEFIReplace : public QObject +{ + Q_OBJECT + +public: + explicit UEFIReplace(QObject *parent = 0); + ~UEFIReplace(); + + UINT8 replace(const QString inPath, const QByteArray & guid, const UINT8 sectionType, const QString contentPath); + +private: + UINT8 replaceInFile(const QModelIndex & index, const QByteArray & guid, const UINT8 sectionType, const QByteArray & contents); + FfsEngine* ffsEngine; + TreeModel* model; +}; + +#endif diff --git a/UEFIReplace/uefireplace.pro b/UEFIReplace/uefireplace.pro new file mode 100644 index 0000000..e3d853d --- /dev/null +++ b/UEFIReplace/uefireplace.pro @@ -0,0 +1,42 @@ +QT += core +QT -= gui + +TARGET = UEFIReplace +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +DEFINES += _CONSOLE + +SOURCES += uefireplace_main.cpp \ + uefireplace.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 += uefireplace.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/UEFIReplace/uefireplace_main.cpp b/UEFIReplace/uefireplace_main.cpp new file mode 100644 index 0000000..562db22 --- /dev/null +++ b/UEFIReplace/uefireplace_main.cpp @@ -0,0 +1,78 @@ +/* uefireplace_main.cpp + +Copyright (c) 2017, mxxxc. 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 +#include +#include "uefireplace.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + a.setOrganizationName("CodeRush"); + a.setOrganizationDomain("coderush.me"); + a.setApplicationName("UEFIReplace"); + + UEFIReplace r; + UINT8 result = ERR_SUCCESS; + QStringList args = a.arguments(); + + if (args.length() < 5) { + std::cout << "UEFIReplace 0.3.9 - UEFI image file replacement utility" << std::endl << std::endl << + "Usage: UEFIReplace image_file guid section_type contents_file" << std::endl; + return ERR_SUCCESS; + } + + QUuid uuid = QUuid(args.at(2)); + QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID)); + bool converted; + UINT8 sectionType = (UINT8)args.at(3).toUShort(&converted, 16); + if (!converted) + result = ERR_INVALID_PARAMETER; + else + result = r.replace(args.at(1), guid, sectionType, args.at(4)); + + switch (result) { + case ERR_SUCCESS: + std::cout << "File replaced" << std::endl; + break; + case ERR_INVALID_PARAMETER: + std::cout << "Function called with invalid parameter" << std::endl; + break; + case ERR_INVALID_FILE: + std::cout << "Invalid/corrupted file specified" << std::endl; + break; + case ERR_INVALID_SECTION: + std::cout << "Invalid/corrupted section specified" << std::endl; + break; + case ERR_NOTHING_TO_PATCH: + std::cout << "No replacements can be applied to input file" << std::endl; + break; + case ERR_NOT_IMPLEMENTED: + std::cout << "Can't replace body of this section type" << 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; +}