Partially port UEFIPatch without backing engine ::patch support

This commit is contained in:
vit9696 2018-09-01 11:15:03 +03:00
parent d61d789569
commit 3699a7cebc
8 changed files with 467 additions and 0 deletions

1
.gitignore vendored
View file

@ -241,6 +241,7 @@ UEFIDump/UEFIDump
UEFIExtract/UEFIExtract
UEFIFind/UEFIFind
UEFIReplace/UEFIReplace
UEFIPatch/UEFIPatch
.qmake.stash
CMakeCache.txt
CMakeFiles

69
UEFIPatch/CMakeLists.txt Normal file
View file

@ -0,0 +1,69 @@
cmake_minimum_required(VERSION 3.0)
PROJECT(UEFIPatch)
SET(PROJECT_SOURCES
uefipatch_main.cpp
uefipatch.cpp
../common/guiddatabase.cpp
../common/types.cpp
../common/descriptor.cpp
../common/ffs.cpp
../common/nvram.cpp
../common/nvramparser.cpp
../common/ffsparser.cpp
../common/ffsbuilder.cpp
../common/ffsops.cpp
../common/peimage.cpp
../common/treeitem.cpp
../common/treemodel.cpp
../common/utility.cpp
../common/LZMA/LzmaCompress.c
../common/LZMA/LzmaDecompress.c
../common/LZMA/SDK/C/LzFind.c
../common/LZMA/SDK/C/LzmaDec.c
../common/LZMA/SDK/C/LzmaEnc.c
../common/Tiano/EfiTianoDecompress.c
../common/Tiano/EfiTianoCompress.c
../common/Tiano/EfiTianoCompressLegacy.c
../common/ustring.cpp
../common/sha256.c
../common/bstrlib/bstrlib.c
../common/bstrlib/bstrwrap.cpp
)
SET(PROJECT_HEADERS
uefipatch.h
../common/guiddatabase.h
../common/basetypes.h
../common/descriptor.h
../common/gbe.h
../common/me.h
../common/ffs.h
../common/nvram.h
../common/nvramparser.h
../common/ffsparser.h
../common/ffsbuilder.h
../common/ffsops.h
../common/peimage.h
../common/types.h
../common/treeitem.h
../common/treemodel.h
../common/utility.h
../common/LZMA/LzmaDecompress.h
../common/Tiano/EfiTianoDecompress.h
../common/LZMA/LzmaCompress.h
../common/Tiano/EfiTianoCompress.h
../common/ubytearray.h
../common/ustring.h
../common/bootguard.h
../common/sha256.h
../common/filesystem.h
../common/bstrlib/bstrlib.h
../common/bstrlib/bstrwrap.h
../version.h
)
ADD_DEFINITIONS(-DU_ENABLE_NVRAM_PARSING_SUPPORT -DU_ENABLE_FIT_PARSING_SUPPORT -DU_ENABLE_GUID_DATABASE_SUPPORT)
ADD_EXECUTABLE(UEFIPatch ${PROJECT_SOURCES} ${PROJECT_HEADERS})

37
UEFIPatch/patches-misc.txt Executable file
View file

@ -0,0 +1,37 @@
# 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
#----------------------------------------------------------------------------------
# Set IA32_FEATURE_CONTROL.SGX_LC
#----------------------------------------------------------------------------------
# SiInit | Gemini Lake
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:B93A0000000F320D00000400:B93A0000000F320D00000600
#----------------------------------------------------------------------------------
# Broken EFI_SIMPLE_POINTER_PROTOCOL implementation patches
# Fixes incorrect pointer position update/click condition on Z87 chips
#----------------------------------------------------------------------------------
# UHCD | ASUS Z87-Pro
580DD900-385D-11D7-883A-00500473D4EB 10 P:807A3200745C807A4000:807A32007506807A4000

59
UEFIPatch/patches.txt Executable file
View file

@ -0,0 +1,59 @@
# 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
# PpmInitialize | Broadwell-E
3FFCAE95-23CF-4967-94F5-16352F68E43B 10 P:0FBA6C24400F:0FBA7424400F
# SiInit | Skylake
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:75080D00800000:EB080D00800000
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:75080D00800000:EB080D00800000
# SiInit | Kaby Lake
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:81E10080000033C1:9090909090909090
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:81E10080000033C1:9090909090909090
# PpmInitialize | Skylake-X
3FFCAE95-23CF-4967-94F5-16352F68E43B 10 P:742CB9E2000000:752CB9E2000000
# CpuInitPei | Skylake-X
01359D99-9446-456D-ADA4-50A711C03ADA 12 P:BE0080000023CE0B:BE0000000023CE0B

156
UEFIPatch/uefipatch.cpp Executable file
View file

@ -0,0 +1,156 @@
/* uefipatch.cpp
Copyright (c) 2018, LongSoft. 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()
{
model = new TreeModel();
ffsParser = new FfsParser(model);
ffsBuilder = new FfsBuilder(model, ffsParser);
ffsOps = new FfsOperations(model);
}
UEFIPatch::~UEFIPatch()
{
delete ffsOps;
delete ffsBuilder;
delete ffsParser;
delete model;
}
USTATUS UEFIPatch::patchFromFile(const UString & inPath, const UString & patches, const UString & outPath)
{
if (!isExistOnFs(patches))
return U_INVALID_FILE;
std::ifstream patchesFile(patches.toLocal8Bit());
if (!patchesFile)
return U_INVALID_FILE;
UByteArray buffer;
USTATUS result = readFileIntoArray(inPath, buffer);
if (result)
return result;
result = ffsParser->parse(buffer);
if (result)
return result;
UINT8 counter = 0;
while (!patchesFile.eof()) {
std::string line;
std::getline(patchesFile, line);
// Use sharp symbol as commentary
if (line.size() == 0 || line[0] == '#')
continue;
// Split the read line
std::vector<UString> list;
std::string::size_type prev = 0, curr = 0;
while ((curr = line.find(' ', curr)) != std::string::npos) {
std::string substring( line.substr(prev, curr-prev) );
list.push_back(UString(substring.c_str()));
prev = ++curr;
}
list.push_back(UString(line.substr(prev, curr-prev).c_str()));
if (list.size() < 3)
continue;
EFI_GUID guid;
const char *sectionTypeStr = list[1].toLocal8Bit();
char *converted = const_cast<char *>(sectionTypeStr);
UINT8 sectionType = (UINT8)std::strtol(sectionTypeStr, &converted, 16);
if (converted == sectionTypeStr || !ustringToGuid(list[0], guid))
return U_INVALID_PARAMETER;
std::vector<PatchData> patches;
for (size_t i = 2; i < list.size(); i++) {
std::vector<UByteArray> patchList;
std::string patchStr = list.at(i).toLocal8Bit();
std::string::size_type prev = 0, curr = 0;
while ((curr = line.find(':', curr)) != std::string::npos) {
std::string substring( line.substr(prev, curr-prev) );
patchList.push_back(UByteArray(substring));
prev = ++curr;
}
patchList.push_back(UByteArray(line.substr(prev, curr-prev)));
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.push_back(patch);
}
else if (patch.type == PATCH_TYPE_OFFSET) {
patch.offset = patchList.at(1).toUInt(NULL, 16);
patch.hexReplacePattern = patchList.at(2);
patches.push_back(patch);
}
else {
// Ignore unknown patch type
continue;
}
}
result = patchFile(model->index(0, 0), UByteArray((const char*)&guid, sizeof(EFI_GUID)), sectionType, patches);
if (result && result != U_NOTHING_TO_PATCH)
return result;
counter++;
}
UByteArray reconstructed;
result = ffsBuilder->build(model->index(0,0), reconstructed);
if (result)
return result;
if (reconstructed == buffer)
return U_NOTHING_TO_PATCH;
std::ofstream outputFile;
outputFile.open(outPath.toLocal8Bit(), std::ios::out | std::ios::binary);
outputFile.write(reconstructed.constData(), reconstructed.size());
outputFile.close();
return U_SUCCESS;
}
USTATUS UEFIPatch::patchFile(const UModelIndex & index, const UByteArray & fileGuid, const UINT8 sectionType, const std::vector<PatchData> & patches)
{
if (!model || !index.isValid())
return U_INVALID_PARAMETER;
if (model->type(index) == Types::Section && model->subtype(index) == sectionType) {
UModelIndex fileIndex = model->findParentOfType(index, Types::File);
if (model->type(fileIndex) == Types::File &&
model->header(fileIndex).left(sizeof(EFI_GUID)) == fileGuid)
{
// return ffsOps->patch(index, patches);
#warning "ffsOps->patch is not implemented!"
return U_NOTHING_TO_PATCH;
}
}
if (model->rowCount(index) > 0) {
for (int i = 0; i < model->rowCount(index); i++) {
USTATUS result = patchFile(index.child(i, 0), fileGuid, sectionType, patches);
if (!result)
break;
else if (result != U_NOTHING_TO_PATCH)
return result;
}
}
return U_NOTHING_TO_PATCH;
}

52
UEFIPatch/uefipatch.h Executable file
View file

@ -0,0 +1,52 @@
/* uefipatch.h
Copyright (c) 2018, LongSoft. 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 <iterator>
#include <set>
#include <vector>
#include "../common/basetypes.h"
#include "../common/ustring.h"
#include "../common/filesystem.h"
#include "../common/ffs.h"
#include "../common/ffsparser.h"
#include "../common/ffsops.h"
#include "../common/ffsbuilder.h"
#include "../common/utility.h"
struct PatchData {
UINT8 type;
UINT32 offset;
UByteArray hexFindPattern;
UByteArray hexReplacePattern;
};
class UEFIPatch
{
public:
explicit UEFIPatch();
~UEFIPatch();
USTATUS patchFromFile(const UString & inPath, const UString & patches, const UString & outPath);
private:
USTATUS patchFile(const UModelIndex & index, const UByteArray & fileGuid, const UINT8 sectionType, const std::vector<PatchData> & patches);
TreeModel* model;
FfsParser* ffsParser;
FfsBuilder* ffsBuilder;
FfsOperations* ffsOps;
};
#endif

90
UEFIPatch/uefipatch_main.cpp Executable file
View file

@ -0,0 +1,90 @@
/* uefipatch_main.cpp
Copyright (c) 2018, LongSoft. 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 <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include "../version.h"
#include "uefipatch.h"
int main(int argc, char *argv[])
{
UEFIPatch w;
USTATUS result = U_SUCCESS;
UINT32 argumentsCount = argc;
if (argumentsCount < 2) {
std::cout << "UEFIPatch " PROGRAM_VERSION " - UEFI image file patching utility" << std::endl << std::endl <<
"Usage: UEFIPatch image_file [patches.txt] [-o output]" << std::endl << std::endl <<
"Patches will be read from patches.txt file by default\n";
return U_SUCCESS;
}
UString inputPath = argv[1];
UString patches = "patches.txt";
UString outputPath = inputPath + ".patched";
for (UINT32 i = 2; i < argumentsCount; i++) {
if ((!std::strcmp(argv[i], "-o") || !std::strcmp(argv[i], "--output")) && i + 1 < argumentsCount) {
outputPath = argv[i+1];
i++;
} else if (patches == UString("patches.txt")) {
patches = argv[i];
} else {
result = U_INVALID_PARAMETER;
}
}
if (result == U_SUCCESS) {
result = w.patchFromFile(inputPath, patches, outputPath);
}
switch (result) {
case U_SUCCESS:
std::cout << "Image patched" << std::endl;
break;
case U_INVALID_PARAMETER:
std::cout << "Function called with invalid parameter" << std::endl;
break;
case U_NOTHING_TO_PATCH:
std::cout << "No patches can be applied to input file" << std::endl;
break;
case U_UNKNOWN_PATCH_TYPE:
std::cout << "Unknown patch type" << std::endl;
break;
case U_PATCH_OFFSET_OUT_OF_BOUNDS:
std::cout << "Patch offset out of bounds" << std::endl;
break;
case U_INVALID_SYMBOL:
std::cout << "Pattern format mismatch" << std::endl;
break;
case U_INVALID_FILE:
std::cout << patches.toLocal8Bit() << " file not found or can't be read" << std::endl;
break;
case U_FILE_OPEN:
std::cout << "Input file not found" << std::endl;
break;
case U_FILE_READ:
std::cout << "Input file can't be read" << std::endl;
break;
case U_FILE_WRITE:
std::cout << "Output file can't be written" << std::endl;
break;
default:
std::cout << "Error " << result << std::endl;
}
return result;
}

View file

@ -71,6 +71,9 @@ typedef size_t USTATUS;
#define U_INVALID_STORE_SIZE 49
#define U_UNKNOWN_COMPRESSION_ALGORITHM 50
#define U_NOTHING_TO_PATCH 51
#define U_UNKNOWN_PATCH_TYPE 52
#define U_PATCH_OFFSET_OUT_OF_BOUNDS 53
#define U_INVALID_SYMBOL 54
#define U_NOT_IMPLEMENTED 0xFF
// UDK porting definitions