mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
Add Patcher Project
The other Patcher repository is locked from future modifications
This commit is contained in:
@@ -0,0 +1,334 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
# *.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Gee.External.Capstone;
|
||||||
|
using Gee.External.Capstone.Arm;
|
||||||
|
//using PeNet;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public static class ArmDisassembler
|
||||||
|
{
|
||||||
|
public static AnalyzedFile Analyze(string FilePath, string AsmPath = null)
|
||||||
|
{
|
||||||
|
PeFile File = new(FilePath);
|
||||||
|
|
||||||
|
SortedList<UInt32, ArmInstruction> AnalyzedCode = new(0x1000000); // Default capacity of 0x100000 was not enough for analyzing ntoskrnl.exe
|
||||||
|
|
||||||
|
if ((AsmPath != null) && System.IO.File.Exists(AsmPath))
|
||||||
|
{
|
||||||
|
using StreamReader Reader = new(AsmPath);
|
||||||
|
while (Reader.Peek() >= 0)
|
||||||
|
{
|
||||||
|
ArmInstruction Instruction = new(Reader.ReadLine());
|
||||||
|
AnalyzedCode.Add(Instruction.Address, Instruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CapstoneArmDisassembler Disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Thumb);
|
||||||
|
|
||||||
|
// Initially use a Dictionary and sort it afterwards. For analyzing ntoskrnl.exe this is about 60 times faster than using a SortedList from the start.
|
||||||
|
// Default capacity of 0x100000 was not enough for analyzing ntoskrnl.exe
|
||||||
|
Dictionary<UInt32, ArmInstruction> TempCode = new(0x1000000);
|
||||||
|
|
||||||
|
// Analyze from entrypoint
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)(File.ImageBase + File.EntryPoint));
|
||||||
|
|
||||||
|
// Analyze from exports
|
||||||
|
foreach (FunctionDescriptor Function in File.Exports)
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)Function.VirtualAddress);
|
||||||
|
|
||||||
|
// Analyze from imports
|
||||||
|
foreach (FunctionDescriptor Function in File.Imports)
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)Function.VirtualAddress);
|
||||||
|
|
||||||
|
// Analyze from runtime-functions
|
||||||
|
foreach (FunctionDescriptor Function in File.RuntimeFunctions)
|
||||||
|
Analyze(Disassembler, File.Sections, TempCode, (UInt32)Function.VirtualAddress);
|
||||||
|
|
||||||
|
// Sort the instructions.
|
||||||
|
// SortedList is used, because it can be indexed by value (not only by key).
|
||||||
|
List<UInt32> Keys = TempCode.Keys.ToList();
|
||||||
|
Keys.Sort();
|
||||||
|
foreach (UInt32 Key in Keys)
|
||||||
|
AnalyzedCode.Add(Key, TempCode[Key]);
|
||||||
|
|
||||||
|
if (AsmPath != null)
|
||||||
|
{
|
||||||
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(AsmPath));
|
||||||
|
|
||||||
|
using StreamWriter Writer = new(AsmPath, false);
|
||||||
|
for (int i = 0; i < AnalyzedCode.Count; i++)
|
||||||
|
{
|
||||||
|
Writer.WriteLine(AnalyzedCode.Values[i].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AnalyzedFile() { File = File, Code = AnalyzedCode };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Analyze(CapstoneArmDisassembler Disassembler, List<Section> Sections, Dictionary<UInt32, ArmInstruction> AnalyzedCode, UInt32 VirtualAddress)
|
||||||
|
{
|
||||||
|
VirtualAddress -= (VirtualAddress % 2);
|
||||||
|
List<UInt32> AddressesToAnalyze = new();
|
||||||
|
AddressesToAnalyze.Add(VirtualAddress);
|
||||||
|
Section CurrentSection = null;
|
||||||
|
|
||||||
|
while (AddressesToAnalyze.Count > 0)
|
||||||
|
{
|
||||||
|
UInt32 CurrentAddress = AddressesToAnalyze[0];
|
||||||
|
if ((CurrentSection == null) || (CurrentAddress < CurrentSection.VirtualAddress) || (CurrentAddress > (CurrentSection.VirtualAddress + CurrentSection.VirtualSize)))
|
||||||
|
{
|
||||||
|
CurrentSection = Sections.Find(s => (CurrentAddress >= s.VirtualAddress) && (CurrentAddress < (s.VirtualAddress + s.VirtualSize)) && s.IsCode);
|
||||||
|
if (CurrentSection == null)
|
||||||
|
{
|
||||||
|
// throw new Exception("Address 0x" + CurrentAddress.ToString("X8") + " is not inside boundaries of code-sections");
|
||||||
|
// Probably jumped to this address because data was disassembled as if it were code. Ignore this.
|
||||||
|
// return;
|
||||||
|
AddressesToAnalyze.RemoveAt(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AnalyzedCode.ContainsKey(CurrentAddress))
|
||||||
|
{
|
||||||
|
// return;
|
||||||
|
AddressesToAnalyze.RemoveAt(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gee.External.Capstone.Arm.ArmInstruction[] NewInstructions = Disassembler.Disassemble(CurrentSection.Buffer.Skip((int)CurrentAddress - (int)CurrentSection.VirtualAddress).ToArray(), CurrentAddress);
|
||||||
|
if (NewInstructions.Any())
|
||||||
|
{
|
||||||
|
UInt32 StartAddress = (UInt32)NewInstructions.First().Address;
|
||||||
|
UInt32 EndAddress = (UInt32)NewInstructions.Last().Address;
|
||||||
|
|
||||||
|
ArmInstruction PreviousInstruction = null;
|
||||||
|
foreach (Gee.External.Capstone.Arm.ArmInstruction DisassemblerInstruction in NewInstructions)
|
||||||
|
{
|
||||||
|
// ArmInstruction Instruction = new ArmInstruction(DisassemblerInstruction);
|
||||||
|
ArmInstruction Instruction = new()
|
||||||
|
{
|
||||||
|
Address = (UInt32)DisassemblerInstruction.Address,
|
||||||
|
Bytes = DisassemblerInstruction.Bytes,
|
||||||
|
Mnemonic = DisassemblerInstruction.Mnemonic,
|
||||||
|
Operand = DisassemblerInstruction.Operand.Replace("sb", "r9").Replace("sl", "r10").Replace("fp", "r11").Replace("ip", "r12")
|
||||||
|
};
|
||||||
|
|
||||||
|
if (AnalyzedCode.ContainsKey((UInt32)Instruction.Address))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Merge movw + movt into one command
|
||||||
|
// movw r3, #0x6010 + movt r3, #0x1000 = mov r3, #0x10006010
|
||||||
|
UInt32 HighPart, LowPart;
|
||||||
|
string HighString, LowString;
|
||||||
|
if ((PreviousInstruction?.Mnemonic == "movt") && (Instruction.Mnemonic == "movw") && (PreviousInstruction.Operand.Split(new char[] { ',' })[0] == Instruction.Operand.Split(new char[] { ',' })[0]))
|
||||||
|
{
|
||||||
|
byte[] Combined = new byte[8];
|
||||||
|
System.Buffer.BlockCopy(PreviousInstruction.Bytes, 0, Combined, 0, 4);
|
||||||
|
System.Buffer.BlockCopy(Instruction.Bytes, 0, Combined, 4, 4);
|
||||||
|
PreviousInstruction.Bytes = Combined;
|
||||||
|
PreviousInstruction.Mnemonic = "mov";
|
||||||
|
|
||||||
|
HighString = PreviousInstruction.Operand[(PreviousInstruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
HighPart = (HighString.Length >= 2) && (HighString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(HighString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(HighString);
|
||||||
|
LowString = Instruction.Operand[(Instruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
LowPart = (LowString.Length >= 2) && (LowString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(LowString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(LowString);
|
||||||
|
PreviousInstruction.Operand = string.Concat(PreviousInstruction.Operand.AsSpan(0, PreviousInstruction.Operand.IndexOf('#') + 1), "0x", ((HighPart << 16) + LowPart).ToString("X8"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((PreviousInstruction?.Mnemonic == "movw") && (Instruction.Mnemonic == "movt") && (PreviousInstruction.Operand.Split(new char[] { ',' })[0] == Instruction.Operand.Split(new char[] { ',' })[0]))
|
||||||
|
{
|
||||||
|
byte[] Combined = new byte[8];
|
||||||
|
System.Buffer.BlockCopy(PreviousInstruction.Bytes, 0, Combined, 0, 4);
|
||||||
|
System.Buffer.BlockCopy(Instruction.Bytes, 0, Combined, 4, 4);
|
||||||
|
PreviousInstruction.Bytes = Combined;
|
||||||
|
PreviousInstruction.Mnemonic = "mov";
|
||||||
|
|
||||||
|
HighString = Instruction.Operand[(Instruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
HighPart = (HighString.Length >= 2) && (HighString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(HighString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(HighString);
|
||||||
|
LowString = PreviousInstruction.Operand[(PreviousInstruction.Operand.IndexOf('#') + 1)..];
|
||||||
|
LowPart = (LowString.Length >= 2) && (LowString.Substring(0, 2) == "0x")
|
||||||
|
? UInt32.Parse(LowString[2..], System.Globalization.NumberStyles.HexNumber)
|
||||||
|
: UInt32.Parse(LowString);
|
||||||
|
PreviousInstruction.Operand = string.Concat(PreviousInstruction.Operand.AsSpan(0, PreviousInstruction.Operand.IndexOf('#') + 1), "0x", ((HighPart << 16) + LowPart).ToString("X8"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalyzedCode.Add((UInt32)Instruction.Address, Instruction);
|
||||||
|
|
||||||
|
int IndexOfIndirectConstant = Instruction.Operand.IndexOf("[pc, #0x");
|
||||||
|
if (IndexOfIndirectConstant >= 0)
|
||||||
|
{
|
||||||
|
int IndexOfEnd = Instruction.Operand.IndexOf("]", IndexOfIndirectConstant);
|
||||||
|
string PCOffsetString = Instruction.Operand.Substring(IndexOfIndirectConstant + 8, IndexOfEnd - IndexOfIndirectConstant - 8);
|
||||||
|
UInt32 PCOffset = UInt32.Parse(PCOffsetString, System.Globalization.NumberStyles.HexNumber);
|
||||||
|
UInt32 PC = (UInt32)Instruction.Address + 4;
|
||||||
|
UInt32 PCforIndirect = PC - (PC % 4);
|
||||||
|
UInt32 VirtualAddressOfIndirectConstant = PCforIndirect + PCOffset;
|
||||||
|
|
||||||
|
// If the address is outside the range of the section, then this is probably data which is compiled as code.
|
||||||
|
// In this case we will ignore this and not do this part of the analysis.
|
||||||
|
if ((VirtualAddressOfIndirectConstant >= CurrentSection.VirtualAddress) && (VirtualAddressOfIndirectConstant < (CurrentSection.VirtualAddress + CurrentSection.VirtualSize)))
|
||||||
|
{
|
||||||
|
UInt32 RawOffsetOfIndirectConstant = VirtualAddressOfIndirectConstant - CurrentSection.VirtualAddress;
|
||||||
|
UInt32 IndirectConstant = BitConverter.ToUInt32(CurrentSection.Buffer, (int)RawOffsetOfIndirectConstant);
|
||||||
|
Instruction.Operand = Instruction.Operand.Substring(0, IndexOfIndirectConstant) + "#0x" + IndirectConstant.ToString("x8") + Instruction.Operand[(IndexOfEnd + 1)..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JumpCommands.Contains(Instruction.Mnemonic))
|
||||||
|
{
|
||||||
|
UInt32 NewAddress = UInt32.Parse(Instruction.Operand[(Instruction.Operand.IndexOf("#0x") + 3)..], System.Globalization.NumberStyles.HexNumber);
|
||||||
|
NewAddress -= (NewAddress % 2);
|
||||||
|
if (((NewAddress < StartAddress) || (NewAddress > EndAddress)) && !AddressesToAnalyze.Any(a => a == NewAddress))
|
||||||
|
AddressesToAnalyze.Add(NewAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviousInstruction = Instruction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressesToAnalyze.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] JumpCommands = new string[]
|
||||||
|
{
|
||||||
|
"b", "b.w", "bl", "bl.w", "beq", "beq.w", "bne", "bne.w", "bhs", "bhs.w", "blo", "blo.w",
|
||||||
|
"bmi", "bmi.w", "bpl", "bpl.w", "bvs", "bvs.w", "bvc", "bvc.w", "bhi", "bhi.w", "bls", "bls.w",
|
||||||
|
"bge", "bge.w", "blt", "blt.w", "bgt", "bgt.w", "ble", "ble.w", "bal", "bal.w", "cbnz", "cbz"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string[] ConditionalJumpInstructions = new string[]
|
||||||
|
{
|
||||||
|
"beq", "beq.w", "bne", "bne.w", "bhs", "bhs.w", "blo", "blo.w", "bmi", "bmi.w",
|
||||||
|
"bpl", "bpl.w", "bvs", "bvs.w", "bvc", "bvc.w", "bhi", "bhi.w", "bls", "bls.w",
|
||||||
|
"bge", "bge.w", "blt", "blt.w", "bgt", "bgt.w", "ble", "ble.w", "bal", "bal.w", "cbnz", "cbz"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string WriteCode(SortedDictionary<UInt32, ArmInstruction> AnalyzedCode)
|
||||||
|
{
|
||||||
|
StringBuilder Code = new(1000);
|
||||||
|
|
||||||
|
foreach (var Instruction in AnalyzedCode)
|
||||||
|
{
|
||||||
|
Code.AppendFormat("{0:X}: \t {1} \t {2}\r\n", Instruction.Value.Address, Instruction.Value.Mnemonic, Instruction.Value.Operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Code.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArmInstruction
|
||||||
|
{
|
||||||
|
public UInt32 Address;
|
||||||
|
public byte[] Bytes;
|
||||||
|
public string Mnemonic;
|
||||||
|
public string Operand;
|
||||||
|
|
||||||
|
public ArmInstruction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmInstruction(string Assembly)
|
||||||
|
{
|
||||||
|
Address = UInt32.Parse(Assembly.Substring(0, 8), System.Globalization.NumberStyles.HexNumber);
|
||||||
|
string Hex = Assembly.Substring(12, 24).Trim();
|
||||||
|
Bytes = new byte[(Hex.Length + 1) / 3];
|
||||||
|
for (int i = 0; i < Bytes.Length; i++)
|
||||||
|
Bytes[i] = byte.Parse(Hex.Substring(i * 3, 2), System.Globalization.NumberStyles.HexNumber);
|
||||||
|
Mnemonic = Assembly.Substring(39, 16).Trim();
|
||||||
|
Operand = Assembly[55..];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder Result = new();
|
||||||
|
|
||||||
|
Result.Append(Address.ToString("X8")); // 0
|
||||||
|
Result.Append(" ");
|
||||||
|
for (int i = 0; i < Bytes.Length; i++) // 12
|
||||||
|
{
|
||||||
|
Result.Append(Bytes[i].ToString("X2"));
|
||||||
|
Result.Append(' ');
|
||||||
|
}
|
||||||
|
Result.Append(new String(' ', (8 - Bytes.Length) * 3));
|
||||||
|
Result.Append(" ");
|
||||||
|
Result.Append(Mnemonic.PadRight(16)); // 39
|
||||||
|
Result.Append(Operand); // 55
|
||||||
|
|
||||||
|
return Result.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnalyzedFile
|
||||||
|
{
|
||||||
|
public PeFile File;
|
||||||
|
public SortedList<UInt32, ArmInstruction> Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>Patcher</RootNamespace>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Patcher\ArmCompiler.cs">
|
||||||
|
<Link>ArmCompiler.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\ByteOperations.cs">
|
||||||
|
<Link>ByteOperations.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\HelperClasses.cs">
|
||||||
|
<Link>HelperClasses.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\ObjectFileParser.cs">
|
||||||
|
<Link>ObjectFileParser.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\PatchEngine.cs">
|
||||||
|
<Link>PatchEngine.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Patcher\PeFile.cs">
|
||||||
|
<Link>PeFile.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<None Include="..\Patcher\LICENSE">
|
||||||
|
<Link>LICENSE</Link>
|
||||||
|
</None>
|
||||||
|
<None Update="BootUnllockAndRootAccessPatchScript.pds">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Gee.External.Capstone" Version="2.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
|
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="MainForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,698 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Patch Definition Script for Boot Unlock and Root Access on Windows Mobile
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
PatchDefinition Name="RootAccess-MainOS" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\sspisrv.dll"
|
||||||
|
|
||||||
|
JumpToImport "RpcImpersonateClient"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "CheckLowboxAccess" // Optional here
|
||||||
|
PatchCode
|
||||||
|
MOVS R1, #1
|
||||||
|
STR R1, [R0]
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\NtlmShared.dll"
|
||||||
|
|
||||||
|
JumpToExport "MsvpPasswordValidate"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\pacmanserver.dll"
|
||||||
|
|
||||||
|
FindFirstUnicode "GetMaxCountForDeployedApp"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
PatchCode
|
||||||
|
LDR R1, =0x7FFFFFFF
|
||||||
|
STR R1, [R0]
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\mscoree.dll"
|
||||||
|
|
||||||
|
JumpToImport "GetModuleFileNameW"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "CompareWithWhiteList" // Optional here
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\DeploymentExt.dll"
|
||||||
|
|
||||||
|
FindFirstUnicode "MaxUnsignedApp"
|
||||||
|
JumpToReference
|
||||||
|
FindValue 0x800413A0
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\ntoskrnl.exe"
|
||||||
|
|
||||||
|
// Fase 1: find all kernel-functions
|
||||||
|
|
||||||
|
JumpToExport "SeAccessCheckWithHint"
|
||||||
|
CreateLabel "SeAccessCheckWithHint"
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "ADD R0, SP, #0x7C" R1 = "MOV R1, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepFilterToDiscretionary"
|
||||||
|
|
||||||
|
JumpToReference R0 = "ADDS R0, R?, #0xD0"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
CreateLabel "SeAccessCheckByType"
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "ADDS R0, R?, #0xF8" R1 = "MOV R1, R?" R2 = "LDR R2, [R?,#0x28]" R3 = "MOV R3, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepConstrainByMandatory"
|
||||||
|
|
||||||
|
JumpBack // to SeAccessCheckByType
|
||||||
|
JumpBack // to SepFilterToDiscretionary
|
||||||
|
|
||||||
|
JumpToReference R1 = "LDR R1, [R?,#8]"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
CreateLabel "SepCommonAccessCheckEx"
|
||||||
|
|
||||||
|
FindFunctionCall Result = "STR R0, [SP,#0xD4]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepAccessCheckEx"
|
||||||
|
|
||||||
|
JumpBack // to SepCommonAccessCheckEx
|
||||||
|
JumpBack // to SepFilterToDiscretionary
|
||||||
|
|
||||||
|
JumpToReference R0 = "ADDS R0, R?, #0x130"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
FindPreviousInstruction "PUSH"
|
||||||
|
CreateLabel "SepAccessCheckAndAuditAlarm"
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "LDR R0, [R?,#0x130]" R1 = "MOV R1, R?" R2 = "LDR R2, [R?,#0x50]" R3 = "MOV R3, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepConstrainByConstraintMask"
|
||||||
|
FindNextConditionalJump
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepConstrainByConstraintMask_FunctionChunk01"
|
||||||
|
|
||||||
|
JumpBack // to SepConstrainByConstraintMask
|
||||||
|
JumpBack // to SepAccessCheckAndAuditAlarm
|
||||||
|
JumpBack // to SepFilterToDiscretionary
|
||||||
|
JumpBack // to SeAccessCheckWithHint
|
||||||
|
|
||||||
|
FindFunctionCall R0 = "ADD R0, SP, #0x88" R1 = "MOV R1, R?"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepMandatoryToDiscretionary"
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
FindFunctionCall Result = "STR R0, [SP,#0x70]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepAccessCheck"
|
||||||
|
|
||||||
|
JumpToExport "SePrivilegeCheck"
|
||||||
|
FindFunctionCall
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepPrivilegeCheck"
|
||||||
|
|
||||||
|
JumpToExport "SeSinglePrivilegeCheck"
|
||||||
|
CreateLabel "SeSinglePrivilegeCheck"
|
||||||
|
|
||||||
|
JumpToExport "ObReferenceObjectByHandleWithTag"
|
||||||
|
CreateLabel "ObReferenceObjectByHandleWithTag"
|
||||||
|
|
||||||
|
// Fase 2: patches
|
||||||
|
|
||||||
|
JumpToLabel "SeAccessCheckByType"
|
||||||
|
|
||||||
|
// Patch 1:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 2:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindStore
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 3:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is back on that value.
|
||||||
|
// FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 4:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is back on that value.
|
||||||
|
// FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 5:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindNextInstruction "BNE"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch5"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch5
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
// Patch 6:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 7:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindStore
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 8:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 9:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
JumpToLabel "SepAccessCheckAndAuditAlarm"
|
||||||
|
|
||||||
|
// Patch 10:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 11:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindStore
|
||||||
|
CreateLabel "Patch11"
|
||||||
|
FindNextConditionalJump
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch11"
|
||||||
|
JumpToLabel "Patch11"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch11
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
// Patch 12:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
PatchCode
|
||||||
|
MOV.W R2, #0
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepCommonAccessCheckEx"
|
||||||
|
|
||||||
|
// Patch 13:
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
JumpToLabel "SeAccessCheckWithHint"
|
||||||
|
|
||||||
|
// Patch 14:
|
||||||
|
FindNextInstruction "BEQ"
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
JumpToLabel "SeSinglePrivilegeCheck"
|
||||||
|
|
||||||
|
// Patch 15:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "ObReferenceObjectByHandleWithTag"
|
||||||
|
|
||||||
|
FindFunctionCall
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "ObpReferenceObjectByHandleWithTag"
|
||||||
|
FindInstructionPattern "LDR R?, [R?,#0x74]; CMP R?, #0; BNE ?" InstructionIndex = 2
|
||||||
|
JumpToTarget
|
||||||
|
|
||||||
|
// Patch 16:
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is on the error-value.
|
||||||
|
|
||||||
|
// Patch 17:
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 18:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
JumpToLabel "SepPrivilegeCheck"
|
||||||
|
|
||||||
|
// Patch 19:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepMandatoryToDiscretionary"
|
||||||
|
|
||||||
|
// Patch 20:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepAccessCheckEx"
|
||||||
|
|
||||||
|
// Patch 21:
|
||||||
|
FindNextValue 0x2000000
|
||||||
|
CreateLabel "Patch21"
|
||||||
|
FindNextInstruction "B"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch21"
|
||||||
|
JumpToLabel "Patch21"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch21
|
||||||
|
EndPatch
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 22:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional // This jump is right above the value 0xC0000022. After patch the pointer is back on that value.
|
||||||
|
// FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 23:
|
||||||
|
JumpToReference 0
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 24:
|
||||||
|
JumpToReference 1
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 25:
|
||||||
|
JumpToReference 2
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 26:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 27:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 28:
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
JumpToLabel "SepAccessCheck"
|
||||||
|
|
||||||
|
// Patch 29:
|
||||||
|
FindFunctionCall R0 = "LDR R0, [SP,#0x28]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepNormalAccessCheck"
|
||||||
|
JumpBack
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
// Patch 30:
|
||||||
|
FindFunctionCall R0 = "MOV R0, R?" R1 = "MOV R1, R?" R2 = "MOV R2, R?" R3 = "LDR R3, [SP,#0x38]"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "SepMaximumAccessCheck"
|
||||||
|
JumpBack
|
||||||
|
FindNextConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
// Patch 31:
|
||||||
|
FindNextConditionalJump
|
||||||
|
ClearInstruction
|
||||||
|
|
||||||
|
// Patch 32:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
JumpToReference 1
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 33:
|
||||||
|
JumpToReference 2
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 34:
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
FindPreviousInstruction "MOVS"
|
||||||
|
FindPreviousInstruction "MOVS"
|
||||||
|
JumpToReference
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
FindNextValue 0xC0000022
|
||||||
|
|
||||||
|
// Patch 35:
|
||||||
|
JumpToReference CodePattern = "BEQ"
|
||||||
|
ClearInstruction
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 36:
|
||||||
|
JumpToReference CodePattern = "MOVS; B"
|
||||||
|
FindPreviousInstruction "B"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch36"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "CMP"
|
||||||
|
PatchCode
|
||||||
|
B.W TargetPatch36
|
||||||
|
EndPatch
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 37:
|
||||||
|
JumpToReference CodePattern = "STR; B"
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
// Patch 38:
|
||||||
|
// Stay in function-chunk. Error-code is between previous two patches.
|
||||||
|
FindPreviousValue 0xC0000022
|
||||||
|
FindPreviousConditionalJump
|
||||||
|
MakeJumpUnconditional
|
||||||
|
|
||||||
|
JumpToLabel "SepConstrainByMandatory"
|
||||||
|
|
||||||
|
// Patch 39:
|
||||||
|
FindNextInstruction "BNE"
|
||||||
|
JumpToTarget
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch39"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch39
|
||||||
|
EndPatch
|
||||||
|
JumpBack
|
||||||
|
|
||||||
|
// Patch 40:
|
||||||
|
FindNextInstruction "B"
|
||||||
|
JumpToTarget
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch40"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch40
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepFilterToDiscretionary"
|
||||||
|
|
||||||
|
// Patch 41:
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
JumpToLabel "SepConstrainByConstraintMask_FunctionChunk01"
|
||||||
|
|
||||||
|
// Patch 42:
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch42"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch42
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
// Patch 43:
|
||||||
|
FindNextInstruction "TST"
|
||||||
|
FindNextInstruction "CBNZ"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "TargetPatch43"
|
||||||
|
JumpBack
|
||||||
|
FindPreviousInstruction "BEQ"
|
||||||
|
FindPreviousInstruction "BEQ" // This one is actually not necessary. Kept here for consistency.
|
||||||
|
PatchCode
|
||||||
|
B TargetPatch43
|
||||||
|
EndPatch
|
||||||
|
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchDefinition Name="SecureBootHack-MainOS" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\BOOT\winload.efi"
|
||||||
|
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\ci.dll"
|
||||||
|
|
||||||
|
JumpToImport "PsGetProcessSignatureLevel"
|
||||||
|
JumpToReference
|
||||||
|
CreateLabel "PsGetProcessSignatureLevelWrapper"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "CipReportAndReprieveUMCIFailure"
|
||||||
|
FindNextInstruction "TST.W"
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional "BNE" // BNE -> B, BEQ -> NOP
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchDefinition Name="SecureBootHack-V1-EFIESP" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi" RelativePath="EFIESP" RelativeOutputPath="SecureBootHack-V1"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\boot\mobilestartup.efi" // Symbols taken from pdb from version 10.0.10586.107
|
||||||
|
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
FindFirstUnicode "BootDebugPolicyApplied"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ApplyBootDebugPolicy"
|
||||||
|
PatchCode // This patch is for the new unlock for Lumia Spec A
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchFile Path="efi\boot\bootarm.efi"
|
||||||
|
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
|
|
||||||
|
PatchDefinition Name="SecureBootHack-V2-EFIESP" VersionFrom="EFIESP\Windows\System32\Boot\mobilestartup.efi" RelativePath="EFIESP"
|
||||||
|
|
||||||
|
PatchFile Path="Windows\System32\boot\mobilestartup.efi"
|
||||||
|
|
||||||
|
FindFirstAscii "MZ"
|
||||||
|
CreateLabel "ImageBase"
|
||||||
|
FindFirstAscii "1.3.6.1.4.1.311.61.4.1"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ImgpValidateImageHash"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
FindFirstUnicode "BootDebugPolicyApplied"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "ApplyBootDebugPolicy"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #0
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
CreateLabel "EnterMassStorageModeShellCode" // Use the left-over space of the ApplyBootDebugPolicy-function to insert shell-code later on
|
||||||
|
FindFirstUnicode "MassStorageFlag"
|
||||||
|
CreateLabel "MassStorageName"
|
||||||
|
PatchUnicode "Heathcliff74MSM"
|
||||||
|
FindFirstBytes "41 E5 C1 A0 CE 73 7F 46 88 EC D4 4F 92 34 50 4A"
|
||||||
|
CreateLabel "MassStorageGuid"
|
||||||
|
JumpToLabel "MassStorageName"
|
||||||
|
JumpToReference
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "EfiGetVariableVolatile"
|
||||||
|
FindValue 2
|
||||||
|
FindNextConditionalJump
|
||||||
|
MakeJumpUnconditional "BEQ"
|
||||||
|
FindFirstUnicode "\Windows\System32\boot\ui\boot.ums.waiting.bmpx"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "EnterMassStorageMode"
|
||||||
|
JumpToReference
|
||||||
|
PatchCode
|
||||||
|
B.W EnterMassStorageModeShellCode
|
||||||
|
EndPatch
|
||||||
|
CreateLabel ReturnFromMassStorageMode
|
||||||
|
FindFirstValue 0x26000145
|
||||||
|
IfNotFoundGo PatchForSetErrorDone
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "SetError"
|
||||||
|
PatchCode
|
||||||
|
MOVS R0, #1
|
||||||
|
BX LR
|
||||||
|
EndPatch
|
||||||
|
PatchForSetErrorDone:
|
||||||
|
FindFirstUnicode "DeviceIDVersion"
|
||||||
|
JumpToReference
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "EfiSetVariable"
|
||||||
|
FindFirstAscii "charge: DisplayPowerState protocol successfully loaded"
|
||||||
|
JumpToReference
|
||||||
|
FindPreviousInstruction "PUSH.W"
|
||||||
|
CreateLabel "InitGraphicsSubsystem"
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "BlpArchQueryCurrentContextType"
|
||||||
|
JumpBack
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
FindNextInstruction "BL"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "BlpArchSwitchContext"
|
||||||
|
JumpBack
|
||||||
|
FindNextInstruction "LDR"
|
||||||
|
JumpToTarget
|
||||||
|
CreateLabel "EfiBS"
|
||||||
|
JumpToLabel "EnterMassStorageModeShellCode"
|
||||||
|
PatchCode
|
||||||
|
MOV R0, PC
|
||||||
|
LDR R1, =(ApplyBootDebugPolicy - ImageBase + 8) // Subtract (Offset of shell-code + 4)
|
||||||
|
SUB R0, R0, R1 // R0 = relocated base of mobilestartup.efi
|
||||||
|
PUSH {R4-R6}
|
||||||
|
SUB SP, SP, #4
|
||||||
|
MOV R4, R0 // R4 = relocated base of mobilestartup.efi
|
||||||
|
|
||||||
|
LDR R3, =(MassStorageName - ImageBase) // Offset of NV var name (which is patched to "Heathcliff74MSM")
|
||||||
|
ADD R0, R4, R3
|
||||||
|
LDR R3, =(MassStorageGuid - ImageBase) // Offset of NV var Guid
|
||||||
|
ADD R1, R4, R3
|
||||||
|
MOVS R2, #3 // Non-volatile, boot-services
|
||||||
|
MOVS R3, #0 // Data-size
|
||||||
|
STR R3, [SP] // Pointer to data-buffer = NULL
|
||||||
|
LDR R6, =(EfiSetVariable - ImageBase + 1) // Offset of SetVariable + 1
|
||||||
|
ADD R5, R4, R6
|
||||||
|
BLX R5 // EfiSetVariable -> Delete variable
|
||||||
|
|
||||||
|
LDR R1, =(BlpArchQueryCurrentContextType - ImageBase + 1) // Offset to first thread-function + 1
|
||||||
|
ADD R5, R4, R1
|
||||||
|
BLX R5
|
||||||
|
MOV R6, R0
|
||||||
|
CMP R6, #1
|
||||||
|
BEQ ContextSwitchDone1
|
||||||
|
MOVS R0, #1
|
||||||
|
LDR R1, =(BlpArchSwitchContext - ImageBase + 1) // Offset to second thread-function + 1
|
||||||
|
ADD R5, R4, R1
|
||||||
|
BLX R5
|
||||||
|
ContextSwitchDone1:
|
||||||
|
|
||||||
|
LDR R0, =(EfiBS - ImageBase) // Offset of pointer to BootServices function-table
|
||||||
|
ADD R1, R4, R0 // R1 = pointer to pointer to BootServices function-table
|
||||||
|
LDR R1, [R1] // R1 = pointer to BootServices function-table
|
||||||
|
LDR.W R5, [R1,#0xAC] // LocateProtocol
|
||||||
|
ADR R0, VarServicesGuid // This is relative, no need to relocate
|
||||||
|
MOVS R1, #0
|
||||||
|
MOV R2, SP
|
||||||
|
BLX R5 // LocateProtocol - pVarServices in [SP]
|
||||||
|
LDR R5, [SP] // R5 = Pointer to VariableServices interface
|
||||||
|
LDR R5, [R5,#4] // R5 = pointer to FlushVariableNV()
|
||||||
|
CMP R5, #0
|
||||||
|
BNE PointerFound
|
||||||
|
LDR R5, [SP] // R5 = Pointer to VariableServices interface
|
||||||
|
LDR R5, [R5,#8] // R5 = pointer to FlushVariableNV()
|
||||||
|
PointerFound:
|
||||||
|
BLX R5 // FlushVariableNV()
|
||||||
|
|
||||||
|
CMP R6, #1
|
||||||
|
BEQ ContextSwitchDone2
|
||||||
|
MOV R0, R6
|
||||||
|
LDR R1, =(BlpArchSwitchContext - ImageBase + 1) // Offset to second thread-function + 1
|
||||||
|
ADD R5, R4, R1
|
||||||
|
BLX R5
|
||||||
|
ContextSwitchDone2:
|
||||||
|
|
||||||
|
LDR R6, =(EnterMassStorageMode - ImageBase + 1) // Offset of EnterMassStorageMode + 1
|
||||||
|
ADD R5, R4, R6
|
||||||
|
BLX R5 // EnterMassStorageMode
|
||||||
|
|
||||||
|
LDR R6, =(ReturnFromMassStorageMode - ImageBase + 1) // Offset of return address + 1
|
||||||
|
ADD R0, R4, R6
|
||||||
|
ADD SP, SP, #4
|
||||||
|
POP {R4-R6}
|
||||||
|
BX R0
|
||||||
|
|
||||||
|
VarServicesGuid:
|
||||||
|
DCD 0xf9085b9d
|
||||||
|
DCW 0x9304, 0x40fb
|
||||||
|
DCB 0x8f, 0xe0, 0x4a, 0xee, 0x3b, 0x1a, 0x78, 0x4b
|
||||||
|
EndPatch
|
||||||
|
PatchChecksum
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// This class was found online.
|
||||||
|
// Original author is probably: Swizzy
|
||||||
|
// https://github.com/ttgxdinger/Random/blob/master/CPUKey%20Checker/CPUKey%20Checker/FolderSelectDialog.cs
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps System.Windows.Forms.OpenFileDialog to make it present
|
||||||
|
/// a vista-style dialog.
|
||||||
|
/// </summary>
|
||||||
|
public class FolderSelectDialog
|
||||||
|
{
|
||||||
|
// Wrapped dialog
|
||||||
|
private readonly OpenFileDialog ofd = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default constructor
|
||||||
|
/// </summary>
|
||||||
|
public FolderSelectDialog()
|
||||||
|
{
|
||||||
|
ofd = new OpenFileDialog
|
||||||
|
{
|
||||||
|
Filter = "Folders|\n",
|
||||||
|
AddExtension = false,
|
||||||
|
CheckFileExists = false,
|
||||||
|
DereferenceLinks = true,
|
||||||
|
Multiselect = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the initial folder to be selected. A null value selects the current directory.
|
||||||
|
/// </summary>
|
||||||
|
public string InitialDirectory
|
||||||
|
{
|
||||||
|
get { return ofd.InitialDirectory; }
|
||||||
|
set { ofd.InitialDirectory = string.IsNullOrEmpty(value) ? Environment.CurrentDirectory : value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the title to show in the dialog
|
||||||
|
/// </summary>
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return ofd.Title; }
|
||||||
|
set { ofd.Title = value ?? "Select a folder"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the selected folder
|
||||||
|
/// </summary>
|
||||||
|
public string FileName
|
||||||
|
{
|
||||||
|
get { return ofd.FileName; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the dialog
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the user presses OK else false</returns>
|
||||||
|
public bool ShowDialog()
|
||||||
|
{
|
||||||
|
return ShowDialog(IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the dialog
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWndOwner">Handle of the control to be parent</param>
|
||||||
|
/// <returns>True if the user presses OK else false</returns>
|
||||||
|
public bool ShowDialog(IntPtr hWndOwner)
|
||||||
|
{
|
||||||
|
var fbd = new FolderBrowserDialog
|
||||||
|
{
|
||||||
|
Description = this.Title,
|
||||||
|
SelectedPath = this.InitialDirectory,
|
||||||
|
ShowNewFolderButton = false
|
||||||
|
};
|
||||||
|
if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofd.FileName = fbd.SelectedPath;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates IWin32Window around an IntPtr
|
||||||
|
/// </summary>
|
||||||
|
public class WindowWrapper : IWin32Window
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">Handle to wrap</param>
|
||||||
|
public WindowWrapper(IntPtr handle)
|
||||||
|
{
|
||||||
|
Handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Original ptr
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr Handle { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+423
@@ -0,0 +1,423 @@
|
|||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
partial class MainForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.txtVisualStudioPath = new System.Windows.Forms.TextBox();
|
||||||
|
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||||
|
this.OpenFileDialog = new System.Windows.Forms.OpenFileDialog();
|
||||||
|
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||||
|
this.cmdVisualStudioPath = new System.Windows.Forms.Button();
|
||||||
|
this.cmdInputFolder = new System.Windows.Forms.Button();
|
||||||
|
this.txtInputFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdOutputFolder = new System.Windows.Forms.Button();
|
||||||
|
this.txtOutputFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdPatchDefinitionsFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtPatchDefinitionsFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.txtConsole = new System.Windows.Forms.TextBox();
|
||||||
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdCompile = new System.Windows.Forms.Button();
|
||||||
|
this.cmdPatch = new System.Windows.Forms.Button();
|
||||||
|
this.cmdScriptFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtScriptFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label5 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdBackupFolder = new System.Windows.Forms.Button();
|
||||||
|
this.txtBackupFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.label6 = new System.Windows.Forms.Label();
|
||||||
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
|
this.CapstoneLink = new System.Windows.Forms.LinkLabel();
|
||||||
|
this.label8 = new System.Windows.Forms.Label();
|
||||||
|
this.CapstoneNetLink = new System.Windows.Forms.LinkLabel();
|
||||||
|
this.label10 = new System.Windows.Forms.Label();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Location = new System.Drawing.Point(15, 13);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(191, 13);
|
||||||
|
this.label1.TabIndex = 0;
|
||||||
|
this.label1.Text = "Path to Visual Studio with ARM32 SDK";
|
||||||
|
//
|
||||||
|
// txtVisualStudioPath
|
||||||
|
//
|
||||||
|
this.txtVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtVisualStudioPath.Location = new System.Drawing.Point(18, 29);
|
||||||
|
this.txtVisualStudioPath.Name = "txtVisualStudioPath";
|
||||||
|
this.txtVisualStudioPath.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtVisualStudioPath.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// OpenFileDialog
|
||||||
|
//
|
||||||
|
this.OpenFileDialog.FileName = "openFileDialog1";
|
||||||
|
//
|
||||||
|
// cmdVisualStudioPath
|
||||||
|
//
|
||||||
|
this.cmdVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdVisualStudioPath.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdVisualStudioPath.Location = new System.Drawing.Point(689, 28);
|
||||||
|
this.cmdVisualStudioPath.Name = "cmdVisualStudioPath";
|
||||||
|
this.cmdVisualStudioPath.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdVisualStudioPath.TabIndex = 2;
|
||||||
|
this.cmdVisualStudioPath.Text = "...";
|
||||||
|
this.cmdVisualStudioPath.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdVisualStudioPath.Click += new System.EventHandler(this.cmdVisualStudioPath_Click);
|
||||||
|
//
|
||||||
|
// cmdInputFolder
|
||||||
|
//
|
||||||
|
this.cmdInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdInputFolder.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdInputFolder.Location = new System.Drawing.Point(689, 224);
|
||||||
|
this.cmdInputFolder.Name = "cmdInputFolder";
|
||||||
|
this.cmdInputFolder.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdInputFolder.TabIndex = 8;
|
||||||
|
this.cmdInputFolder.Text = "...";
|
||||||
|
this.cmdInputFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdInputFolder.Click += new System.EventHandler(this.cmdInputFolder_Click);
|
||||||
|
//
|
||||||
|
// txtInputFolder
|
||||||
|
//
|
||||||
|
this.txtInputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtInputFolder.Location = new System.Drawing.Point(18, 225);
|
||||||
|
this.txtInputFolder.Name = "txtInputFolder";
|
||||||
|
this.txtInputFolder.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtInputFolder.TabIndex = 7;
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Location = new System.Drawing.Point(15, 209);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(71, 13);
|
||||||
|
this.label2.TabIndex = 12;
|
||||||
|
this.label2.Text = "Input location";
|
||||||
|
//
|
||||||
|
// cmdOutputFolder
|
||||||
|
//
|
||||||
|
this.cmdOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdOutputFolder.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdOutputFolder.Location = new System.Drawing.Point(689, 322);
|
||||||
|
this.cmdOutputFolder.Name = "cmdOutputFolder";
|
||||||
|
this.cmdOutputFolder.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdOutputFolder.TabIndex = 12;
|
||||||
|
this.cmdOutputFolder.Text = "...";
|
||||||
|
this.cmdOutputFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdOutputFolder.Click += new System.EventHandler(this.cmdOutputFolder_Click);
|
||||||
|
//
|
||||||
|
// txtOutputFolder
|
||||||
|
//
|
||||||
|
this.txtOutputFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtOutputFolder.Location = new System.Drawing.Point(18, 323);
|
||||||
|
this.txtOutputFolder.Name = "txtOutputFolder";
|
||||||
|
this.txtOutputFolder.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtOutputFolder.TabIndex = 11;
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(15, 307);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(125, 13);
|
||||||
|
this.label3.TabIndex = 15;
|
||||||
|
this.label3.Text = "Output location (optional)";
|
||||||
|
//
|
||||||
|
// cmdPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.cmdPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatchDefinitionsFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdPatchDefinitionsFile.Location = new System.Drawing.Point(689, 91);
|
||||||
|
this.cmdPatchDefinitionsFile.Name = "cmdPatchDefinitionsFile";
|
||||||
|
this.cmdPatchDefinitionsFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdPatchDefinitionsFile.TabIndex = 4;
|
||||||
|
this.cmdPatchDefinitionsFile.Text = "...";
|
||||||
|
this.cmdPatchDefinitionsFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatchDefinitionsFile.Click += new System.EventHandler(this.cmdPatchDefinitionsFile_Click);
|
||||||
|
//
|
||||||
|
// txtPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.txtPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtPatchDefinitionsFile.Location = new System.Drawing.Point(18, 92);
|
||||||
|
this.txtPatchDefinitionsFile.Name = "txtPatchDefinitionsFile";
|
||||||
|
this.txtPatchDefinitionsFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtPatchDefinitionsFile.TabIndex = 3;
|
||||||
|
this.txtPatchDefinitionsFile.Leave += new System.EventHandler(this.txtPatchDefinitionsFile_Leave);
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(15, 76);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(117, 13);
|
||||||
|
this.label4.TabIndex = 3;
|
||||||
|
this.label4.Text = "Patch defintions xml-file";
|
||||||
|
//
|
||||||
|
// txtConsole
|
||||||
|
//
|
||||||
|
this.txtConsole.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtConsole.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.txtConsole.Location = new System.Drawing.Point(18, 383);
|
||||||
|
this.txtConsole.Multiline = true;
|
||||||
|
this.txtConsole.Name = "txtConsole";
|
||||||
|
this.txtConsole.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtConsole.Size = new System.Drawing.Size(706, 392);
|
||||||
|
this.txtConsole.TabIndex = 13;
|
||||||
|
//
|
||||||
|
// label9
|
||||||
|
//
|
||||||
|
this.label9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.label9.AutoSize = true;
|
||||||
|
this.label9.Location = new System.Drawing.Point(15, 367);
|
||||||
|
this.label9.Name = "label9";
|
||||||
|
this.label9.Size = new System.Drawing.Size(78, 13);
|
||||||
|
this.label9.TabIndex = 24;
|
||||||
|
this.label9.Text = "Console output";
|
||||||
|
//
|
||||||
|
// cmdCompile
|
||||||
|
//
|
||||||
|
this.cmdCompile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdCompile.Location = new System.Drawing.Point(470, 792);
|
||||||
|
this.cmdCompile.Name = "cmdCompile";
|
||||||
|
this.cmdCompile.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdCompile.TabIndex = 14;
|
||||||
|
this.cmdCompile.Text = "Compile";
|
||||||
|
this.cmdCompile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdCompile.Click += new System.EventHandler(this.cmdCompile_Click);
|
||||||
|
//
|
||||||
|
// cmdPatch
|
||||||
|
//
|
||||||
|
this.cmdPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatch.Location = new System.Drawing.Point(604, 792);
|
||||||
|
this.cmdPatch.Name = "cmdPatch";
|
||||||
|
this.cmdPatch.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdPatch.TabIndex = 15;
|
||||||
|
this.cmdPatch.Text = "Patch";
|
||||||
|
this.cmdPatch.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatch.Click += new System.EventHandler(this.cmdPatch_Click);
|
||||||
|
//
|
||||||
|
// cmdScriptFile
|
||||||
|
//
|
||||||
|
this.cmdScriptFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdScriptFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdScriptFile.Location = new System.Drawing.Point(689, 155);
|
||||||
|
this.cmdScriptFile.Name = "cmdScriptFile";
|
||||||
|
this.cmdScriptFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdScriptFile.TabIndex = 6;
|
||||||
|
this.cmdScriptFile.Text = "...";
|
||||||
|
this.cmdScriptFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdScriptFile.Click += new System.EventHandler(this.cmdScriptFile_Click);
|
||||||
|
//
|
||||||
|
// txtScriptFile
|
||||||
|
//
|
||||||
|
this.txtScriptFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtScriptFile.Location = new System.Drawing.Point(18, 156);
|
||||||
|
this.txtScriptFile.Name = "txtScriptFile";
|
||||||
|
this.txtScriptFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtScriptFile.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// label5
|
||||||
|
//
|
||||||
|
this.label5.AutoSize = true;
|
||||||
|
this.label5.Location = new System.Drawing.Point(15, 140);
|
||||||
|
this.label5.Name = "label5";
|
||||||
|
this.label5.Size = new System.Drawing.Size(50, 13);
|
||||||
|
this.label5.TabIndex = 28;
|
||||||
|
this.label5.Text = "Script-file";
|
||||||
|
//
|
||||||
|
// cmdBackupFolder
|
||||||
|
//
|
||||||
|
this.cmdBackupFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdBackupFolder.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdBackupFolder.Location = new System.Drawing.Point(689, 273);
|
||||||
|
this.cmdBackupFolder.Name = "cmdBackupFolder";
|
||||||
|
this.cmdBackupFolder.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdBackupFolder.TabIndex = 10;
|
||||||
|
this.cmdBackupFolder.Text = "...";
|
||||||
|
this.cmdBackupFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdBackupFolder.Click += new System.EventHandler(this.cmdBackupFolder_Click);
|
||||||
|
//
|
||||||
|
// txtBackupFolder
|
||||||
|
//
|
||||||
|
this.txtBackupFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtBackupFolder.Location = new System.Drawing.Point(18, 274);
|
||||||
|
this.txtBackupFolder.Name = "txtBackupFolder";
|
||||||
|
this.txtBackupFolder.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtBackupFolder.TabIndex = 9;
|
||||||
|
//
|
||||||
|
// label6
|
||||||
|
//
|
||||||
|
this.label6.AutoSize = true;
|
||||||
|
this.label6.Location = new System.Drawing.Point(15, 258);
|
||||||
|
this.label6.Name = "label6";
|
||||||
|
this.label6.Size = new System.Drawing.Size(130, 13);
|
||||||
|
this.label6.TabIndex = 31;
|
||||||
|
this.label6.Text = "Backup location (optional)";
|
||||||
|
//
|
||||||
|
// label7
|
||||||
|
//
|
||||||
|
this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label7.AutoSize = true;
|
||||||
|
this.label7.Location = new System.Drawing.Point(20, 807);
|
||||||
|
this.label7.Name = "label7";
|
||||||
|
this.label7.Size = new System.Drawing.Size(66, 13);
|
||||||
|
this.label7.TabIndex = 32;
|
||||||
|
this.label7.Text = "Powered by ";
|
||||||
|
//
|
||||||
|
// CapstoneLink
|
||||||
|
//
|
||||||
|
this.CapstoneLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.CapstoneLink.AutoSize = true;
|
||||||
|
this.CapstoneLink.Location = new System.Drawing.Point(80, 807);
|
||||||
|
this.CapstoneLink.Name = "CapstoneLink";
|
||||||
|
this.CapstoneLink.Size = new System.Drawing.Size(52, 13);
|
||||||
|
this.CapstoneLink.TabIndex = 33;
|
||||||
|
this.CapstoneLink.TabStop = true;
|
||||||
|
this.CapstoneLink.Text = "Capstone";
|
||||||
|
this.CapstoneLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.CapstoneLink_LinkClicked);
|
||||||
|
//
|
||||||
|
// label8
|
||||||
|
//
|
||||||
|
this.label8.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label8.AutoSize = true;
|
||||||
|
this.label8.Location = new System.Drawing.Point(129, 807);
|
||||||
|
this.label8.Name = "label8";
|
||||||
|
this.label8.Size = new System.Drawing.Size(28, 13);
|
||||||
|
this.label8.TabIndex = 34;
|
||||||
|
this.label8.Text = "and ";
|
||||||
|
//
|
||||||
|
// CapstoneNetLink
|
||||||
|
//
|
||||||
|
this.CapstoneNetLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.CapstoneNetLink.AutoSize = true;
|
||||||
|
this.CapstoneNetLink.Location = new System.Drawing.Point(151, 807);
|
||||||
|
this.CapstoneNetLink.Name = "CapstoneNetLink";
|
||||||
|
this.CapstoneNetLink.Size = new System.Drawing.Size(77, 13);
|
||||||
|
this.CapstoneNetLink.TabIndex = 35;
|
||||||
|
this.CapstoneNetLink.TabStop = true;
|
||||||
|
this.CapstoneNetLink.Text = "Capstone.NET";
|
||||||
|
this.CapstoneNetLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.CapstoneNetLink_LinkClicked);
|
||||||
|
//
|
||||||
|
// label10
|
||||||
|
//
|
||||||
|
this.label10.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.label10.AutoSize = true;
|
||||||
|
this.label10.Location = new System.Drawing.Point(225, 807);
|
||||||
|
this.label10.Name = "label10";
|
||||||
|
this.label10.Size = new System.Drawing.Size(42, 13);
|
||||||
|
this.label10.TabIndex = 36;
|
||||||
|
this.label10.Text = "libraries";
|
||||||
|
//
|
||||||
|
// MainForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(742, 840);
|
||||||
|
this.Controls.Add(this.label10);
|
||||||
|
this.Controls.Add(this.CapstoneNetLink);
|
||||||
|
this.Controls.Add(this.label8);
|
||||||
|
this.Controls.Add(this.CapstoneLink);
|
||||||
|
this.Controls.Add(this.label7);
|
||||||
|
this.Controls.Add(this.cmdBackupFolder);
|
||||||
|
this.Controls.Add(this.txtBackupFolder);
|
||||||
|
this.Controls.Add(this.label6);
|
||||||
|
this.Controls.Add(this.cmdScriptFile);
|
||||||
|
this.Controls.Add(this.txtScriptFile);
|
||||||
|
this.Controls.Add(this.label5);
|
||||||
|
this.Controls.Add(this.cmdPatch);
|
||||||
|
this.Controls.Add(this.cmdCompile);
|
||||||
|
this.Controls.Add(this.txtConsole);
|
||||||
|
this.Controls.Add(this.label9);
|
||||||
|
this.Controls.Add(this.cmdPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.txtPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
|
this.Controls.Add(this.cmdOutputFolder);
|
||||||
|
this.Controls.Add(this.txtOutputFolder);
|
||||||
|
this.Controls.Add(this.label3);
|
||||||
|
this.Controls.Add(this.cmdInputFolder);
|
||||||
|
this.Controls.Add(this.txtInputFolder);
|
||||||
|
this.Controls.Add(this.label2);
|
||||||
|
this.Controls.Add(this.cmdVisualStudioPath);
|
||||||
|
this.Controls.Add(this.txtVisualStudioPath);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Name = "MainForm";
|
||||||
|
this.Text = "ARM Auto-patcher by Rene Lergner";
|
||||||
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed);
|
||||||
|
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.TextBox txtVisualStudioPath;
|
||||||
|
private System.Windows.Forms.FolderBrowserDialog FolderBrowserDialog;
|
||||||
|
private System.Windows.Forms.OpenFileDialog OpenFileDialog;
|
||||||
|
private System.Windows.Forms.SaveFileDialog SaveFileDialog;
|
||||||
|
private System.Windows.Forms.Button cmdVisualStudioPath;
|
||||||
|
private System.Windows.Forms.Button cmdInputFolder;
|
||||||
|
private System.Windows.Forms.TextBox txtInputFolder;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.Button cmdOutputFolder;
|
||||||
|
private System.Windows.Forms.TextBox txtOutputFolder;
|
||||||
|
private System.Windows.Forms.Label label3;
|
||||||
|
private System.Windows.Forms.Button cmdPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.TextBox txtPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.TextBox txtConsole;
|
||||||
|
private System.Windows.Forms.Label label9;
|
||||||
|
private System.Windows.Forms.Button cmdCompile;
|
||||||
|
private System.Windows.Forms.Button cmdPatch;
|
||||||
|
private System.Windows.Forms.Button cmdScriptFile;
|
||||||
|
private System.Windows.Forms.TextBox txtScriptFile;
|
||||||
|
private System.Windows.Forms.Label label5;
|
||||||
|
private System.Windows.Forms.Button cmdBackupFolder;
|
||||||
|
private System.Windows.Forms.TextBox txtBackupFolder;
|
||||||
|
private System.Windows.Forms.Label label6;
|
||||||
|
private System.Windows.Forms.Label label7;
|
||||||
|
private System.Windows.Forms.LinkLabel CapstoneLink;
|
||||||
|
private System.Windows.Forms.Label label8;
|
||||||
|
private System.Windows.Forms.LinkLabel CapstoneNetLink;
|
||||||
|
private System.Windows.Forms.Label label10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public partial class MainForm : Form
|
||||||
|
{
|
||||||
|
private PatchEngine PatchEngine = null;
|
||||||
|
|
||||||
|
public MainForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
LoadPaths();
|
||||||
|
CenterToScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
txtVisualStudioPath.Text = (string)Key.GetValue("VisualStudioPath", "");
|
||||||
|
if (txtVisualStudioPath.Text.Length == 0)
|
||||||
|
txtVisualStudioPath.Text = FindVisualStudioPath();
|
||||||
|
|
||||||
|
txtPatchDefinitionsFile.Text = (string)Key.GetValue("PatchDefinitionsFilePath", "");
|
||||||
|
txtScriptFile.Text = (string)Key.GetValue("ScriptFilePath", "");
|
||||||
|
txtInputFolder.Text = (string)Key.GetValue("InputFolderPath", "");
|
||||||
|
txtOutputFolder.Text = (string)Key.GetValue("OutputFolderPath", "");
|
||||||
|
txtBackupFolder.Text = (string)Key.GetValue("BackupFolderPath", "");
|
||||||
|
|
||||||
|
LoadPatchDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] FindMSVCBinaryPaths(string s)
|
||||||
|
{
|
||||||
|
string LegacyPath = Path.Combine(s, @"VC\bin");
|
||||||
|
if (Directory.Exists(LegacyPath))
|
||||||
|
{
|
||||||
|
return new string[] { LegacyPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC")))
|
||||||
|
{
|
||||||
|
IEnumerable<string> MSVCs = Directory.EnumerateDirectories(Path.Combine(s, @"VC\Tools\MSVC"));
|
||||||
|
IEnumerable<string> Bins = MSVCs.Select(s => Path.Combine(s, "bin")).Where(s => Directory.Exists(s));
|
||||||
|
return Bins.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindArmAsmPath(string s)
|
||||||
|
{
|
||||||
|
foreach (string MSVCBin in FindMSVCBinaryPaths(s))
|
||||||
|
{
|
||||||
|
string path1 = Path.Combine(MSVCBin, "x86_arm");
|
||||||
|
string path2 = Path.Combine(MSVCBin, @"Hostx86\arm");
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path1, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path2, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindVisualStudioPath()
|
||||||
|
{
|
||||||
|
IEnumerable<string> MainX86VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files (x86)\", "Microsoft Visual Studio*");
|
||||||
|
IEnumerable<string> MainX64VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files\", "Microsoft Visual Studio*");
|
||||||
|
|
||||||
|
IEnumerable<string> MainVSDirectories = MainX86VSDirectories.Union(MainX64VSDirectories);
|
||||||
|
|
||||||
|
IEnumerable<string> SubMainVSDirectories = MainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> SubSubMainVSDirectories = SubMainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> Directories = MainVSDirectories.Union(SubMainVSDirectories).Union(SubSubMainVSDirectories);
|
||||||
|
|
||||||
|
string attempt1 = Directories.Where(s => FindArmAsmPath(s) != "").OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"VC\bin\x86_arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
|
||||||
|
if (attempt1 != "")
|
||||||
|
return attempt1;
|
||||||
|
|
||||||
|
return Directories.Where(s => Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC"))).Select(s => Path.Combine(s, @"VC\Tools\MSVC")).SelectMany(s => Directory.EnumerateDirectories(s)).Where(s => File.Exists(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StorePaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
string VisualStudioPath = txtVisualStudioPath.Text.Trim();
|
||||||
|
if (VisualStudioPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("VisualStudioPath") != null)
|
||||||
|
Key.DeleteValue("VisualStudioPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("VisualStudioPath", VisualStudioPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string PatchDefinitionsFilePath = txtPatchDefinitionsFile.Text.Trim();
|
||||||
|
if (PatchDefinitionsFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("PatchDefinitionsFilePath") != null)
|
||||||
|
Key.DeleteValue("PatchDefinitionsFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("PatchDefinitionsFilePath", PatchDefinitionsFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string ScriptFilePath = txtScriptFile.Text.Trim();
|
||||||
|
if (ScriptFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("ScriptFilePath") != null)
|
||||||
|
Key.DeleteValue("ScriptFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("ScriptFilePath", ScriptFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string InputFolderPath = txtInputFolder.Text.Trim();
|
||||||
|
if (InputFolderPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("InputFolderPath") != null)
|
||||||
|
Key.DeleteValue("InputFolderPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("InputFolderPath", InputFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string OutputFolderPath = txtOutputFolder.Text.Trim();
|
||||||
|
if (OutputFolderPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("OutputFolderPath") != null)
|
||||||
|
Key.DeleteValue("OutputFolderPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("OutputFolderPath", OutputFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string BackupFolderPath = txtBackupFolder.Text.Trim();
|
||||||
|
if (BackupFolderPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("BackupFolderPath") != null)
|
||||||
|
Key.DeleteValue("BackupFolderPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("BackupFolderPath", BackupFolderPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LoadingPatchDefinitions = false;
|
||||||
|
|
||||||
|
private void LoadPatchDefinitions()
|
||||||
|
{
|
||||||
|
if (LoadingPatchDefinitions)
|
||||||
|
return;
|
||||||
|
LoadingPatchDefinitions = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string Definitions = File.ReadAllText(txtPatchDefinitionsFile.Text);
|
||||||
|
PatchEngine = new PatchEngine(Definitions);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
PatchEngine = new PatchEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadingPatchDefinitions = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdVisualStudioPath_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderBrowserDialog.SelectedPath = txtVisualStudioPath.Text;
|
||||||
|
FolderBrowserDialog.Description = "Select path to Visual Studio with ARM32 SDK";
|
||||||
|
System.Windows.Forms.DialogResult Result = FolderBrowserDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
txtVisualStudioPath.Text = FolderBrowserDialog.SelectedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatchDefinitionsFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = false;
|
||||||
|
OpenFileDialog.DefaultExt = "xml";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtPatchDefinitionsFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open patch-definitions file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtPatchDefinitionsFile.Text = OpenFileDialog.FileName;
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void txtPatchDefinitionsFile_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||||
|
{
|
||||||
|
StorePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdInputFolder_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderSelectDialog Dialog = new();
|
||||||
|
Dialog.Title = "Select input location";
|
||||||
|
Dialog.InitialDirectory = txtInputFolder.Text;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dialog.InitialDirectory = txtInputFolder.Text;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
bool Result = Dialog.ShowDialog();
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
txtInputFolder.Text = Dialog.FileName;
|
||||||
|
txtOutputFolder.Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdOutputFolder_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderSelectDialog Dialog = new();
|
||||||
|
Dialog.Title = "Select output location";
|
||||||
|
Dialog.InitialDirectory = txtOutputFolder.Text;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dialog.InitialDirectory = txtOutputFolder.Text;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
bool Result = Dialog.ShowDialog();
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
txtOutputFolder.Text = Dialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdScriptFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = true;
|
||||||
|
OpenFileDialog.DefaultExt = "pds";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtScriptFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtScriptFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open patch-definition-script-file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtScriptFile.Text = OpenFileDialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdCompile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
ClearLog();
|
||||||
|
StorePaths();
|
||||||
|
ScriptEngine.ExecuteScript(txtVisualStudioPath.Text.Trim(), txtScriptFile.Text.Trim(), txtInputFolder.Text.Trim(), PatchEngine: PatchEngine, WriteLog: WriteLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatch_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
ClearLog();
|
||||||
|
StorePaths();
|
||||||
|
ScriptEngine.ExecuteScript(txtVisualStudioPath.Text.Trim(), txtScriptFile.Text.Trim(), txtInputFolder.Text.Trim(), PatchEngine, txtOutputFolder.Text.Trim(), txtBackupFolder.Text.Trim().Length == 0 ? null : txtBackupFolder.Text.Trim(), WriteLog);
|
||||||
|
|
||||||
|
PatchEngine.WriteDefinitions(txtPatchDefinitionsFile.Text);
|
||||||
|
WriteLog("Patch-definitions written to: " + txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearLog()
|
||||||
|
{
|
||||||
|
txtConsole.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteLog(string Line)
|
||||||
|
{
|
||||||
|
if (txtConsole.InvokeRequired)
|
||||||
|
{
|
||||||
|
txtConsole.Invoke((MethodInvoker)delegate { WriteLog(Line); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txtConsole.AppendText(Line + Environment.NewLine);
|
||||||
|
txtConsole.Select(txtConsole.Text.Length, 0);
|
||||||
|
txtConsole.ScrollToCaret();
|
||||||
|
System.Diagnostics.Debug.WriteLine(Line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdBackupFolder_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderSelectDialog Dialog = new();
|
||||||
|
Dialog.Title = "Select backup location";
|
||||||
|
Dialog.InitialDirectory = txtBackupFolder.Text;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dialog.InitialDirectory = txtBackupFolder.Text;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
bool Result = Dialog.ShowDialog();
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
txtBackupFolder.Text = Dialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CapstoneLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Process.Start("https://github.com/aquynh/capstone/blob/master/LICENSE.TXT");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CapstoneNetLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Process.Start("https://github.com/9ee1/Capstone.NET/blob/master/LICENSE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="OpenFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>182, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="SaveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>317, 17</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("AutoPatcher")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("AutoPatcher")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("95cf9509-c1c4-40f5-a60e-9d93ea6f438c")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Patcher.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.28010.2041
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Patcher", "Patcher\Patcher.csproj", "{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoPatcher", "AutoPatcher\AutoPatcher.csproj", "{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
.NET45Debug|Any CPU = .NET45Debug|Any CPU
|
||||||
|
.NET45Debug|x64 = .NET45Debug|x64
|
||||||
|
.NET45Debug|x86 = .NET45Debug|x86
|
||||||
|
.NET45Release|Any CPU = .NET45Release|Any CPU
|
||||||
|
.NET45Release|x64 = .NET45Release|x64
|
||||||
|
.NET45Release|x86 = .NET45Release|x86
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x64.Build.0 = Debug|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Debug|x86.Build.0 = Debug|x86
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x64.ActiveCfg = Release|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x64.Build.0 = Release|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.ActiveCfg = Release|x86
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}..NET45Release|x86.Build.0 = Release|x86
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x64.Build.0 = Release|x64
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B67C62AE-86C4-4C18-99AB-4E94A3E09D36}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x64.Build.0 = Debug|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Debug|x86.Build.0 = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x64.ActiveCfg = Release|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x64.Build.0 = Release|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.ActiveCfg = Release|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}..NET45Release|x86.Build.0 = Release|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x64.Build.0 = Release|x64
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{95CF9509-C1C4-40F5-A60E-9D93EA6F438C}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {6763D5C5-7BCE-437C-9FD0-67BDD8D79FD2}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public enum CodeType
|
||||||
|
{
|
||||||
|
ARM,
|
||||||
|
Thumb,
|
||||||
|
Thumb2
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArmCompiler
|
||||||
|
{
|
||||||
|
public static Int32 LastErrorCode;
|
||||||
|
public static string Output;
|
||||||
|
|
||||||
|
public static byte[] Compile(string PathToVisualStudio, UInt32 Origin, CodeType CodeType, string ArmCodeFragment)
|
||||||
|
{
|
||||||
|
if (PathToVisualStudio.Length == 0)
|
||||||
|
{
|
||||||
|
Output = "ARM SDK is missing.";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string AssemblyFilePath = Path.GetTempFileName();
|
||||||
|
string ObjectFilePathTmp = Path.GetTempFileName();
|
||||||
|
string ObjectFilePath = ObjectFilePathTmp.Replace(".tmp", ".obj");
|
||||||
|
File.Move(ObjectFilePathTmp, ObjectFilePath);
|
||||||
|
|
||||||
|
string CodeTypeDirective = null;
|
||||||
|
switch (CodeType)
|
||||||
|
{
|
||||||
|
case Patcher.CodeType.ARM:
|
||||||
|
CodeTypeDirective = "CODE32";
|
||||||
|
break;
|
||||||
|
case Patcher.CodeType.Thumb:
|
||||||
|
CodeTypeDirective = "CODE16";
|
||||||
|
break;
|
||||||
|
case Patcher.CodeType.Thumb2:
|
||||||
|
CodeTypeDirective = "THUMB";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string FullAssemblyCode =
|
||||||
|
" AREA ARM_AREA, CODE, READONLY" + Environment.NewLine +
|
||||||
|
" " + CodeTypeDirective + Environment.NewLine;
|
||||||
|
|
||||||
|
string ProcessedAssembly = ProcessArmCodeFragment(ArmCodeFragment, Origin, out uint Padding);
|
||||||
|
|
||||||
|
if (Padding > 0)
|
||||||
|
FullAssemblyCode += " SPACE " + Padding.ToString() + Environment.NewLine;
|
||||||
|
|
||||||
|
FullAssemblyCode +=
|
||||||
|
"start" + Environment.NewLine +
|
||||||
|
ProcessedAssembly;
|
||||||
|
|
||||||
|
FullAssemblyCode += " end" + Environment.NewLine;
|
||||||
|
|
||||||
|
File.WriteAllText(AssemblyFilePath, FullAssemblyCode);
|
||||||
|
|
||||||
|
string ArmAsmPath = MainForm.FindArmAsmPath(PathToVisualStudio);
|
||||||
|
string BinPath = MainForm.FindMSVCBinaryPaths(PathToVisualStudio).FirstOrDefault() ?? "";
|
||||||
|
ProcessStartInfo psi = new(Path.Combine(ArmAsmPath, "armasm.exe"));
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + Path.Combine(PathToVisualStudio, @"Common7\IDE\");
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + Path.Combine(PathToVisualStudio, @"Common7\Tools\");
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + BinPath;
|
||||||
|
psi.EnvironmentVariables["PATH"] += ";" + ArmAsmPath;
|
||||||
|
psi.UseShellExecute = false;
|
||||||
|
psi.RedirectStandardOutput = true;
|
||||||
|
psi.CreateNoWindow = true;
|
||||||
|
psi.Arguments = "-g \"" + AssemblyFilePath + "\" \"" + ObjectFilePath + "\"";
|
||||||
|
Process ArmAsmProcess = Process.Start(psi);
|
||||||
|
ArmAsmProcess.WaitForExit();
|
||||||
|
LastErrorCode = ArmAsmProcess.ExitCode;
|
||||||
|
if (ArmAsmProcess.ExitCode != 0)
|
||||||
|
{
|
||||||
|
using StreamReader reader = ArmAsmProcess.StandardOutput;
|
||||||
|
Output = reader.ReadToEnd();
|
||||||
|
|
||||||
|
string[] Lines = Output.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
Output = "";
|
||||||
|
|
||||||
|
foreach (string Line in Lines)
|
||||||
|
{
|
||||||
|
string Out = Line.Trim();
|
||||||
|
if (Out.Length == 0) continue;
|
||||||
|
if (Out.StartsWith("Microsoft (R) ARM Macro Assembler")) continue;
|
||||||
|
if (Out.StartsWith("Copyright (C) Microsoft Corporation")) continue;
|
||||||
|
if (Out.StartsWith(AssemblyFilePath))
|
||||||
|
{
|
||||||
|
Out = Out[AssemblyFilePath.Length..];
|
||||||
|
int P = Out.IndexOf(':');
|
||||||
|
Out = Out[(P + 1)..].Trim();
|
||||||
|
}
|
||||||
|
Output += Out + Environment.NewLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Result = null;
|
||||||
|
|
||||||
|
if (LastErrorCode == 0)
|
||||||
|
Result = COFF.ObjectFileParser.ParseObjectFile(ObjectFilePath).SectionHeaders.First(h => h.Name == "ARM_AREA").RawData;
|
||||||
|
|
||||||
|
File.Delete(AssemblyFilePath);
|
||||||
|
File.Delete(ObjectFilePath);
|
||||||
|
|
||||||
|
if ((Result != null) && (Padding > 0))
|
||||||
|
{
|
||||||
|
byte[] RemovedPadding = new byte[Result.Length - Padding];
|
||||||
|
Buffer.BlockCopy(Result, (int)Padding, RemovedPadding, 0, RemovedPadding.Length);
|
||||||
|
Result = RemovedPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ProcessArmCodeFragment(string ArmCodeFragment, UInt32 Origin, out UInt32 Padding)
|
||||||
|
{
|
||||||
|
string[] BranchOpcodes = new string[] { "B", "BEQ", "BNE", "BCS", "BHS", "BCC", "BLO", "BMI", "BPL", "BVS", "BVC", "BHI", "BLS", "BGE", "BLT", "BGT", "BLE", "BAL"};
|
||||||
|
|
||||||
|
StringBuilder Result = new(1000);
|
||||||
|
Padding = 0;
|
||||||
|
|
||||||
|
string[] Lines = ArmCodeFragment.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||||
|
List<Tuple<string, string>> Labels = new();
|
||||||
|
|
||||||
|
foreach (string Line in Lines)
|
||||||
|
{
|
||||||
|
string Code = Line;
|
||||||
|
if (Line.Contains(':'))
|
||||||
|
{
|
||||||
|
string Label = Line.Substring(0, Line.IndexOf(':'));
|
||||||
|
Label = Label.Trim();
|
||||||
|
if (Label.Length > 0)
|
||||||
|
Result.AppendLine(Label);
|
||||||
|
Code = Line[(Line.IndexOf(':') + 1)..];
|
||||||
|
}
|
||||||
|
|
||||||
|
int EquPos = Code.IndexOf("EQU", StringComparison.OrdinalIgnoreCase);
|
||||||
|
if ((EquPos > 0) && (EquPos > 0) && (EquPos < (Code.Length - 3)))
|
||||||
|
{
|
||||||
|
if (new char[] { '\t', ' ' }.Contains(Line[EquPos - 1]) &&
|
||||||
|
new char[] { '\t', ' ' }.Contains(Line[EquPos + 3]))
|
||||||
|
{
|
||||||
|
Result.AppendLine(Line.Trim());
|
||||||
|
Labels.Add(new Tuple<string, string>(Line.Substring(0, EquPos).Trim(), Line[(EquPos + 3)..].Trim()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Code = Code.Trim();
|
||||||
|
|
||||||
|
bool IsAbsoluteAddress = false;
|
||||||
|
|
||||||
|
int OpcodeLength = Code.IndexOfAny(new char [] { '\t', ' ', '.' });
|
||||||
|
if (OpcodeLength > 0)
|
||||||
|
{
|
||||||
|
string Opcode = Code.Substring(0, OpcodeLength).ToUpper();
|
||||||
|
|
||||||
|
string PossibleAddress = null;
|
||||||
|
|
||||||
|
if (Opcode == "LDR")
|
||||||
|
{
|
||||||
|
PossibleAddress = Code[(Code.IndexOf(',') + 1)..].Trim();
|
||||||
|
}
|
||||||
|
else if (BranchOpcodes.Contains(Opcode))
|
||||||
|
{
|
||||||
|
PossibleAddress = Code[(Code.IndexOfAny(new char[] { '\t', ' ' }) + 1)..].Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PossibleAddress != null)
|
||||||
|
{
|
||||||
|
foreach (Tuple<string, string> Label in Labels)
|
||||||
|
{
|
||||||
|
if (string.Equals(Label.Item1, PossibleAddress, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
PossibleAddress = Label.Item2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PossibleAddress.StartsWith("0x"))
|
||||||
|
PossibleAddress = PossibleAddress[2..];
|
||||||
|
IsAbsoluteAddress = UInt32.TryParse(PossibleAddress, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out uint ParsedValue);
|
||||||
|
if (IsAbsoluteAddress && (ParsedValue < Origin))
|
||||||
|
Padding = Math.Max(Padding, Origin - ParsedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result.Append(' ');
|
||||||
|
Result.Append(Code);
|
||||||
|
if (IsAbsoluteAddress)
|
||||||
|
{
|
||||||
|
Result.Append(" + start - 0x");
|
||||||
|
Result.Append(Origin.ToString("X8"));
|
||||||
|
}
|
||||||
|
Result.Append(Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,382 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
internal static class ByteOperations
|
||||||
|
{
|
||||||
|
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
UInt32 Length = 0;
|
||||||
|
while (((Offset + Length) < ByteArray.Length) && (ByteArray[Offset + Length] != 0))
|
||||||
|
Length++;
|
||||||
|
byte[] Bytes = new byte[Length];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||||
|
return System.Text.Encoding.ASCII.GetString(Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||||
|
{
|
||||||
|
byte[] Bytes = new byte[Length];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||||
|
return System.Text.Encoding.ASCII.GetString(Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ReadUnicodeString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||||
|
{
|
||||||
|
byte[] Bytes = new byte[Length];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||||
|
return System.Text.Encoding.Unicode.GetString(Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
|
||||||
|
{
|
||||||
|
if (MaxBufferLength != null)
|
||||||
|
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
|
||||||
|
|
||||||
|
byte[] TextBytes = System.Text.UnicodeEncoding.Unicode.GetBytes(Text);
|
||||||
|
int WriteLength = TextBytes.Length;
|
||||||
|
if (WriteLength > MaxBufferLength)
|
||||||
|
WriteLength = (int)MaxBufferLength;
|
||||||
|
|
||||||
|
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32 ReadUInt32(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToUInt32(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt32(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Int32 ReadInt32(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToInt32(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteInt32(byte[] ByteArray, UInt32 Offset, Int32 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt16 ReadUInt16(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToUInt16(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt16(byte[] ByteArray, UInt32 Offset, UInt16 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Int16 ReadInt16(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToInt16(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteInt16(byte[] ByteArray, UInt32 Offset, Int16 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static byte ReadUInt8(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
return ByteArray[Offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt8(byte[] ByteArray, UInt32 Offset, byte Value)
|
||||||
|
{
|
||||||
|
ByteArray[Offset] = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32 ReadUInt24(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
return (UInt32)(ByteArray[Offset] + (ByteArray[Offset + 1] << 8) + (ByteArray[Offset + 2] << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt24(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt64 ReadUInt64(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
// Assume CPU and FFU are both Little Endian
|
||||||
|
return BitConverter.ToUInt64(ByteArray, (int)Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteUInt64(byte[] ByteArray, UInt32 Offset, UInt64 Value)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Guid ReadGuid(byte[] ByteArray, UInt32 Offset)
|
||||||
|
{
|
||||||
|
byte[] GuidBuffer = new byte[0x10];
|
||||||
|
Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10);
|
||||||
|
return new Guid(GuidBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteGuid(byte[] ByteArray, UInt32 Offset, Guid Value)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment)
|
||||||
|
{
|
||||||
|
if (((Offset - Base) % Alignment) == 0)
|
||||||
|
return Offset;
|
||||||
|
else
|
||||||
|
return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern)
|
||||||
|
{
|
||||||
|
// The mask is optional.
|
||||||
|
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||||
|
|
||||||
|
UInt32? Result = null;
|
||||||
|
|
||||||
|
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
byte[] Buffer = new byte[0x10000 + Pattern.Length - 1];
|
||||||
|
UInt32 BytesInBuffer = 0;
|
||||||
|
UInt32 BytesRead;
|
||||||
|
UInt32 SearchPositionFile = 0;
|
||||||
|
UInt32 SearchPositionBuffer = 0;
|
||||||
|
UInt32 BufferFileOffset = 0; // Offset in file where data from buffer is located.
|
||||||
|
int i;
|
||||||
|
|
||||||
|
OutPattern = null;
|
||||||
|
|
||||||
|
while (SearchPositionFile <= (Stream.Length - Pattern.Length))
|
||||||
|
{
|
||||||
|
if ((SearchPositionBuffer + Pattern.Length) > BytesInBuffer)
|
||||||
|
{
|
||||||
|
// Need to read next chunk
|
||||||
|
if ((BytesInBuffer - SearchPositionBuffer) > 0)
|
||||||
|
{
|
||||||
|
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, Buffer, 0, (int)(BytesInBuffer - SearchPositionBuffer));
|
||||||
|
}
|
||||||
|
uint BufferReadPosition = BytesInBuffer - SearchPositionBuffer;
|
||||||
|
BytesInBuffer -= SearchPositionBuffer;
|
||||||
|
BufferFileOffset += SearchPositionBuffer;
|
||||||
|
SearchPositionBuffer = 0;
|
||||||
|
|
||||||
|
BytesRead = (UInt32)Stream.Read(Buffer, (int)BufferReadPosition, Buffer.Length - (int)BufferReadPosition);
|
||||||
|
BytesInBuffer += BytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Match = true;
|
||||||
|
for (i = 0; i < Pattern.Length; i++)
|
||||||
|
{
|
||||||
|
if (Buffer[SearchPositionBuffer + i] != Pattern[i])
|
||||||
|
{
|
||||||
|
if ((Mask == null) || (Mask[i] == 0))
|
||||||
|
{
|
||||||
|
Match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Match)
|
||||||
|
{
|
||||||
|
Result = SearchPositionFile;
|
||||||
|
|
||||||
|
OutPattern = new byte[Pattern.Length];
|
||||||
|
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, OutPattern, 0, Pattern.Length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPositionBuffer++;
|
||||||
|
SearchPositionFile++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.Close();
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, System.Text.ASCIIEncoding.ASCII.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindAscii(byte[] SourceBuffer, uint SourceOffset, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, SourceOffset, null, System.Text.ASCIIEncoding.ASCII.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, System.Text.UnicodeEncoding.Unicode.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindUnicode(byte[] SourceBuffer, uint SourceOffset, string Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, SourceOffset, null, System.Text.UnicodeEncoding.Unicode.GetBytes((string)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, BitConverter.GetBytes((UInt32)Pattern), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||||
|
{
|
||||||
|
return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt32? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||||
|
{
|
||||||
|
// The mask is optional.
|
||||||
|
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||||
|
|
||||||
|
UInt32? Result = null;
|
||||||
|
|
||||||
|
UInt32 SearchPosition = SourceOffset;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while ((SearchPosition <= (SourceBuffer.Length - Pattern.Length)) && ((SourceSize == null) || (SearchPosition <= (SourceOffset + SourceSize - Pattern.Length))))
|
||||||
|
{
|
||||||
|
bool Match = true;
|
||||||
|
for (i = 0; i < Pattern.Length; i++)
|
||||||
|
{
|
||||||
|
if (SourceBuffer[SearchPosition + i] != Pattern[i])
|
||||||
|
{
|
||||||
|
if ((Mask == null) || (Mask[i] == 0))
|
||||||
|
{
|
||||||
|
Match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Match)
|
||||||
|
{
|
||||||
|
Result = SearchPosition;
|
||||||
|
|
||||||
|
if (OutPattern != null)
|
||||||
|
System.Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static byte CalculateChecksum8(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||||
|
{
|
||||||
|
byte Checksum = 0;
|
||||||
|
|
||||||
|
for (UInt32 i = Offset; i < (Offset + Size); i++)
|
||||||
|
Checksum += Buffer[i];
|
||||||
|
|
||||||
|
return (byte)(0x100 - Checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static UInt16 CalculateChecksum16(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||||
|
{
|
||||||
|
UInt16 Checksum = 0;
|
||||||
|
|
||||||
|
for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2)
|
||||||
|
Checksum += BitConverter.ToUInt16(Buffer, (int)i);
|
||||||
|
|
||||||
|
return (UInt16)(0x10000 - Checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly UInt32[] CRC32Table = new UInt32[] {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length)
|
||||||
|
{
|
||||||
|
if ((Input == null) || ((Offset + Length) > Input.Length))
|
||||||
|
throw new ArgumentException();
|
||||||
|
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
uint crc = (uint)(((uint)0) ^ (-1));
|
||||||
|
for (var i = Offset; i < (Offset + Length); i++)
|
||||||
|
{
|
||||||
|
crc = (crc >> 8) ^ CRC32Table[ (crc ^ Input[i]) & 0xFF ];
|
||||||
|
}
|
||||||
|
crc = (uint)(crc ^ (-1));
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
public static class Converter
|
||||||
|
{
|
||||||
|
public static string ConvertHexToString(byte[] Bytes, string Separator)
|
||||||
|
{
|
||||||
|
StringBuilder s = new(1000);
|
||||||
|
for (int i = Bytes.GetLowerBound(0); i <= Bytes.GetUpperBound(0); i++)
|
||||||
|
{
|
||||||
|
if (i != Bytes.GetLowerBound(0))
|
||||||
|
s.Append(Separator);
|
||||||
|
s.Append(Bytes[i].ToString("X2"));
|
||||||
|
}
|
||||||
|
return s.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ConvertStringToHex(string HexString)
|
||||||
|
{
|
||||||
|
if (HexString.Length % 2 == 1)
|
||||||
|
throw new Exception("The binary key cannot have an odd number of digits");
|
||||||
|
|
||||||
|
byte[] arr = new byte[HexString.Length >> 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < (HexString.Length >> 1); ++i)
|
||||||
|
{
|
||||||
|
arr[i] = (byte)((GetHexVal(HexString[i << 1]) << 4) + GetHexVal(HexString[(i << 1) + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetHexVal(char hex)
|
||||||
|
{
|
||||||
|
int val = (int)hex;
|
||||||
|
//For uppercase A-F letters:
|
||||||
|
//return val - (val < 58 ? 48 : 55);
|
||||||
|
//For lowercase a-f letters:
|
||||||
|
//return val - (val < 58 ? 48 : 87);
|
||||||
|
//Or the two combined, but a bit slower:
|
||||||
|
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Generated
+426
@@ -0,0 +1,426 @@
|
|||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
partial class MainForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.txtVisualStudioPath = new System.Windows.Forms.TextBox();
|
||||||
|
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||||
|
this.OpenFileDialog = new System.Windows.Forms.OpenFileDialog();
|
||||||
|
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||||
|
this.cmdVisualStudioPath = new System.Windows.Forms.Button();
|
||||||
|
this.cmdInputFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtInputFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdOutputFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtOutputFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdPatchDefinitionsFile = new System.Windows.Forms.Button();
|
||||||
|
this.txtPatchDefinitionsFile = new System.Windows.Forms.TextBox();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.label5 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbPatchDefinitionName = new System.Windows.Forms.ComboBox();
|
||||||
|
this.cmbTargetVersion = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label6 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbTargetPath = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
|
this.label8 = new System.Windows.Forms.Label();
|
||||||
|
this.txtAssemblyCode = new System.Windows.Forms.TextBox();
|
||||||
|
this.txtCompiledOpcodes = new System.Windows.Forms.TextBox();
|
||||||
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
|
this.txtVirtualOffset = new System.Windows.Forms.TextBox();
|
||||||
|
this.label10 = new System.Windows.Forms.Label();
|
||||||
|
this.cmbCodeType = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label11 = new System.Windows.Forms.Label();
|
||||||
|
this.cmdCompile = new System.Windows.Forms.Button();
|
||||||
|
this.cmdPatch = new System.Windows.Forms.Button();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Location = new System.Drawing.Point(15, 13);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(191, 13);
|
||||||
|
this.label1.TabIndex = 0;
|
||||||
|
this.label1.Text = "Path to Visual Studio with ARM32 SDK";
|
||||||
|
//
|
||||||
|
// txtVisualStudioPath
|
||||||
|
//
|
||||||
|
this.txtVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtVisualStudioPath.Location = new System.Drawing.Point(18, 29);
|
||||||
|
this.txtVisualStudioPath.Name = "txtVisualStudioPath";
|
||||||
|
this.txtVisualStudioPath.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtVisualStudioPath.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// OpenFileDialog
|
||||||
|
//
|
||||||
|
this.OpenFileDialog.FileName = "openFileDialog1";
|
||||||
|
//
|
||||||
|
// cmdVisualStudioPath
|
||||||
|
//
|
||||||
|
this.cmdVisualStudioPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdVisualStudioPath.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdVisualStudioPath.Location = new System.Drawing.Point(689, 28);
|
||||||
|
this.cmdVisualStudioPath.Name = "cmdVisualStudioPath";
|
||||||
|
this.cmdVisualStudioPath.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdVisualStudioPath.TabIndex = 2;
|
||||||
|
this.cmdVisualStudioPath.Text = "...";
|
||||||
|
this.cmdVisualStudioPath.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdVisualStudioPath.Click += new System.EventHandler(this.cmdVisualStudioPath_Click);
|
||||||
|
//
|
||||||
|
// cmdInputFile
|
||||||
|
//
|
||||||
|
this.cmdInputFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdInputFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdInputFile.Location = new System.Drawing.Point(689, 301);
|
||||||
|
this.cmdInputFile.Name = "cmdInputFile";
|
||||||
|
this.cmdInputFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdInputFile.TabIndex = 14;
|
||||||
|
this.cmdInputFile.Text = "...";
|
||||||
|
this.cmdInputFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdInputFile.Click += new System.EventHandler(this.cmdInputFile_Click);
|
||||||
|
//
|
||||||
|
// txtInputFile
|
||||||
|
//
|
||||||
|
this.txtInputFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtInputFile.Location = new System.Drawing.Point(18, 302);
|
||||||
|
this.txtInputFile.Name = "txtInputFile";
|
||||||
|
this.txtInputFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtInputFile.TabIndex = 13;
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Location = new System.Drawing.Point(15, 286);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(47, 13);
|
||||||
|
this.label2.TabIndex = 12;
|
||||||
|
this.label2.Text = "Input file";
|
||||||
|
//
|
||||||
|
// cmdOutputFile
|
||||||
|
//
|
||||||
|
this.cmdOutputFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdOutputFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdOutputFile.Location = new System.Drawing.Point(689, 349);
|
||||||
|
this.cmdOutputFile.Name = "cmdOutputFile";
|
||||||
|
this.cmdOutputFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdOutputFile.TabIndex = 17;
|
||||||
|
this.cmdOutputFile.Text = "...";
|
||||||
|
this.cmdOutputFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdOutputFile.Click += new System.EventHandler(this.cmdOutputFile_Click);
|
||||||
|
//
|
||||||
|
// txtOutputFile
|
||||||
|
//
|
||||||
|
this.txtOutputFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtOutputFile.Location = new System.Drawing.Point(18, 350);
|
||||||
|
this.txtOutputFile.Name = "txtOutputFile";
|
||||||
|
this.txtOutputFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtOutputFile.TabIndex = 16;
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(15, 334);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(101, 13);
|
||||||
|
this.label3.TabIndex = 15;
|
||||||
|
this.label3.Text = "Output file (optional)";
|
||||||
|
//
|
||||||
|
// cmdPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.cmdPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatchDefinitionsFile.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.cmdPatchDefinitionsFile.Location = new System.Drawing.Point(689, 91);
|
||||||
|
this.cmdPatchDefinitionsFile.Name = "cmdPatchDefinitionsFile";
|
||||||
|
this.cmdPatchDefinitionsFile.Size = new System.Drawing.Size(35, 22);
|
||||||
|
this.cmdPatchDefinitionsFile.TabIndex = 5;
|
||||||
|
this.cmdPatchDefinitionsFile.Text = "...";
|
||||||
|
this.cmdPatchDefinitionsFile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatchDefinitionsFile.Click += new System.EventHandler(this.cmdPatchDefinitionsFile_Click);
|
||||||
|
//
|
||||||
|
// txtPatchDefinitionsFile
|
||||||
|
//
|
||||||
|
this.txtPatchDefinitionsFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtPatchDefinitionsFile.Location = new System.Drawing.Point(18, 92);
|
||||||
|
this.txtPatchDefinitionsFile.Name = "txtPatchDefinitionsFile";
|
||||||
|
this.txtPatchDefinitionsFile.Size = new System.Drawing.Size(665, 20);
|
||||||
|
this.txtPatchDefinitionsFile.TabIndex = 4;
|
||||||
|
this.txtPatchDefinitionsFile.Leave += new System.EventHandler(this.txtPatchDefinitionsFile_Leave);
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(15, 76);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(117, 13);
|
||||||
|
this.label4.TabIndex = 3;
|
||||||
|
this.label4.Text = "Patch defintions xml-file";
|
||||||
|
//
|
||||||
|
// label5
|
||||||
|
//
|
||||||
|
this.label5.AutoSize = true;
|
||||||
|
this.label5.Location = new System.Drawing.Point(15, 124);
|
||||||
|
this.label5.Name = "label5";
|
||||||
|
this.label5.Size = new System.Drawing.Size(107, 13);
|
||||||
|
this.label5.TabIndex = 6;
|
||||||
|
this.label5.Text = "Patch defintion name";
|
||||||
|
//
|
||||||
|
// cmbPatchDefinitionName
|
||||||
|
//
|
||||||
|
this.cmbPatchDefinitionName.FormattingEnabled = true;
|
||||||
|
this.cmbPatchDefinitionName.Location = new System.Drawing.Point(18, 140);
|
||||||
|
this.cmbPatchDefinitionName.Name = "cmbPatchDefinitionName";
|
||||||
|
this.cmbPatchDefinitionName.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbPatchDefinitionName.TabIndex = 7;
|
||||||
|
this.cmbPatchDefinitionName.SelectedValueChanged += new System.EventHandler(this.cmbPatchDefinitionName_SelectedValueChanged);
|
||||||
|
this.cmbPatchDefinitionName.Leave += new System.EventHandler(this.cmbPatchDefinitionName_Leave);
|
||||||
|
//
|
||||||
|
// cmbTargetVersion
|
||||||
|
//
|
||||||
|
this.cmbTargetVersion.FormattingEnabled = true;
|
||||||
|
this.cmbTargetVersion.Location = new System.Drawing.Point(18, 189);
|
||||||
|
this.cmbTargetVersion.Name = "cmbTargetVersion";
|
||||||
|
this.cmbTargetVersion.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbTargetVersion.TabIndex = 9;
|
||||||
|
this.cmbTargetVersion.SelectedValueChanged += new System.EventHandler(this.cmbTargetVersion_SelectedValueChanged);
|
||||||
|
this.cmbTargetVersion.Leave += new System.EventHandler(this.cmbTargetVersion_Leave);
|
||||||
|
//
|
||||||
|
// label6
|
||||||
|
//
|
||||||
|
this.label6.AutoSize = true;
|
||||||
|
this.label6.Location = new System.Drawing.Point(15, 173);
|
||||||
|
this.label6.Name = "label6";
|
||||||
|
this.label6.Size = new System.Drawing.Size(129, 13);
|
||||||
|
this.label6.TabIndex = 8;
|
||||||
|
this.label6.Text = "Target version description";
|
||||||
|
//
|
||||||
|
// cmbTargetPath
|
||||||
|
//
|
||||||
|
this.cmbTargetPath.FormattingEnabled = true;
|
||||||
|
this.cmbTargetPath.Location = new System.Drawing.Point(18, 238);
|
||||||
|
this.cmbTargetPath.Name = "cmbTargetPath";
|
||||||
|
this.cmbTargetPath.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbTargetPath.TabIndex = 11;
|
||||||
|
//
|
||||||
|
// label7
|
||||||
|
//
|
||||||
|
this.label7.AutoSize = true;
|
||||||
|
this.label7.Location = new System.Drawing.Point(15, 222);
|
||||||
|
this.label7.Name = "label7";
|
||||||
|
this.label7.Size = new System.Drawing.Size(269, 13);
|
||||||
|
this.label7.TabIndex = 10;
|
||||||
|
this.label7.Text = "Folder for target file relative to Patch Defintion rootfolder";
|
||||||
|
//
|
||||||
|
// label8
|
||||||
|
//
|
||||||
|
this.label8.AutoSize = true;
|
||||||
|
this.label8.Location = new System.Drawing.Point(15, 497);
|
||||||
|
this.label8.Name = "label8";
|
||||||
|
this.label8.Size = new System.Drawing.Size(365, 13);
|
||||||
|
this.label8.TabIndex = 22;
|
||||||
|
this.label8.Text = "ARM32 Patch / Shell assembly code (labels need to be followed by a colon)";
|
||||||
|
//
|
||||||
|
// txtAssemblyCode
|
||||||
|
//
|
||||||
|
this.txtAssemblyCode.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtAssemblyCode.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.txtAssemblyCode.Location = new System.Drawing.Point(18, 513);
|
||||||
|
this.txtAssemblyCode.Multiline = true;
|
||||||
|
this.txtAssemblyCode.Name = "txtAssemblyCode";
|
||||||
|
this.txtAssemblyCode.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtAssemblyCode.Size = new System.Drawing.Size(706, 161);
|
||||||
|
this.txtAssemblyCode.TabIndex = 23;
|
||||||
|
//
|
||||||
|
// txtCompiledOpcodes
|
||||||
|
//
|
||||||
|
this.txtCompiledOpcodes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtCompiledOpcodes.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.txtCompiledOpcodes.Location = new System.Drawing.Point(18, 713);
|
||||||
|
this.txtCompiledOpcodes.Multiline = true;
|
||||||
|
this.txtCompiledOpcodes.Name = "txtCompiledOpcodes";
|
||||||
|
this.txtCompiledOpcodes.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtCompiledOpcodes.Size = new System.Drawing.Size(706, 59);
|
||||||
|
this.txtCompiledOpcodes.TabIndex = 25;
|
||||||
|
//
|
||||||
|
// label9
|
||||||
|
//
|
||||||
|
this.label9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.label9.AutoSize = true;
|
||||||
|
this.label9.Location = new System.Drawing.Point(15, 697);
|
||||||
|
this.label9.Name = "label9";
|
||||||
|
this.label9.Size = new System.Drawing.Size(94, 13);
|
||||||
|
this.label9.TabIndex = 24;
|
||||||
|
this.label9.Text = "Compiled opcodes";
|
||||||
|
//
|
||||||
|
// txtVirtualOffset
|
||||||
|
//
|
||||||
|
this.txtVirtualOffset.Location = new System.Drawing.Point(18, 416);
|
||||||
|
this.txtVirtualOffset.Name = "txtVirtualOffset";
|
||||||
|
this.txtVirtualOffset.Size = new System.Drawing.Size(302, 20);
|
||||||
|
this.txtVirtualOffset.TabIndex = 19;
|
||||||
|
//
|
||||||
|
// label10
|
||||||
|
//
|
||||||
|
this.label10.AutoSize = true;
|
||||||
|
this.label10.Location = new System.Drawing.Point(15, 400);
|
||||||
|
this.label10.Name = "label10";
|
||||||
|
this.label10.Size = new System.Drawing.Size(309, 13);
|
||||||
|
this.label10.TabIndex = 18;
|
||||||
|
this.label10.Text = "Virtual offset (hex) (leave empty for only recalculating checksum)";
|
||||||
|
//
|
||||||
|
// cmbCodeType
|
||||||
|
//
|
||||||
|
this.cmbCodeType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.cmbCodeType.FormattingEnabled = true;
|
||||||
|
this.cmbCodeType.Items.AddRange(new object[] {
|
||||||
|
"ARM",
|
||||||
|
"Thumb",
|
||||||
|
"Thumb2"});
|
||||||
|
this.cmbCodeType.Location = new System.Drawing.Point(18, 464);
|
||||||
|
this.cmbCodeType.Name = "cmbCodeType";
|
||||||
|
this.cmbCodeType.Size = new System.Drawing.Size(302, 21);
|
||||||
|
this.cmbCodeType.TabIndex = 21;
|
||||||
|
//
|
||||||
|
// label11
|
||||||
|
//
|
||||||
|
this.label11.AutoSize = true;
|
||||||
|
this.label11.Location = new System.Drawing.Point(15, 448);
|
||||||
|
this.label11.Name = "label11";
|
||||||
|
this.label11.Size = new System.Drawing.Size(55, 13);
|
||||||
|
this.label11.TabIndex = 20;
|
||||||
|
this.label11.Text = "Code type";
|
||||||
|
//
|
||||||
|
// cmdCompile
|
||||||
|
//
|
||||||
|
this.cmdCompile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdCompile.Location = new System.Drawing.Point(470, 792);
|
||||||
|
this.cmdCompile.Name = "cmdCompile";
|
||||||
|
this.cmdCompile.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdCompile.TabIndex = 26;
|
||||||
|
this.cmdCompile.Text = "Compile";
|
||||||
|
this.cmdCompile.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdCompile.Click += new System.EventHandler(this.cmdCompile_Click);
|
||||||
|
//
|
||||||
|
// cmdPatch
|
||||||
|
//
|
||||||
|
this.cmdPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.cmdPatch.Location = new System.Drawing.Point(604, 792);
|
||||||
|
this.cmdPatch.Name = "cmdPatch";
|
||||||
|
this.cmdPatch.Size = new System.Drawing.Size(120, 33);
|
||||||
|
this.cmdPatch.TabIndex = 27;
|
||||||
|
this.cmdPatch.Text = "Patch";
|
||||||
|
this.cmdPatch.UseVisualStyleBackColor = true;
|
||||||
|
this.cmdPatch.Click += new System.EventHandler(this.cmdPatch_Click);
|
||||||
|
//
|
||||||
|
// MainForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(742, 840);
|
||||||
|
this.Controls.Add(this.cmdPatch);
|
||||||
|
this.Controls.Add(this.cmdCompile);
|
||||||
|
this.Controls.Add(this.cmbCodeType);
|
||||||
|
this.Controls.Add(this.label11);
|
||||||
|
this.Controls.Add(this.txtVirtualOffset);
|
||||||
|
this.Controls.Add(this.label10);
|
||||||
|
this.Controls.Add(this.txtCompiledOpcodes);
|
||||||
|
this.Controls.Add(this.label9);
|
||||||
|
this.Controls.Add(this.txtAssemblyCode);
|
||||||
|
this.Controls.Add(this.label8);
|
||||||
|
this.Controls.Add(this.cmbTargetPath);
|
||||||
|
this.Controls.Add(this.label7);
|
||||||
|
this.Controls.Add(this.cmbTargetVersion);
|
||||||
|
this.Controls.Add(this.label6);
|
||||||
|
this.Controls.Add(this.cmbPatchDefinitionName);
|
||||||
|
this.Controls.Add(this.label5);
|
||||||
|
this.Controls.Add(this.cmdPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.txtPatchDefinitionsFile);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
|
this.Controls.Add(this.cmdOutputFile);
|
||||||
|
this.Controls.Add(this.txtOutputFile);
|
||||||
|
this.Controls.Add(this.label3);
|
||||||
|
this.Controls.Add(this.cmdInputFile);
|
||||||
|
this.Controls.Add(this.txtInputFile);
|
||||||
|
this.Controls.Add(this.label2);
|
||||||
|
this.Controls.Add(this.cmdVisualStudioPath);
|
||||||
|
this.Controls.Add(this.txtVisualStudioPath);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Name = "MainForm";
|
||||||
|
this.Text = "ARM patcher by Rene Lergner";
|
||||||
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed);
|
||||||
|
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.TextBox txtVisualStudioPath;
|
||||||
|
private System.Windows.Forms.FolderBrowserDialog FolderBrowserDialog;
|
||||||
|
private System.Windows.Forms.OpenFileDialog OpenFileDialog;
|
||||||
|
private System.Windows.Forms.SaveFileDialog SaveFileDialog;
|
||||||
|
private System.Windows.Forms.Button cmdVisualStudioPath;
|
||||||
|
private System.Windows.Forms.Button cmdInputFile;
|
||||||
|
private System.Windows.Forms.TextBox txtInputFile;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.Button cmdOutputFile;
|
||||||
|
private System.Windows.Forms.TextBox txtOutputFile;
|
||||||
|
private System.Windows.Forms.Label label3;
|
||||||
|
private System.Windows.Forms.Button cmdPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.TextBox txtPatchDefinitionsFile;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.Label label5;
|
||||||
|
private System.Windows.Forms.ComboBox cmbPatchDefinitionName;
|
||||||
|
private System.Windows.Forms.ComboBox cmbTargetVersion;
|
||||||
|
private System.Windows.Forms.Label label6;
|
||||||
|
private System.Windows.Forms.ComboBox cmbTargetPath;
|
||||||
|
private System.Windows.Forms.Label label7;
|
||||||
|
private System.Windows.Forms.Label label8;
|
||||||
|
private System.Windows.Forms.TextBox txtAssemblyCode;
|
||||||
|
private System.Windows.Forms.TextBox txtCompiledOpcodes;
|
||||||
|
private System.Windows.Forms.Label label9;
|
||||||
|
private System.Windows.Forms.TextBox txtVirtualOffset;
|
||||||
|
private System.Windows.Forms.Label label10;
|
||||||
|
private System.Windows.Forms.ComboBox cmbCodeType;
|
||||||
|
private System.Windows.Forms.Label label11;
|
||||||
|
private System.Windows.Forms.Button cmdCompile;
|
||||||
|
private System.Windows.Forms.Button cmdPatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public partial class MainForm : Form
|
||||||
|
{
|
||||||
|
public MainForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
cmbCodeType.SelectedItem = "Thumb2";
|
||||||
|
LoadPaths();
|
||||||
|
CenterToScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdCompile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
string VirtualOffsetString = txtVirtualOffset.Text.Trim();
|
||||||
|
if (VirtualOffsetString.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
VirtualOffsetString = VirtualOffsetString[2..];
|
||||||
|
|
||||||
|
CodeType CodeType = Patcher.CodeType.Thumb2;
|
||||||
|
byte[] CompiledCode = null;
|
||||||
|
if (UInt32.TryParse(VirtualOffsetString, System.Globalization.NumberStyles.HexNumber, null, out uint VirtualOffset))
|
||||||
|
{
|
||||||
|
CodeType = (CodeType)Enum.Parse(typeof(Patcher.CodeType), cmbCodeType.SelectedItem.ToString());
|
||||||
|
CompiledCode = ArmCompiler.Compile(txtVisualStudioPath.Text, VirtualOffset, CodeType, txtAssemblyCode.Text);
|
||||||
|
}
|
||||||
|
if ((VirtualOffset != 0) && (CompiledCode == null))
|
||||||
|
txtCompiledOpcodes.Text = ArmCompiler.Output;
|
||||||
|
else if (CompiledCode != null)
|
||||||
|
txtCompiledOpcodes.Text = Converter.ConvertHexToString(CompiledCode, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
txtVisualStudioPath.Text = (string)Key.GetValue("VisualStudioPath", "");
|
||||||
|
if (txtVisualStudioPath.Text.Length == 0)
|
||||||
|
txtVisualStudioPath.Text = FindVisualStudioPath();
|
||||||
|
|
||||||
|
txtPatchDefinitionsFile.Text = (string)Key.GetValue("PatchDefinitionsFilePath", "");
|
||||||
|
cmbPatchDefinitionName.Text = (string)Key.GetValue("PatchDefinitionName", "");
|
||||||
|
cmbTargetVersion.Text = (string)Key.GetValue("TargetVersion", "");
|
||||||
|
cmbTargetPath.Text = (string)Key.GetValue("TargetFilePath", "");
|
||||||
|
txtInputFile.Text = (string)Key.GetValue("InputFilePath", "");
|
||||||
|
txtOutputFile.Text = (string)Key.GetValue("OutputFilePath", "");
|
||||||
|
|
||||||
|
LoadPatchDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] FindMSVCBinaryPaths(string s)
|
||||||
|
{
|
||||||
|
string LegacyPath = Path.Combine(s, @"VC\bin");
|
||||||
|
if (Directory.Exists(LegacyPath))
|
||||||
|
{
|
||||||
|
return new string[] { LegacyPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC")))
|
||||||
|
{
|
||||||
|
IEnumerable<string> MSVCs = Directory.EnumerateDirectories(Path.Combine(s, @"VC\Tools\MSVC"));
|
||||||
|
IEnumerable<string> Bins = MSVCs.Select(s => Path.Combine(s, "bin")).Where(s => Directory.Exists(s));
|
||||||
|
return Bins.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FindArmAsmPath(string s)
|
||||||
|
{
|
||||||
|
foreach (string MSVCBin in FindMSVCBinaryPaths(s))
|
||||||
|
{
|
||||||
|
string path1 = Path.Combine(MSVCBin, "x86_arm");
|
||||||
|
string path2 = Path.Combine(MSVCBin, @"Hostx86\arm");
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path1, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(path2, "armasm.exe")))
|
||||||
|
{
|
||||||
|
return path2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindVisualStudioPath()
|
||||||
|
{
|
||||||
|
IEnumerable<string> MainX86VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files (x86)\", "Microsoft Visual Studio*");
|
||||||
|
IEnumerable<string> MainX64VSDirectories = Directory.EnumerateDirectories(@"C:\Program Files\", "Microsoft Visual Studio*");
|
||||||
|
|
||||||
|
IEnumerable<string> MainVSDirectories = MainX86VSDirectories.Union(MainX64VSDirectories);
|
||||||
|
|
||||||
|
IEnumerable<string> SubMainVSDirectories = MainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> SubSubMainVSDirectories = SubMainVSDirectories.SelectMany(s => Directory.EnumerateDirectories(s));
|
||||||
|
IEnumerable<string> Directories = MainVSDirectories.Union(SubMainVSDirectories).Union(SubSubMainVSDirectories);
|
||||||
|
|
||||||
|
string attempt1 = Directories.Where(s => FindArmAsmPath(s) != "").OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"VC\bin\x86_arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
|
||||||
|
if (attempt1 != "")
|
||||||
|
return attempt1;
|
||||||
|
|
||||||
|
return Directories.Where(s => Directory.Exists(Path.Combine(s, @"VC\Tools\MSVC"))).Select(s => Path.Combine(s, @"VC\Tools\MSVC")).SelectMany(s => Directory.EnumerateDirectories(s)).Where(s => File.Exists(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).OrderByDescending(s => File.GetCreationTime(Path.Combine(s, @"bin\Hostx86\arm\armasm.exe"))).FirstOrDefault() ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StorePaths()
|
||||||
|
{
|
||||||
|
RegistryKey Key = Registry.CurrentUser.OpenSubKey(@"Software\Patcher", true) ?? Registry.CurrentUser.CreateSubKey(@"Software\Patcher");
|
||||||
|
|
||||||
|
string VisualStudioPath = txtVisualStudioPath.Text.Trim();
|
||||||
|
if (VisualStudioPath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("VisualStudioPath") != null)
|
||||||
|
Key.DeleteValue("VisualStudioPath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("VisualStudioPath", VisualStudioPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string PatchDefinitionsFilePath = txtPatchDefinitionsFile.Text.Trim();
|
||||||
|
if (PatchDefinitionsFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("PatchDefinitionsFilePath") != null)
|
||||||
|
Key.DeleteValue("PatchDefinitionsFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("PatchDefinitionsFilePath", PatchDefinitionsFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string PatchDefinitionName = cmbPatchDefinitionName.Text.Trim();
|
||||||
|
if (PatchDefinitionName.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("PatchDefinitionName") != null)
|
||||||
|
Key.DeleteValue("PatchDefinitionName");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("PatchDefinitionName", PatchDefinitionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string TargetVersion = cmbTargetVersion.Text.Trim();
|
||||||
|
if (TargetVersion.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("TargetVersion") != null)
|
||||||
|
Key.DeleteValue("TargetVersion");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("TargetVersion", TargetVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
string TargetFilePath = cmbTargetPath.Text.Trim();
|
||||||
|
if (TargetFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("TargetFilePath") != null)
|
||||||
|
Key.DeleteValue("TargetFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("TargetFilePath", TargetFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string InputFilePath = txtInputFile.Text.Trim();
|
||||||
|
if (InputFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("InputFilePath") != null)
|
||||||
|
Key.DeleteValue("InputFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("InputFilePath", InputFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string OutputFilePath = txtOutputFile.Text.Trim();
|
||||||
|
if (OutputFilePath.Length == 0)
|
||||||
|
{
|
||||||
|
if (Key.GetValue("OutputFilePath") != null)
|
||||||
|
Key.DeleteValue("OutputFilePath");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key.SetValue("OutputFilePath", OutputFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LoadingPatchDefinitions = false;
|
||||||
|
|
||||||
|
private void LoadPatchDefinitions()
|
||||||
|
{
|
||||||
|
if (LoadingPatchDefinitions)
|
||||||
|
return;
|
||||||
|
LoadingPatchDefinitions = true;
|
||||||
|
|
||||||
|
string PatchDefinitionName = cmbPatchDefinitionName.Text;
|
||||||
|
string TargetVersion = cmbTargetVersion.Text;
|
||||||
|
string TargetPath = cmbTargetPath.Text;
|
||||||
|
|
||||||
|
cmbPatchDefinitionName.SelectedIndex = -1;
|
||||||
|
cmbTargetVersion.SelectedIndex = -1;
|
||||||
|
cmbTargetPath.SelectedIndex = -1;
|
||||||
|
|
||||||
|
cmbPatchDefinitionName.Items.Clear();
|
||||||
|
cmbTargetVersion.Items.Clear();
|
||||||
|
cmbTargetPath.Items.Clear();
|
||||||
|
|
||||||
|
cmbPatchDefinitionName.Text = PatchDefinitionName;
|
||||||
|
cmbTargetVersion.Text = TargetVersion;
|
||||||
|
cmbTargetPath.Text = TargetPath;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string Definitions = File.ReadAllText(txtPatchDefinitionsFile.Text);
|
||||||
|
PatchEngine Engine = new(Definitions);
|
||||||
|
Engine.PatchDefinitions.Where(d => !string.IsNullOrEmpty(d.Name)).Select(d => d.Name).Distinct().ToList().ForEach(n => cmbPatchDefinitionName.Items.Add(n));
|
||||||
|
PatchDefinition Definition = null;
|
||||||
|
if (cmbPatchDefinitionName.Text.Trim().Length > 0)
|
||||||
|
Definition = Engine.PatchDefinitions.Find(d => string.Equals(d.Name, cmbPatchDefinitionName.Text.Trim(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (Definition != null)
|
||||||
|
{
|
||||||
|
Definition.TargetVersions.Where(v => !string.IsNullOrEmpty(v.Description)).Select(v => v.Description).Distinct().ToList().ForEach(d => cmbTargetVersion.Items.Add(d));
|
||||||
|
TargetVersion Version = null;
|
||||||
|
if (cmbTargetVersion.Text.Trim().Length > 0)
|
||||||
|
Version = Definition.TargetVersions.Find(v => string.Equals(v.Description, cmbTargetVersion.Text.Trim(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (Version != null)
|
||||||
|
{
|
||||||
|
Version.TargetFiles.Where(f => !string.IsNullOrEmpty(f.Path)).Select(f => Path.GetDirectoryName(f.Path)).Distinct().ToList().ForEach(f => cmbTargetPath.Items.Add(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
LoadingPatchDefinitions = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdVisualStudioPath_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FolderBrowserDialog.SelectedPath = txtVisualStudioPath.Text;
|
||||||
|
FolderBrowserDialog.Description = "Select path to Visual Studio with ARM32 SDK";
|
||||||
|
System.Windows.Forms.DialogResult Result = FolderBrowserDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
txtVisualStudioPath.Text = FolderBrowserDialog.SelectedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatchDefinitionsFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = false;
|
||||||
|
OpenFileDialog.DefaultExt = "xml";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtPatchDefinitionsFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open patch-definitions file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtPatchDefinitionsFile.Text = OpenFileDialog.FileName;
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void txtPatchDefinitionsFile_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||||
|
{
|
||||||
|
StorePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbPatchDefinitionName_SelectedValueChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbPatchDefinitionName_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbTargetVersion_SelectedValueChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmbTargetVersion_Leave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
WindowsFormsSynchronizationContext.Current.Post(s => LoadPatchDefinitions(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdInputFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog.CheckFileExists = true;
|
||||||
|
OpenFileDialog.DefaultExt = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenFileDialog.FileName = Path.GetFileName(txtInputFile.Text);
|
||||||
|
OpenFileDialog.InitialDirectory = Path.GetDirectoryName(txtInputFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
OpenFileDialog.Multiselect = false;
|
||||||
|
OpenFileDialog.Title = "Open input file";
|
||||||
|
System.Windows.Forms.DialogResult Result = OpenFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtInputFile.Text = OpenFileDialog.FileName;
|
||||||
|
txtOutputFile.Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdOutputFile_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
SaveFileDialog.CheckFileExists = false;
|
||||||
|
SaveFileDialog.DefaultExt = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SaveFileDialog.FileName = Path.GetFileName(txtInputFile.Text);
|
||||||
|
SaveFileDialog.InitialDirectory = Path.GetDirectoryName(txtOutputFile.Text);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
SaveFileDialog.Title = "Open input file";
|
||||||
|
System.Windows.Forms.DialogResult Result = SaveFileDialog.ShowDialog();
|
||||||
|
if (Result == System.Windows.Forms.DialogResult.OK)
|
||||||
|
txtOutputFile.Text = SaveFileDialog.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmdPatch_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
string VirtualOffsetString = txtVirtualOffset.Text.Trim();
|
||||||
|
if (VirtualOffsetString.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
VirtualOffsetString = VirtualOffsetString[2..];
|
||||||
|
CodeType CodeType = Patcher.CodeType.Thumb2;
|
||||||
|
byte[] CompiledCode = null;
|
||||||
|
if (UInt32.TryParse(VirtualOffsetString, System.Globalization.NumberStyles.HexNumber, null, out uint VirtualAddress))
|
||||||
|
{
|
||||||
|
CodeType = (CodeType)Enum.Parse(typeof(Patcher.CodeType), cmbCodeType.SelectedItem.ToString());
|
||||||
|
CompiledCode = ArmCompiler.Compile(txtVisualStudioPath.Text, VirtualAddress, CodeType, txtAssemblyCode.Text);
|
||||||
|
}
|
||||||
|
if ((VirtualAddress != 0) && (CompiledCode == null))
|
||||||
|
{
|
||||||
|
txtCompiledOpcodes.Text = ArmCompiler.Output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CompiledCode != null)
|
||||||
|
txtCompiledOpcodes.Text = Converter.ConvertHexToString(CompiledCode, " ");
|
||||||
|
|
||||||
|
string TargetFilePath = Path.Combine(cmbTargetPath.Text, Path.GetFileName(txtInputFile.Text));
|
||||||
|
if (TargetFilePath.StartsWith(@"\"))
|
||||||
|
TargetFilePath = TargetFilePath[1..];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MainPatcher.AddPatch(txtInputFile.Text, (txtOutputFile.Text.Trim().Length > 0) ? txtOutputFile.Text : null, cmbPatchDefinitionName.Text, cmbTargetVersion.Text, TargetFilePath, txtVisualStudioPath.Text, VirtualAddress, CodeType, txtAssemblyCode.Text, txtPatchDefinitionsFile.Text);
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException)
|
||||||
|
{
|
||||||
|
txtCompiledOpcodes.Text = "BAD VIRTUAL OFFSET";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
txtCompiledOpcodes.Text = "UNKNOWN ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
txtVirtualOffset.Focus();
|
||||||
|
txtVirtualOffset.SelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="OpenFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>182, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="SaveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>317, 17</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
public static class MainPatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// TargetFilePath is relative to the root of the PatchDefinition
|
||||||
|
/// OutputFilePath can be null
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="InputFilePath"></param>
|
||||||
|
/// <param name="OutputFilePath"></param>
|
||||||
|
/// <param name="PatchDefinitionName"></param>
|
||||||
|
/// <param name="TargetVersionDescription"></param>
|
||||||
|
/// <param name="TargetFilePath"></param>
|
||||||
|
/// <param name="PathToVisualStudioWithWP8SDK"></param>
|
||||||
|
/// <param name="VirtualAddress"></param>
|
||||||
|
/// <param name="CodeType"></param>
|
||||||
|
/// <param name="ArmCodeFragment"></param>
|
||||||
|
/// <param name="PatchDefintionsXmlPath"></param>
|
||||||
|
public static void AddPatch(string InputFilePath, string OutputFilePath, string PatchDefinitionName, string TargetVersionDescription, string TargetFilePath, string PathToVisualStudioWithWP8SDK, UInt32 VirtualAddress, CodeType CodeType, string ArmCodeFragment, string PatchDefintionsXmlPath)
|
||||||
|
{
|
||||||
|
SHA1Managed SHA = new();
|
||||||
|
|
||||||
|
// Compile ARM code
|
||||||
|
byte[] CompiledCode = null;
|
||||||
|
if (VirtualAddress != 0)
|
||||||
|
CompiledCode = ArmCompiler.Compile(PathToVisualStudioWithWP8SDK, VirtualAddress, CodeType, ArmCodeFragment);
|
||||||
|
|
||||||
|
// Read original binary
|
||||||
|
byte[] Binary = File.ReadAllBytes(InputFilePath);
|
||||||
|
|
||||||
|
// Backup original checksum
|
||||||
|
UInt32 ChecksumOffset = GetChecksumOffset(Binary);
|
||||||
|
UInt32 OriginalChecksum = ByteOperations.ReadUInt32(Binary, ChecksumOffset);
|
||||||
|
|
||||||
|
// Determine Raw Offset
|
||||||
|
PeFile PeFile = new(Binary);
|
||||||
|
UInt32 RawOffset = 0;
|
||||||
|
if (VirtualAddress != 0)
|
||||||
|
RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress);
|
||||||
|
|
||||||
|
// Add or replace patch
|
||||||
|
string PatchDefintionsXml = File.ReadAllText(PatchDefintionsXmlPath);
|
||||||
|
PatchEngine PatchEngine = new(PatchDefintionsXml);
|
||||||
|
PatchDefinition PatchDefinition = PatchEngine.PatchDefinitions.Find(d => string.Equals(d.Name, PatchDefinitionName, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (PatchDefinition == null)
|
||||||
|
{
|
||||||
|
PatchDefinition = new PatchDefinition
|
||||||
|
{
|
||||||
|
Name = PatchDefinitionName
|
||||||
|
};
|
||||||
|
PatchEngine.PatchDefinitions.Add(PatchDefinition);
|
||||||
|
}
|
||||||
|
TargetVersion TargetVersion = PatchDefinition.TargetVersions.Find(v => string.Equals(v.Description, TargetVersionDescription, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (TargetVersion == null)
|
||||||
|
{
|
||||||
|
TargetVersion = new TargetVersion
|
||||||
|
{
|
||||||
|
Description = TargetVersionDescription
|
||||||
|
};
|
||||||
|
PatchDefinition.TargetVersions.Add(TargetVersion);
|
||||||
|
}
|
||||||
|
TargetFile TargetFile = TargetVersion.TargetFiles.Find(f => (f.Path != null) && (string.Equals(f.Path.TrimStart(new char[] { '\\' }), TargetFilePath.TrimStart(new char[] { '\\' }), StringComparison.CurrentCultureIgnoreCase)));
|
||||||
|
if (TargetFile == null)
|
||||||
|
{
|
||||||
|
TargetFile = new TargetFile();
|
||||||
|
TargetVersion.TargetFiles.Add(TargetFile);
|
||||||
|
}
|
||||||
|
TargetFile.Path = TargetFilePath;
|
||||||
|
TargetFile.HashOriginal = SHA.ComputeHash(Binary);
|
||||||
|
Patch Patch;
|
||||||
|
if (VirtualAddress != 0)
|
||||||
|
{
|
||||||
|
Patch = TargetFile.Patches.Find(p => p.Address == RawOffset);
|
||||||
|
if (Patch == null)
|
||||||
|
{
|
||||||
|
Patch = new Patch
|
||||||
|
{
|
||||||
|
Address = RawOffset
|
||||||
|
};
|
||||||
|
TargetFile.Patches.Add(Patch);
|
||||||
|
}
|
||||||
|
Patch.OriginalBytes = new byte[CompiledCode.Length];
|
||||||
|
Buffer.BlockCopy(Binary, (int)RawOffset, Patch.OriginalBytes, 0, CompiledCode.Length);
|
||||||
|
Patch.PatchedBytes = CompiledCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply all patches
|
||||||
|
foreach (Patch CurrentPatch in TargetFile.Patches)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(CurrentPatch.PatchedBytes, 0, Binary, (int)CurrentPatch.Address, CurrentPatch.PatchedBytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate checksum
|
||||||
|
// This also modifies the binary
|
||||||
|
// Original checksum is already backed up
|
||||||
|
UInt32 Checksum = CalculateChecksum(Binary);
|
||||||
|
|
||||||
|
// Add or replace checksum patch
|
||||||
|
Patch = TargetFile.Patches.Find(p => p.Address == ChecksumOffset);
|
||||||
|
if (Patch == null)
|
||||||
|
{
|
||||||
|
Patch = new Patch
|
||||||
|
{
|
||||||
|
Address = ChecksumOffset
|
||||||
|
};
|
||||||
|
TargetFile.Patches.Add(Patch);
|
||||||
|
}
|
||||||
|
Patch.OriginalBytes = new byte[4];
|
||||||
|
ByteOperations.WriteUInt32(Patch.OriginalBytes, 0, OriginalChecksum);
|
||||||
|
Patch.PatchedBytes = new byte[4];
|
||||||
|
ByteOperations.WriteUInt32(Patch.PatchedBytes, 0, Checksum);
|
||||||
|
|
||||||
|
// Calculate hash for patched target file
|
||||||
|
TargetFile.HashPatched = SHA.ComputeHash(Binary);
|
||||||
|
|
||||||
|
// Write patched file
|
||||||
|
if (OutputFilePath != null)
|
||||||
|
File.WriteAllBytes(OutputFilePath, Binary);
|
||||||
|
|
||||||
|
// Write PatchDefintions
|
||||||
|
PatchEngine.WriteDefinitions(PatchDefintionsXmlPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UInt32 CalculateChecksum(byte[] PEFile)
|
||||||
|
{
|
||||||
|
UInt32 Checksum = 0;
|
||||||
|
UInt32 Hi;
|
||||||
|
|
||||||
|
// Clear file checksum
|
||||||
|
ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(PEFile), 0);
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < ((UInt32)PEFile.Length & 0xfffffffe); i += 2)
|
||||||
|
{
|
||||||
|
Checksum += ByteOperations.ReadUInt16(PEFile, i);
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((PEFile.Length % 2) != 0)
|
||||||
|
{
|
||||||
|
Checksum += (UInt32)ByteOperations.ReadUInt8(PEFile, (UInt32)PEFile.Length - 1);
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Checksum += (UInt32)PEFile.Length;
|
||||||
|
|
||||||
|
// Write file checksum
|
||||||
|
ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(PEFile), Checksum);
|
||||||
|
|
||||||
|
return Checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UInt32 GetChecksumOffset(byte[] PEFile)
|
||||||
|
{
|
||||||
|
return ByteOperations.ReadUInt32(PEFile, 0x3C) + +0x58;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,819 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
// This code is based on Get-ObjDump from Matthew Graeber (@mattifestation)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace COFF
|
||||||
|
{
|
||||||
|
public enum Machine : ushort
|
||||||
|
{
|
||||||
|
UNKNOWN = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Intel 386.
|
||||||
|
/// </summary>
|
||||||
|
I386 = 0x014C,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian =0x160 big-endian
|
||||||
|
/// </summary>
|
||||||
|
R3000 = 0x0162,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian
|
||||||
|
/// </summary>
|
||||||
|
R4000 = 0x0166,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian
|
||||||
|
/// </summary>
|
||||||
|
R10000 = 0x0168,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS little-endian WCE v2
|
||||||
|
/// </summary>
|
||||||
|
WCEMIPSV2 = 0x0169,
|
||||||
|
/// <summary>
|
||||||
|
/// Alpha_AXP
|
||||||
|
/// </summary>
|
||||||
|
ALPHA = 0x0184,
|
||||||
|
/// <summary>
|
||||||
|
/// SH3 little-endian
|
||||||
|
/// </summary>
|
||||||
|
SH3 = 0x01A2,
|
||||||
|
SH3DSP = 0x01A3,
|
||||||
|
/// <summary>
|
||||||
|
/// SH3E little-endian
|
||||||
|
/// </summary>
|
||||||
|
SH3E = 0x01A4,
|
||||||
|
/// <summary>
|
||||||
|
/// SH4 little-endian
|
||||||
|
/// </summary>
|
||||||
|
SH4 = 0x01A6,
|
||||||
|
/// <summary>
|
||||||
|
/// SH5
|
||||||
|
/// </summary>
|
||||||
|
SH5 = 0x01A8,
|
||||||
|
/// <summary>
|
||||||
|
/// ARM Little-Endian
|
||||||
|
/// </summary>
|
||||||
|
ARM = 0x01C0,
|
||||||
|
THUMB = 0x01C2,
|
||||||
|
/// <summary>
|
||||||
|
/// ARM Thumb-2 Little-Endian
|
||||||
|
/// </summary>
|
||||||
|
ARMV7 = 0x01C4,
|
||||||
|
AM33 = 0x01D3,
|
||||||
|
/// <summary>
|
||||||
|
/// IBM PowerPC Little-Endian
|
||||||
|
/// </summary>
|
||||||
|
POWERPC = 0x01F0,
|
||||||
|
POWERPCFP = 0x01F1,
|
||||||
|
/// <summary>
|
||||||
|
/// Intel 64
|
||||||
|
/// </summary>
|
||||||
|
IA64 = 0x0200,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS
|
||||||
|
/// </summary>
|
||||||
|
MIPS16 = 0x0266,
|
||||||
|
/// <summary>
|
||||||
|
/// ALPHA64
|
||||||
|
/// </summary>
|
||||||
|
ALPHA64 = 0x0284,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS
|
||||||
|
/// </summary>
|
||||||
|
MIPSFPU = 0x0366,
|
||||||
|
/// <summary>
|
||||||
|
/// MIPS
|
||||||
|
/// </summary>
|
||||||
|
MIPSFPU16 = 0x0466,
|
||||||
|
AXP64 = ALPHA64,
|
||||||
|
/// <summary>
|
||||||
|
/// Infineon
|
||||||
|
/// </summary>
|
||||||
|
TRICORE = 0x0520,
|
||||||
|
CEF = 0x0CEF,
|
||||||
|
/// <summary>
|
||||||
|
/// EFI public byte Code
|
||||||
|
/// </summary>
|
||||||
|
EBC = 0x0EBC,
|
||||||
|
/// <summary>
|
||||||
|
/// AMD64 (K8)
|
||||||
|
/// </summary>
|
||||||
|
AMD64 = 0x8664,
|
||||||
|
/// <summary>
|
||||||
|
/// M32R little-endian
|
||||||
|
/// </summary>
|
||||||
|
M32R = 0x9041,
|
||||||
|
/// <summary>
|
||||||
|
/// ARMv8 in 64-bit mode
|
||||||
|
/// </summary>
|
||||||
|
ARM64 = 0xAA64,
|
||||||
|
CEE = 0xC0EE
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum CoffHeaderCharacteristics : ushort
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Relocation info stripped from file.
|
||||||
|
/// </summary>
|
||||||
|
RELOCS_STRIPPED = 0x0001,
|
||||||
|
/// <summary>
|
||||||
|
/// File is executable (i.e. no unresolved external references).
|
||||||
|
/// </summary>
|
||||||
|
EXECUTABLE_IMAGE = 0x0002,
|
||||||
|
/// <summary>
|
||||||
|
/// Line nunbers stripped from file.
|
||||||
|
/// </summary>
|
||||||
|
LINE_NUMS_STRIPPED = 0x0004,
|
||||||
|
/// <summary>
|
||||||
|
/// Local symbols stripped from file.
|
||||||
|
/// </summary>
|
||||||
|
LOCAL_SYMS_STRIPPED = 0x0008,
|
||||||
|
/// <summary>
|
||||||
|
/// Agressively trim working set
|
||||||
|
/// </summary>
|
||||||
|
AGGRESIVE_WS_TRIM = 0x0010,
|
||||||
|
/// <summary>
|
||||||
|
/// App can handle >2gb addresses
|
||||||
|
/// </summary>
|
||||||
|
LARGE_ADDRESS_AWARE = 0x0020,
|
||||||
|
/// <summary>
|
||||||
|
/// public bytes of machine public ushort are reversed.
|
||||||
|
/// </summary>
|
||||||
|
REVERSED_LO = 0x0080,
|
||||||
|
/// <summary>
|
||||||
|
/// 32 bit public ushort machine.
|
||||||
|
/// </summary>
|
||||||
|
BIT32_MACHINE = 0x0100,
|
||||||
|
/// <summary>
|
||||||
|
/// Debugging info stripped from file in .DBG file
|
||||||
|
/// </summary>
|
||||||
|
DEBUG_STRIPPED = 0x0200,
|
||||||
|
/// <summary>
|
||||||
|
/// If Image is on removable media =copy and run from the swap file.
|
||||||
|
/// </summary>
|
||||||
|
REMOVABLE_RUN_FROM_SWAP = 0x0400,
|
||||||
|
/// <summary>
|
||||||
|
/// If Image is on Net =copy and run from the swap file.
|
||||||
|
/// </summary>
|
||||||
|
NET_RUN_FROM_SWAP = 0x0800,
|
||||||
|
/// <summary>
|
||||||
|
/// System File.
|
||||||
|
/// </summary>
|
||||||
|
SYSTEM = 0x1000,
|
||||||
|
/// <summary>
|
||||||
|
/// File is a DLL.
|
||||||
|
/// </summary>
|
||||||
|
DLL = 0x2000,
|
||||||
|
/// <summary>
|
||||||
|
/// File should only be run on a UP machine
|
||||||
|
/// </summary>
|
||||||
|
UP_SYSTEM_ONLY = 0x4000,
|
||||||
|
/// <summary>
|
||||||
|
/// public bytes of machine public ushort are reversed.
|
||||||
|
/// </summary>
|
||||||
|
REVERSED_HI = 0x8000
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HEADER
|
||||||
|
{
|
||||||
|
public Machine Machine;
|
||||||
|
public ushort NumberOfSections;
|
||||||
|
public DateTime TimeDateStamp;
|
||||||
|
public uint PointerToSymbolTable;
|
||||||
|
public uint NumberOfSymbols;
|
||||||
|
public ushort SizeOfOptionalHeader;
|
||||||
|
public CoffHeaderCharacteristics Characteristics;
|
||||||
|
|
||||||
|
public HEADER(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.Machine = (Machine)br.ReadUInt16();
|
||||||
|
this.NumberOfSections = br.ReadUInt16();
|
||||||
|
this.TimeDateStamp = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(br.ReadUInt32());
|
||||||
|
this.PointerToSymbolTable = br.ReadUInt32();
|
||||||
|
this.NumberOfSymbols = br.ReadUInt32();
|
||||||
|
this.SizeOfOptionalHeader = br.ReadUInt16();
|
||||||
|
this.Characteristics = (CoffHeaderCharacteristics)br.ReadUInt16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SectionHeaderCharacteristics : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reserved.
|
||||||
|
/// </summary>
|
||||||
|
TYPE_NO_PAD = 0x00000008,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains code.
|
||||||
|
/// </summary>
|
||||||
|
CNT_CODE = 0x00000020,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains initialized data.
|
||||||
|
/// </summary>
|
||||||
|
CNT_INITIALIZED_DATA = 0x00000040,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains uninitialized data.
|
||||||
|
/// </summary>
|
||||||
|
CNT_UNINITIALIZED_DATA = 0x00000080,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains comments or some other type of information.
|
||||||
|
/// </summary>
|
||||||
|
LNK_INFO = 0x00000200,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contents will not become part of image.
|
||||||
|
/// </summary>
|
||||||
|
LNK_REMOVE = 0x00000800,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contents comdat.
|
||||||
|
/// </summary>
|
||||||
|
LNK_COMDAT = 0x00001000,
|
||||||
|
/// <summary>
|
||||||
|
/// Reset speculative exceptions handling bits in the TLB entries for this section.
|
||||||
|
/// </summary>
|
||||||
|
NO_DEFER_SPEC_EXC = 0x00004000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section content can be accessed relative to GP
|
||||||
|
/// </summary>
|
||||||
|
GPREL = 0x00008000,
|
||||||
|
MEM_FARDATA = 0x00008000,
|
||||||
|
MEM_PURGEABLE = 0x00020000,
|
||||||
|
MEM_16BIT = 0x00020000,
|
||||||
|
MEM_LOCKED = 0x00040000,
|
||||||
|
MEM_PRELOAD = 0x00080000,
|
||||||
|
ALIGN_1BYTES = 0x00100000,
|
||||||
|
ALIGN_2BYTES = 0x00200000,
|
||||||
|
ALIGN_4BYTES = 0x00300000,
|
||||||
|
ALIGN_8BYTES = 0x00400000,
|
||||||
|
/// <summary>
|
||||||
|
/// Default alignment if no others are specified.
|
||||||
|
/// </summary>
|
||||||
|
ALIGN_16BYTES = 0x00500000,
|
||||||
|
ALIGN_32BYTES = 0x00600000,
|
||||||
|
ALIGN_64BYTES = 0x00700000,
|
||||||
|
ALIGN_128BYTES = 0x00800000,
|
||||||
|
ALIGN_256BYTES = 0x00900000,
|
||||||
|
ALIGN_512BYTES = 0x00A00000,
|
||||||
|
ALIGN_1024BYTES = 0x00B00000,
|
||||||
|
ALIGN_2048BYTES = 0x00C00000,
|
||||||
|
ALIGN_4096BYTES = 0x00D00000,
|
||||||
|
ALIGN_8192BYTES = 0x00E00000,
|
||||||
|
ALIGN_MASK = 0x00F00000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section contains extended relocations.
|
||||||
|
/// </summary>
|
||||||
|
LNK_NRELOC_OVFL = 0x01000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section can be discarded.
|
||||||
|
/// </summary>
|
||||||
|
MEM_DISCARDABLE = 0x02000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is not cachable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_NOT_CACHED = 0x04000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is not pageable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_NOT_PAGED = 0x08000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is shareable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_SHARED = 0x10000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is executable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_EXECUTE = 0x20000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is readable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_READ = 0x40000000,
|
||||||
|
/// <summary>
|
||||||
|
/// Section is writeable.
|
||||||
|
/// </summary>
|
||||||
|
MEM_WRITE = 0x80000000
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AMD64RelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
ADDR64,
|
||||||
|
ADDR32,
|
||||||
|
ADDR32NB,
|
||||||
|
REL32,
|
||||||
|
REL32_1,
|
||||||
|
REL32_2,
|
||||||
|
REL32_3,
|
||||||
|
REL32_4,
|
||||||
|
REL32_5,
|
||||||
|
SECTION,
|
||||||
|
SECREL,
|
||||||
|
SECREL7,
|
||||||
|
TOKEN,
|
||||||
|
SREL32,
|
||||||
|
PAIR,
|
||||||
|
SSPAN32
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ARMRelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
ADDR32,
|
||||||
|
ADDR32NB,
|
||||||
|
BRANCH24,
|
||||||
|
BRANCH11,
|
||||||
|
TOKEN,
|
||||||
|
BLX24 = 0x08,
|
||||||
|
BLX11 = 0x09,
|
||||||
|
SECTION = 0x0E,
|
||||||
|
SECREL = 0x0F,
|
||||||
|
MOV32A = 0x10,
|
||||||
|
MOV32T = 0x11,
|
||||||
|
BRANCH20T = 0x12,
|
||||||
|
BRANCH24T = 0x14,
|
||||||
|
BLX23T = 0x15
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ARMv8RelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
ADDR32,
|
||||||
|
ADDR32NB,
|
||||||
|
BRANCH26,
|
||||||
|
PAGEBASE_REL21,
|
||||||
|
REL21,
|
||||||
|
PAGEOFFSET_12A,
|
||||||
|
PAGEOFFSET_12L,
|
||||||
|
SECREL,
|
||||||
|
SECREL_LOW12A,
|
||||||
|
SECREL_HIGH12A,
|
||||||
|
SECREL_LOW12L,
|
||||||
|
TOKEN,
|
||||||
|
SECTION,
|
||||||
|
ADDR64
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum X86RelocationType : ushort
|
||||||
|
{
|
||||||
|
ABSOLUTE,
|
||||||
|
DIR16,
|
||||||
|
DIR32 = 0x06,
|
||||||
|
DIR32NB = 0x07,
|
||||||
|
SEG12 = 0x09,
|
||||||
|
SECTION = 0x0A,
|
||||||
|
SECREL = 0x0B,
|
||||||
|
TOKEN = 0x0C,
|
||||||
|
SECREL7 = 0x0D,
|
||||||
|
REL32 = 0x14
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RelocationEntry
|
||||||
|
{
|
||||||
|
public uint VirtualAddress;
|
||||||
|
public uint SymbolTableIndex;
|
||||||
|
public Enum Type;
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public RelocationEntry(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.VirtualAddress = br.ReadUInt32();
|
||||||
|
this.SymbolTableIndex = br.ReadUInt32();
|
||||||
|
// Default to X86RelocationType. This will be changed once the processor type is determined
|
||||||
|
this.Type = (X86RelocationType)br.ReadUInt16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SECTION_HEADER
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public uint PhysicalAddress;
|
||||||
|
public uint VirtualSize;
|
||||||
|
public uint VirtualAddress;
|
||||||
|
public uint SizeOfRawData;
|
||||||
|
public uint PointerToRawData;
|
||||||
|
public uint PointerToRelocations;
|
||||||
|
public uint PointerToLinenumbers;
|
||||||
|
public ushort NumberOfRelocations;
|
||||||
|
public ushort NumberOfLinenumbers;
|
||||||
|
public SectionHeaderCharacteristics Characteristics;
|
||||||
|
public Byte[] RawData;
|
||||||
|
public RelocationEntry[] Relocations;
|
||||||
|
|
||||||
|
public SECTION_HEADER(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.Name = Encoding.UTF8.GetString(br.ReadBytes(8)).Split((Char)0)[0];
|
||||||
|
this.PhysicalAddress = br.ReadUInt32();
|
||||||
|
this.VirtualSize = this.PhysicalAddress;
|
||||||
|
this.VirtualAddress = br.ReadUInt32();
|
||||||
|
this.SizeOfRawData = br.ReadUInt32();
|
||||||
|
this.PointerToRawData = br.ReadUInt32();
|
||||||
|
this.PointerToRelocations = br.ReadUInt32();
|
||||||
|
this.PointerToLinenumbers = br.ReadUInt32();
|
||||||
|
this.NumberOfRelocations = br.ReadUInt16();
|
||||||
|
this.NumberOfLinenumbers = br.ReadUInt16();
|
||||||
|
this.Characteristics = (SectionHeaderCharacteristics)br.ReadUInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SectionNumber : short
|
||||||
|
{
|
||||||
|
UNDEFINED,
|
||||||
|
ABSOLUTE = -1,
|
||||||
|
DEBUG = -2
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum TypeClass : short
|
||||||
|
{
|
||||||
|
TYPE_NULL,
|
||||||
|
TYPE_VOID,
|
||||||
|
TYPE_CHAR,
|
||||||
|
TYPE_SHORT,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_LONG,
|
||||||
|
TYPE_FLOAT,
|
||||||
|
TYPE_DOUBLE,
|
||||||
|
TYPE_STRUCT,
|
||||||
|
TYPE_UNION,
|
||||||
|
TYPE_ENUM,
|
||||||
|
TYPE_MOE,
|
||||||
|
TYPE_BYTE,
|
||||||
|
TYPE_WORD,
|
||||||
|
TYPE_UINT,
|
||||||
|
TYPE_DWORD,
|
||||||
|
DTYPE_POINTER = 0x100,
|
||||||
|
DTYPE_FUNCTION = 0x200,
|
||||||
|
DTYPE_ARRAY = 0x300,
|
||||||
|
/// <summary>
|
||||||
|
/// Technically, this is defined as 0 in the MSB
|
||||||
|
/// </summary>
|
||||||
|
DTYPE_NULL = 0x400
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StorageClass : byte
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
AUTOMATIC,
|
||||||
|
EXTERNAL,
|
||||||
|
STATIC,
|
||||||
|
REGISTER,
|
||||||
|
EXTERNAL_DEF,
|
||||||
|
LABEL,
|
||||||
|
UNDEFINED_LABEL,
|
||||||
|
MEMBER_OF_STRUCT,
|
||||||
|
ARGUMENT,
|
||||||
|
STRUCT_TAG,
|
||||||
|
MEMBER_OF_UNION,
|
||||||
|
UNION_TAG,
|
||||||
|
TYPE_DEFINITION,
|
||||||
|
ENUM_TAG,
|
||||||
|
MEMBER_OF_ENUM,
|
||||||
|
REGISTER_PARAM,
|
||||||
|
BIT_FIELD,
|
||||||
|
BLOCK = 0x64,
|
||||||
|
FUNCTION = 0x65,
|
||||||
|
END_OF_STRUCT = 0x66,
|
||||||
|
FILE = 0x67,
|
||||||
|
SECTION = 0x68,
|
||||||
|
WEAK_EXTERNAL = 0x69,
|
||||||
|
CLR_TOKEN = 0x6B,
|
||||||
|
END_OF_FUNCTION = 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SYMBOL_TABLE
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public uint Value;
|
||||||
|
public SectionNumber SectionNumber;
|
||||||
|
public TypeClass Type;
|
||||||
|
public StorageClass StorageClass;
|
||||||
|
public byte NumberOfAuxSymbols;
|
||||||
|
public Object AuxSymbols;
|
||||||
|
private readonly Byte[] NameArray;
|
||||||
|
|
||||||
|
public SYMBOL_TABLE(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.NameArray = br.ReadBytes(8);
|
||||||
|
|
||||||
|
if (this.NameArray[0] == 0 && this.NameArray[1] == 0 && this.NameArray[2] == 0 && this.NameArray[3] == 0)
|
||||||
|
{
|
||||||
|
// Per specification, if the high DWORD is 0, then then low DWORD is an index into the string table
|
||||||
|
this.Name = "/" + BitConverter.ToInt32(NameArray, 4).ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = Encoding.UTF8.GetString(NameArray).Trim((char)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Value = br.ReadUInt32();
|
||||||
|
this.SectionNumber = (SectionNumber)br.ReadInt16();
|
||||||
|
this.Type = (TypeClass)br.ReadInt16();
|
||||||
|
if ((((int)this.Type) & 0xff00) == 0) { this.Type = (TypeClass)Enum.Parse(typeof(TypeClass), ((int)this.Type | 0x400).ToString()); }
|
||||||
|
this.StorageClass = (StorageClass)br.ReadByte();
|
||||||
|
this.NumberOfAuxSymbols = br.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SECTION_DEFINITION
|
||||||
|
{
|
||||||
|
public uint Length;
|
||||||
|
public ushort NumberOfRelocations;
|
||||||
|
public ushort NumberOfLinenumbers;
|
||||||
|
public uint CheckSum;
|
||||||
|
public ushort Number;
|
||||||
|
public byte Selection;
|
||||||
|
|
||||||
|
public SECTION_DEFINITION(BinaryReader br)
|
||||||
|
{
|
||||||
|
this.Length = br.ReadUInt32();
|
||||||
|
this.NumberOfRelocations = br.ReadUInt16();
|
||||||
|
this.NumberOfLinenumbers = br.ReadUInt16();
|
||||||
|
this.CheckSum = br.ReadUInt32();
|
||||||
|
this.Number = br.ReadUInt16();
|
||||||
|
this.Selection = br.ReadByte();
|
||||||
|
br.ReadBytes(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParsedObjectFile
|
||||||
|
{
|
||||||
|
public HEADER CoffHeader;
|
||||||
|
public SECTION_HEADER[] SectionHeaders;
|
||||||
|
public SYMBOL_TABLE[] SymbolTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ObjectFileParser
|
||||||
|
{
|
||||||
|
public static ParsedObjectFile ParseObjectFile(string ObjectFilePath)
|
||||||
|
{
|
||||||
|
ParsedObjectFile Result = null;
|
||||||
|
|
||||||
|
// Fixed structure sizes
|
||||||
|
const int SizeofCOFFFileHeader = 20;
|
||||||
|
const int SizeofSectionHeader = 40;
|
||||||
|
const int SizeofSymbolTableEntry = 18;
|
||||||
|
const int SizeofRelocationEntry = 10;
|
||||||
|
|
||||||
|
// Open the object file for reading
|
||||||
|
using (FileStream FileStream = System.IO.File.OpenRead(ObjectFilePath))
|
||||||
|
{
|
||||||
|
long FileLength = FileStream.Length;
|
||||||
|
|
||||||
|
if (FileLength < SizeofCOFFFileHeader)
|
||||||
|
{
|
||||||
|
// You cannot parse the COFF header if the file is not big enough to contain a COFF header.
|
||||||
|
throw new Exception("ObjectFile is too small to store a COFF header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a BinaryReader object for the object file
|
||||||
|
using BinaryReader BinaryReader = new(FileStream);
|
||||||
|
// Parse the COFF header
|
||||||
|
COFF.HEADER CoffHeader = new(BinaryReader);
|
||||||
|
|
||||||
|
if (CoffHeader.SizeOfOptionalHeader != 0)
|
||||||
|
{
|
||||||
|
// Per the PECOFF specification, an object file does not have an optional header
|
||||||
|
throw new Exception("Coff header indicates the existence of an optional header. An object file cannot have an optional header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CoffHeader.PointerToSymbolTable == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("An object file is supposed to have a symbol table.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileLength < ((CoffHeader.NumberOfSections * SizeofSectionHeader) + SizeofCOFFFileHeader))
|
||||||
|
{
|
||||||
|
// The object file isn't big enough to store the number of sections present.
|
||||||
|
throw new Exception("ObjectFile is too small to store section header data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A string collection used to store section header names. This collection is referenced while
|
||||||
|
// parsing the symbol table entries whose name is the same as the section header. In this case,
|
||||||
|
// the symbol entry will have a particular auxiliary symbol table entry.
|
||||||
|
System.Collections.Specialized.StringCollection SectionHeaderNames = new();
|
||||||
|
|
||||||
|
// Correlate the processor type to the relocation type. There are more relocation type defined
|
||||||
|
// in the PECOFF specification, but I don't expect those to be present. In that case, relocation
|
||||||
|
// entries default to X86RelocationType.
|
||||||
|
COFF.SECTION_HEADER[] SectionHeaders = new COFF.SECTION_HEADER[CoffHeader.NumberOfSections];
|
||||||
|
|
||||||
|
// Parse section headers
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
SectionHeaders[i] = new COFF.SECTION_HEADER(BinaryReader);
|
||||||
|
|
||||||
|
// Add the section name to the string collection. This will be referenced during symbol table parsing.
|
||||||
|
SectionHeaderNames.Add(SectionHeaders[i].Name);
|
||||||
|
|
||||||
|
// Save the current filestream position. We are about to jump out of place.
|
||||||
|
long SavedFilePosition = FileStream.Position;
|
||||||
|
|
||||||
|
// Check to see if the raw data points beyond the actual file size
|
||||||
|
if ((SectionHeaders[i].PointerToRawData + SectionHeaders[i].SizeOfRawData) > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("Section header's raw data exceeds the size of the object file.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Read the raw data into a byte array
|
||||||
|
FileStream.Seek(SectionHeaders[i].PointerToRawData, SeekOrigin.Begin);
|
||||||
|
SectionHeaders[i].RawData = BinaryReader.ReadBytes((int)SectionHeaders[i].SizeOfRawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if the section has a relocation table
|
||||||
|
if ((SectionHeaders[i].PointerToRelocations != 0) && (SectionHeaders[i].NumberOfRelocations != 0))
|
||||||
|
{
|
||||||
|
// Check to see if the relocation entries point beyond the actual file size
|
||||||
|
if ((SectionHeaders[i].PointerToRelocations + (SizeofRelocationEntry * SectionHeaders[i].NumberOfRelocations)) > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("(SectionHeaders[i].Name) section header's relocation entries exceeds the soze of the object file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream.Seek(SectionHeaders[i].PointerToRelocations, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
COFF.RelocationEntry[] Relocations = new COFF.RelocationEntry[SectionHeaders[i].NumberOfRelocations];
|
||||||
|
|
||||||
|
for (int j = 0; j < SectionHeaders[i].NumberOfRelocations; j++)
|
||||||
|
{
|
||||||
|
Relocations[j] = new COFF.RelocationEntry(BinaryReader);
|
||||||
|
// Cast the relocation as its respective type
|
||||||
|
switch (CoffHeader.Machine)
|
||||||
|
{
|
||||||
|
case Machine.I386:
|
||||||
|
Relocations[j].Type = (COFF.X86RelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
case Machine.AMD64:
|
||||||
|
Relocations[j].Type = (COFF.AMD64RelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
case Machine.ARMV7:
|
||||||
|
Relocations[j].Type = (COFF.ARMRelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
case Machine.ARM64:
|
||||||
|
Relocations[j].Type = (COFF.ARMv8RelocationType)Relocations[j].Type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the relocation table entry to the section header
|
||||||
|
SectionHeaders[i].Relocations = Relocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the original filestream pointer
|
||||||
|
FileStream.Seek(SavedFilePosition, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the contents of the COFF string table
|
||||||
|
long SymTableSize = CoffHeader.NumberOfSymbols * SizeofSymbolTableEntry;
|
||||||
|
long StringTableOffset = CoffHeader.PointerToSymbolTable + SymTableSize;
|
||||||
|
|
||||||
|
if (StringTableOffset > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("The string table points beyond the end of the file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream.Seek(StringTableOffset, SeekOrigin.Begin);
|
||||||
|
UInt32 StringTableLength = BinaryReader.ReadUInt32();
|
||||||
|
|
||||||
|
if (StringTableLength > FileLength)
|
||||||
|
{
|
||||||
|
throw new Exception("The string table's length exceeds the length of the file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string StringTable = System.Text.Encoding.UTF8.GetString(BinaryReader.ReadBytes((int)StringTableLength));
|
||||||
|
|
||||||
|
COFF.SYMBOL_TABLE[] RawSymbolTable = new COFF.SYMBOL_TABLE[CoffHeader.NumberOfSymbols];
|
||||||
|
|
||||||
|
// Retrieve the symbol table
|
||||||
|
if (FileLength < StringTableOffset)
|
||||||
|
{
|
||||||
|
throw new Exception("Symbol table is larger than the file size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream.Seek(CoffHeader.PointerToSymbolTable, SeekOrigin.Begin);
|
||||||
|
int NumberofRegularSymbols = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Go through each symbol table looking for auxiliary symbols to parse
|
||||||
|
|
||||||
|
Currently supported auxiliary symbol table entry formats:
|
||||||
|
1) .file
|
||||||
|
2) Entry names that match the name of a section header
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSymbols; i++)
|
||||||
|
{
|
||||||
|
// Parse the symbol tables regardless of whether they are normal or auxiliary symbols
|
||||||
|
RawSymbolTable[i] = new COFF.SYMBOL_TABLE(BinaryReader);
|
||||||
|
|
||||||
|
if (RawSymbolTable[i].NumberOfAuxSymbols == 0)
|
||||||
|
{
|
||||||
|
// This symbol table entry has no auxiliary symbols
|
||||||
|
NumberofRegularSymbols++;
|
||||||
|
}
|
||||||
|
else if (RawSymbolTable[i].Name == ".file")
|
||||||
|
{
|
||||||
|
long TempPosition = FileStream.Position; // Save filestream position
|
||||||
|
// Retrieve the file name
|
||||||
|
RawSymbolTable[i].AuxSymbols = System.Text.Encoding.UTF8.GetString(BinaryReader.ReadBytes(RawSymbolTable[i].NumberOfAuxSymbols * SizeofSymbolTableEntry)).TrimEnd((Char)0);
|
||||||
|
FileStream.Seek(TempPosition, SeekOrigin.Begin); // Restore filestream position
|
||||||
|
}
|
||||||
|
else if (SectionHeaderNames.Contains(RawSymbolTable[i].Name))
|
||||||
|
{
|
||||||
|
long TempPosition = FileStream.Position; // Save filestream position
|
||||||
|
RawSymbolTable[i].AuxSymbols = new COFF.SECTION_DEFINITION(BinaryReader);
|
||||||
|
FileStream.Seek(TempPosition, SeekOrigin.Begin); // Restore filestream position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an array of symbol table entries without auxiliary table entries
|
||||||
|
COFF.SYMBOL_TABLE[] SymbolTable = new COFF.SYMBOL_TABLE[NumberofRegularSymbols];
|
||||||
|
int k = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSymbols; i++)
|
||||||
|
{
|
||||||
|
SymbolTable[k] = RawSymbolTable[i]; // FYI, the first symbol table entry will never be an aux symbol
|
||||||
|
k++;
|
||||||
|
|
||||||
|
// Skip over the auxiliary symbols
|
||||||
|
if (RawSymbolTable[i].NumberOfAuxSymbols != 0)
|
||||||
|
{
|
||||||
|
i += RawSymbolTable[i].NumberOfAuxSymbols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the section names if any of them point to the COFF string table
|
||||||
|
for (int i = 0; i < CoffHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
if (SectionHeaders[i].Name?.IndexOf('/') == 0)
|
||||||
|
{
|
||||||
|
string StringTableIndexString = SectionHeaders[i].Name[1..];
|
||||||
|
|
||||||
|
if (int.TryParse(StringTableIndexString, out int StringTableIndex))
|
||||||
|
{
|
||||||
|
StringTableIndex -= 4;
|
||||||
|
|
||||||
|
if (StringTableIndex > (StringTableLength + 4))
|
||||||
|
{
|
||||||
|
throw new Exception("String table entry exceeds the bounds of the object file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int Length = StringTable.IndexOf((Char)0, StringTableIndex);
|
||||||
|
SectionHeaders[i].Name = StringTable.Substring(StringTableIndex, Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the symbol table names
|
||||||
|
for (int i = 0; i < SymbolTable.Length; i++)
|
||||||
|
{
|
||||||
|
if (SymbolTable[i].Name?.IndexOf('/') == 0)
|
||||||
|
{
|
||||||
|
string StringTableIndexString = SymbolTable[i].Name[1..];
|
||||||
|
|
||||||
|
if (int.TryParse(StringTableIndexString, out int StringTableIndex))
|
||||||
|
{
|
||||||
|
StringTableIndex -= 4;
|
||||||
|
int Length = StringTable.IndexOf((Char)0, StringTableIndex) - StringTableIndex;
|
||||||
|
SymbolTable[i].Name = StringTable.Substring(StringTableIndex, Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply symbol names to the relocation entries
|
||||||
|
// SectionHeaders | Where-Object { _.Relocations } | % {
|
||||||
|
// _.Relocations | % { _.Name = RawSymbolTable[_.SymbolTableIndex].Name }
|
||||||
|
// }
|
||||||
|
SectionHeaders.Where(h => h.Relocations != null).ToList().ForEach(h => h.Relocations.ToList().ForEach(r => r.Name = RawSymbolTable[r.SymbolTableIndex].Name));
|
||||||
|
|
||||||
|
Result = new ParsedObjectFile
|
||||||
|
{
|
||||||
|
CoffHeader = CoffHeader,
|
||||||
|
SectionHeaders = SectionHeaders,
|
||||||
|
SymbolTable = SymbolTable
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace WPinternals
|
||||||
|
{
|
||||||
|
internal class PatchEngine
|
||||||
|
{
|
||||||
|
internal List<PatchDefinition> PatchDefinitions = new();
|
||||||
|
internal readonly List<TargetRedirection> TargetRedirections = new();
|
||||||
|
|
||||||
|
internal PatchEngine() { }
|
||||||
|
|
||||||
|
internal PatchEngine(string PatchDefinitionsXmlString)
|
||||||
|
{
|
||||||
|
XmlSerializer x = new(PatchDefinitions.GetType(), null, Array.Empty<Type>(), new XmlRootAttribute("PatchDefinitions"), "");
|
||||||
|
MemoryStream s = new(System.Text.Encoding.ASCII.GetBytes(PatchDefinitionsXmlString));
|
||||||
|
PatchDefinitions = (List<PatchDefinition>)x.Deserialize(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteDefinitions(string FilePath)
|
||||||
|
{
|
||||||
|
XmlSerializer x = new(PatchDefinitions.GetType(), null, Array.Empty<Type>(), new XmlRootAttribute("PatchDefinitions"), "");
|
||||||
|
|
||||||
|
XmlSerializerNamespaces ns = new();
|
||||||
|
ns.Add("", "");
|
||||||
|
|
||||||
|
System.IO.StreamWriter FileWriter = new(FilePath);
|
||||||
|
XmlWriter XmlWriter = XmlWriter.Create(FileWriter, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true, NewLineHandling = NewLineHandling.Entitize });
|
||||||
|
|
||||||
|
FileWriter.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("<!--");
|
||||||
|
FileWriter.WriteLine("Copyright(c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("Permission is hereby granted, free of charge, to any person obtaining a");
|
||||||
|
FileWriter.WriteLine("copy of this software and associated documentation files(the \"Software\"),");
|
||||||
|
FileWriter.WriteLine("to deal in the Software without restriction, including without limitation");
|
||||||
|
FileWriter.WriteLine("the rights to use, copy, modify, merge, publish, distribute, sublicense,");
|
||||||
|
FileWriter.WriteLine("and / or sell copies of the Software, and to permit persons to whom the");
|
||||||
|
FileWriter.WriteLine("Software is furnished to do so, subject to the following conditions:");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("The above copyright notice and this permission notice shall be included in");
|
||||||
|
FileWriter.WriteLine("all copies or substantial portions of the Software.");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
FileWriter.WriteLine("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR");
|
||||||
|
FileWriter.WriteLine("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,");
|
||||||
|
FileWriter.WriteLine("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE");
|
||||||
|
FileWriter.WriteLine("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER");
|
||||||
|
FileWriter.WriteLine("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING");
|
||||||
|
FileWriter.WriteLine("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER");
|
||||||
|
FileWriter.WriteLine("DEALINGS IN THE SOFTWARE.");
|
||||||
|
FileWriter.WriteLine("-->");
|
||||||
|
FileWriter.WriteLine("");
|
||||||
|
|
||||||
|
x.Serialize(XmlWriter, PatchDefinitions, ns);
|
||||||
|
|
||||||
|
FileWriter.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _TargetPath = null;
|
||||||
|
internal string TargetPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _TargetPath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_TargetPath = value.TrimEnd(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TargetRedirection
|
||||||
|
{
|
||||||
|
private string _RelativePath;
|
||||||
|
private string _TargetPath;
|
||||||
|
|
||||||
|
internal TargetRedirection(string RelativePath, string TargetPath)
|
||||||
|
{
|
||||||
|
this.RelativePath = RelativePath;
|
||||||
|
this.TargetPath = TargetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string RelativePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _RelativePath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_RelativePath = value.TrimStart(new char[] { '\\' }).TrimEnd(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string TargetPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _TargetPath;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_TargetPath = value.TrimEnd(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class PatchDefinition
|
||||||
|
{
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public List<TargetVersion> TargetVersions = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class TargetVersion
|
||||||
|
{
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Description;
|
||||||
|
|
||||||
|
public List<TargetFile> TargetFiles = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class TargetFile
|
||||||
|
{
|
||||||
|
private string _Path;
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Path
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Path;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Path = value.TrimStart(new char[] { '\\' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] HashOriginal;
|
||||||
|
[XmlAttribute("HashOriginal")]
|
||||||
|
public string HashOriginalAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(HashOriginal, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
HashOriginal = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] HashPatched;
|
||||||
|
[XmlAttribute("HashPatched")]
|
||||||
|
public string HashPatchedAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(HashPatched, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
HashPatched = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Patch> Patches = new();
|
||||||
|
public List<TargetFile> Obsolete = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must be public to be serializable
|
||||||
|
/// </summary>
|
||||||
|
public class Patch
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
public UInt32 Address;
|
||||||
|
[XmlAttribute("Address")]
|
||||||
|
public string AddressAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "0x" + Address.ToString("X8");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
string NewValue = value;
|
||||||
|
if (NewValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
NewValue = NewValue[2..];
|
||||||
|
Address = Convert.ToUInt32(NewValue, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] OriginalBytes;
|
||||||
|
[XmlAttribute("OriginalBytes")]
|
||||||
|
public string OriginalBytesAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(OriginalBytes, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
OriginalBytes = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public byte[] PatchedBytes;
|
||||||
|
[XmlAttribute("PatchedBytes")]
|
||||||
|
public string PatchedBytesAsString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Converter.ConvertHexToString(PatchedBytes, "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
PatchedBytes = Converter.ConvertStringToHex(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
|
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="MainForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,818 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
// Explanation of PE header here:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/ms809762.aspx
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Linq;
|
||||||
|
using WPinternals;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
#region Structs
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_DOS_HEADER
|
||||||
|
{
|
||||||
|
public UInt16 e_magic;
|
||||||
|
public UInt16 e_cblp;
|
||||||
|
public UInt16 e_cp;
|
||||||
|
public UInt16 e_crlc;
|
||||||
|
public UInt16 e_cparhdr;
|
||||||
|
public UInt16 e_minalloc;
|
||||||
|
public UInt16 e_maxalloc;
|
||||||
|
public UInt16 e_ss;
|
||||||
|
public UInt16 e_sp;
|
||||||
|
public UInt16 e_csum;
|
||||||
|
public UInt16 e_ip;
|
||||||
|
public UInt16 e_cs;
|
||||||
|
public UInt16 e_lfarlc;
|
||||||
|
public UInt16 e_ovno;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||||
|
public UInt16[] e_res1;
|
||||||
|
public UInt16 e_oemid;
|
||||||
|
public UInt16 e_oeminfo;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||||
|
public UInt16[] e_res2;
|
||||||
|
public UInt32 e_lfanew;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_NT_HEADERS
|
||||||
|
{
|
||||||
|
public UInt32 Signature;
|
||||||
|
public IMAGE_FILE_HEADER FileHeader;
|
||||||
|
public IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
|
||||||
|
public IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_FILE_HEADER
|
||||||
|
{
|
||||||
|
public UInt16 Machine;
|
||||||
|
public UInt16 NumberOfSections;
|
||||||
|
public UInt32 TimeDateStamp;
|
||||||
|
public UInt32 PointerToSymbolTable;
|
||||||
|
public UInt32 NumberOfSymbols;
|
||||||
|
public UInt16 SizeOfOptionalHeader;
|
||||||
|
public UInt16 Characteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_OPTIONAL_HEADER32
|
||||||
|
{
|
||||||
|
public UInt16 Magic;
|
||||||
|
public Byte MajorLinkerVersion;
|
||||||
|
public Byte MinorLinkerVersion;
|
||||||
|
public UInt32 SizeOfCode;
|
||||||
|
public UInt32 SizeOfInitializedData;
|
||||||
|
public UInt32 SizeOfUninitializedData;
|
||||||
|
public UInt32 AddressOfEntryPoint;
|
||||||
|
public UInt32 BaseOfCode;
|
||||||
|
public UInt32 BaseOfData;
|
||||||
|
public UInt32 ImageBase;
|
||||||
|
public UInt32 SectionAlignment;
|
||||||
|
public UInt32 FileAlignment;
|
||||||
|
public UInt16 MajorOperatingSystemVersion;
|
||||||
|
public UInt16 MinorOperatingSystemVersion;
|
||||||
|
public UInt16 MajorImageVersion;
|
||||||
|
public UInt16 MinorImageVersion;
|
||||||
|
public UInt16 MajorSubsystemVersion;
|
||||||
|
public UInt16 MinorSubsystemVersion;
|
||||||
|
public UInt32 Win32VersionValue;
|
||||||
|
public UInt32 SizeOfImage;
|
||||||
|
public UInt32 SizeOfHeaders;
|
||||||
|
public UInt32 CheckSum;
|
||||||
|
public UInt16 Subsystem;
|
||||||
|
public UInt16 DllCharacteristics;
|
||||||
|
public UInt32 SizeOfStackReserve;
|
||||||
|
public UInt32 SizeOfStackCommit;
|
||||||
|
public UInt32 SizeOfHeapReserve;
|
||||||
|
public UInt32 SizeOfHeapCommit;
|
||||||
|
public UInt32 LoaderFlags;
|
||||||
|
public UInt32 NumberOfRvaAndSizes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||||
|
public IMAGE_DATA_DIRECTORY[] DataDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_OPTIONAL_HEADER64
|
||||||
|
{
|
||||||
|
public UInt16 Magic;
|
||||||
|
public Byte MajorLinkerVersion;
|
||||||
|
public Byte MinorLinkerVersion;
|
||||||
|
public UInt32 SizeOfCode;
|
||||||
|
public UInt32 SizeOfInitializedData;
|
||||||
|
public UInt32 SizeOfUninitializedData;
|
||||||
|
public UInt32 AddressOfEntryPoint;
|
||||||
|
public UInt32 BaseOfCode;
|
||||||
|
public UInt64 ImageBase;
|
||||||
|
public UInt32 SectionAlignment;
|
||||||
|
public UInt32 FileAlignment;
|
||||||
|
public UInt16 MajorOperatingSystemVersion;
|
||||||
|
public UInt16 MinorOperatingSystemVersion;
|
||||||
|
public UInt16 MajorImageVersion;
|
||||||
|
public UInt16 MinorImageVersion;
|
||||||
|
public UInt16 MajorSubsystemVersion;
|
||||||
|
public UInt16 MinorSubsystemVersion;
|
||||||
|
public UInt32 Win32VersionValue;
|
||||||
|
public UInt32 SizeOfImage;
|
||||||
|
public UInt32 SizeOfHeaders;
|
||||||
|
public UInt32 CheckSum;
|
||||||
|
public UInt16 Subsystem;
|
||||||
|
public UInt16 DllCharacteristics;
|
||||||
|
public UInt64 SizeOfStackReserve;
|
||||||
|
public UInt64 SizeOfStackCommit;
|
||||||
|
public UInt64 SizeOfHeapReserve;
|
||||||
|
public UInt64 SizeOfHeapCommit;
|
||||||
|
public UInt32 LoaderFlags;
|
||||||
|
public UInt32 NumberOfRvaAndSizes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||||
|
public IMAGE_DATA_DIRECTORY[] DataDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_DATA_DIRECTORY
|
||||||
|
{
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
public UInt32 Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_SECTION_HEADER
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
|
||||||
|
public string Name;
|
||||||
|
public Misc Misc;
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
public UInt32 SizeOfRawData;
|
||||||
|
public UInt32 PointerToRawData;
|
||||||
|
public UInt32 PointerToRelocations;
|
||||||
|
public UInt32 PointerToLinenumbers;
|
||||||
|
public UInt16 NumberOfRelocations;
|
||||||
|
public UInt16 NumberOfLinenumbers;
|
||||||
|
public UInt32 Characteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct Misc
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public UInt32 PhysicalAddress;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public UInt32 VirtualSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGE_EXPORT_DIRECTORY
|
||||||
|
{
|
||||||
|
public UInt32 Characteristics;
|
||||||
|
public UInt32 TimeDateStamp;
|
||||||
|
public UInt16 MajorVersion;
|
||||||
|
public UInt16 MinorVersion;
|
||||||
|
public UInt32 Name;
|
||||||
|
public UInt32 Base;
|
||||||
|
public UInt32 NumberOfFunctions;
|
||||||
|
public UInt32 NumberOfNames;
|
||||||
|
/// <summary>
|
||||||
|
/// RVA from base of image
|
||||||
|
/// </summary>
|
||||||
|
public UInt32 AddressOfFunctions;
|
||||||
|
/// <summary>
|
||||||
|
/// RVA from base of image
|
||||||
|
/// </summary>
|
||||||
|
public UInt32 AddressOfNames;
|
||||||
|
/// <summary>
|
||||||
|
/// RVA from base of image
|
||||||
|
/// </summary>
|
||||||
|
public UInt32 AddressOfNameOrdinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct IMAGE_IMPORT_DESCRIPTOR
|
||||||
|
{
|
||||||
|
#region union
|
||||||
|
/// <summary>
|
||||||
|
/// CSharp doesnt really support unions, but they can be emulated by a field offset 0
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public uint Characteristics; // 0 for terminating null import descriptor
|
||||||
|
/// <summary>
|
||||||
|
/// RVA to original unbound IAT (PIMAGE_THUNK_DATA)
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public uint OriginalFirstThunk;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public uint TimeDateStamp;
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public uint ForwarderChain;
|
||||||
|
[FieldOffset(12)]
|
||||||
|
public uint Name;
|
||||||
|
[FieldOffset(16)]
|
||||||
|
public uint FirstThunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct RUNTIME_FUNCTION_64
|
||||||
|
{
|
||||||
|
public UInt64 RVAofBeginAddress;
|
||||||
|
public UInt64 RVAofEndAddress;
|
||||||
|
public UInt64 RVAofUnwindData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct RUNTIME_FUNCTION_32
|
||||||
|
{
|
||||||
|
public UInt32 RVAofBeginAddress;
|
||||||
|
public UInt32 RVAofUnwindData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public static class SectionFlags
|
||||||
|
{
|
||||||
|
public const UInt32 IMAGE_SCN_CNT_CODE = 0x00000020;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum ResourceType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Accelerator table.
|
||||||
|
/// </summary>
|
||||||
|
RT_ACCELERATOR = 9,
|
||||||
|
/// <summary>
|
||||||
|
/// Animated cursor.
|
||||||
|
/// </summary>
|
||||||
|
RT_ANICURSOR = 21,
|
||||||
|
/// <summary>
|
||||||
|
/// Animated icon.
|
||||||
|
/// </summary>
|
||||||
|
RT_ANIICON = 22,
|
||||||
|
/// <summary>
|
||||||
|
/// Bitmap resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_BITMAP = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-dependent cursor resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_CURSOR = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Dialog box.
|
||||||
|
/// </summary>
|
||||||
|
RT_DIALOG = 5,
|
||||||
|
/// <summary>
|
||||||
|
/// Allows
|
||||||
|
/// </summary>
|
||||||
|
RT_DLGINCLUDE = 17,
|
||||||
|
/// <summary>
|
||||||
|
/// Font resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_FONT = 8,
|
||||||
|
/// <summary>
|
||||||
|
/// Font directory resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_FONTDIR = 7,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-independent cursor resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_GROUP_CURSOR = RT_CURSOR + 11,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-independent icon resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_GROUP_ICON = RT_ICON + 11,
|
||||||
|
/// <summary>
|
||||||
|
/// HTML resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_HTML = 23,
|
||||||
|
/// <summary>
|
||||||
|
/// Hardware-dependent icon resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_ICON = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// Side-by-Side Assembly Manifest.
|
||||||
|
/// </summary>
|
||||||
|
RT_MANIFEST = 24,
|
||||||
|
/// <summary>
|
||||||
|
/// Menu resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_MENU = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// Message-table entry.
|
||||||
|
/// </summary>
|
||||||
|
RT_MESSAGETABLE = 11,
|
||||||
|
/// <summary>
|
||||||
|
/// Plug and Play resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_PLUGPLAY = 19,
|
||||||
|
/// <summary>
|
||||||
|
/// Application-defined resource (raw data).
|
||||||
|
/// </summary>
|
||||||
|
RT_RCDATA = 10,
|
||||||
|
/// <summary>
|
||||||
|
/// String-table entry.
|
||||||
|
/// </summary>
|
||||||
|
RT_STRING = 6,
|
||||||
|
/// <summary>
|
||||||
|
/// Version resource.
|
||||||
|
/// </summary>
|
||||||
|
RT_VERSION = 16,
|
||||||
|
/// <summary>
|
||||||
|
/// VXD
|
||||||
|
/// </summary>
|
||||||
|
RT_VXD = 20,
|
||||||
|
RT_DLGINIT = 240,
|
||||||
|
RT_TOOLBAR = 241
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public class PeFile
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public readonly IMAGE_DOS_HEADER DosHeader;
|
||||||
|
public IMAGE_NT_HEADERS NtHeaders;
|
||||||
|
private readonly IList<IMAGE_SECTION_HEADER> _sectionHeaders = new List<IMAGE_SECTION_HEADER>();
|
||||||
|
|
||||||
|
public List<Section> Sections = new();
|
||||||
|
public List<FunctionDescriptor> Exports = new();
|
||||||
|
public List<FunctionDescriptor> Imports = new();
|
||||||
|
public List<FunctionDescriptor> RuntimeFunctions = new();
|
||||||
|
public byte[] Buffer;
|
||||||
|
public UInt64 ImageBase;
|
||||||
|
public UInt64 EntryPoint;
|
||||||
|
public UInt64 ExportDirectoryVirtualOffset;
|
||||||
|
public UInt64 ImportDirectoryVirtualOffset;
|
||||||
|
public UInt64 RuntimeDirectoryVirtualOffset;
|
||||||
|
public UInt32 RuntimeDirectorySize;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public PeFile(string Path): this(File.ReadAllBytes(Path))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PeFile(byte[] Buffer)
|
||||||
|
{
|
||||||
|
int P = 0;
|
||||||
|
|
||||||
|
this.Buffer = Buffer;
|
||||||
|
|
||||||
|
// Read MS-DOS header section
|
||||||
|
DosHeader = MarshalBytesTo<IMAGE_DOS_HEADER>(Buffer, P);
|
||||||
|
|
||||||
|
// MS-DOS magic number should read 'MZ'
|
||||||
|
if (DosHeader.e_magic != 0x5a4d)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("File is not a portable executable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read NT Headers
|
||||||
|
P = (int)DosHeader.e_lfanew;
|
||||||
|
NtHeaders.Signature = MarshalBytesTo<UInt32>(Buffer, P);
|
||||||
|
|
||||||
|
// Make sure we have 'PE' in the pe signature
|
||||||
|
if (NtHeaders.Signature != 0x4550)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid portable executable signature in NT header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
P += sizeof(UInt32);
|
||||||
|
NtHeaders.FileHeader = MarshalBytesTo<IMAGE_FILE_HEADER>(Buffer, P);
|
||||||
|
|
||||||
|
// Read optional headers
|
||||||
|
P += Marshal.SizeOf(typeof(IMAGE_FILE_HEADER));
|
||||||
|
if (Is32bitAssembly())
|
||||||
|
{
|
||||||
|
Load32bitOptionalHeaders(Buffer, P);
|
||||||
|
ImageBase = NtHeaders.OptionalHeader32.ImageBase;
|
||||||
|
EntryPoint = NtHeaders.OptionalHeader32.AddressOfEntryPoint;
|
||||||
|
ExportDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[0].VirtualAddress;
|
||||||
|
ImportDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[1].VirtualAddress;
|
||||||
|
RuntimeDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[3].VirtualAddress;
|
||||||
|
RuntimeDirectorySize = NtHeaders.OptionalHeader32.DataDirectory[3].Size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Load64bitOptionalHeaders(Buffer, P);
|
||||||
|
ImageBase = NtHeaders.OptionalHeader64.ImageBase;
|
||||||
|
EntryPoint = NtHeaders.OptionalHeader64.AddressOfEntryPoint;
|
||||||
|
ExportDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[0].VirtualAddress;
|
||||||
|
ImportDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[1].VirtualAddress;
|
||||||
|
RuntimeDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[3].VirtualAddress;
|
||||||
|
RuntimeDirectorySize = NtHeaders.OptionalHeader64.DataDirectory[3].Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Sections
|
||||||
|
_sectionHeaders.ToList().ForEach(s =>
|
||||||
|
{
|
||||||
|
byte[] RawCode = new byte[s.SizeOfRawData];
|
||||||
|
System.Buffer.BlockCopy(Buffer, (int)s.PointerToRawData, RawCode, 0, (int)s.SizeOfRawData);
|
||||||
|
|
||||||
|
Sections.Add(new Section { Header = s, Buffer = RawCode, VirtualAddress = s.VirtualAddress + (UInt32)ImageBase, VirtualSize = s.Misc.VirtualSize, IsCode = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_CNT_CODE) != 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read Exports
|
||||||
|
// TODO: Proper support for 64-bit files
|
||||||
|
if (ExportDirectoryVirtualOffset != 0)
|
||||||
|
{
|
||||||
|
IMAGE_EXPORT_DIRECTORY ExportDirectory = MarshalBytesTo<IMAGE_EXPORT_DIRECTORY>(Buffer, (int)ConvertVirtualOffsetToRawOffset((uint)ExportDirectoryVirtualOffset));
|
||||||
|
if (ExportDirectory.AddressOfNames != 0)
|
||||||
|
{
|
||||||
|
Section ExportsSection = GetSectionForVirtualAddress((uint)(ImageBase + ExportDirectory.AddressOfNames));
|
||||||
|
UInt32 OffsetNames = (UInt32)(ImageBase + ExportDirectory.AddressOfNames - ExportsSection.VirtualAddress);
|
||||||
|
UInt32 OffsetOrdinals = (UInt32)(ImageBase + ExportDirectory.AddressOfNameOrdinals - ExportsSection.VirtualAddress);
|
||||||
|
UInt32 OffsetFunctions = (UInt32)(ImageBase + ExportDirectory.AddressOfFunctions - ExportsSection.VirtualAddress);
|
||||||
|
string[] ExportNames = new string[ExportDirectory.NumberOfNames];
|
||||||
|
UInt16[] Ordinals = new UInt16[ExportDirectory.NumberOfNames];
|
||||||
|
UInt32[] VirtualAddresses = new UInt32[ExportDirectory.NumberOfFunctions];
|
||||||
|
for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
|
||||||
|
{
|
||||||
|
UInt32 NamesRVA = ByteOperations.ReadUInt32(ExportsSection.Buffer, (UInt32)(OffsetNames + (i * sizeof(UInt32))));
|
||||||
|
UInt32 NameOffset = (UInt32)(NamesRVA + ImageBase - ExportsSection.VirtualAddress);
|
||||||
|
ExportNames[i] = ByteOperations.ReadAsciiString(ExportsSection.Buffer, NameOffset);
|
||||||
|
|
||||||
|
Ordinals[i] = ByteOperations.ReadUInt16(ExportsSection.Buffer, (UInt32)(OffsetOrdinals + (i * sizeof(UInt16))));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ExportDirectory.NumberOfFunctions; i++)
|
||||||
|
{
|
||||||
|
VirtualAddresses[i] = ByteOperations.ReadUInt32(ExportsSection.Buffer, (UInt32)(OffsetFunctions + (i * sizeof(UInt32))));
|
||||||
|
VirtualAddresses[i] -= VirtualAddresses[i] % 2; // Round down for Thumb2
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
|
||||||
|
{
|
||||||
|
Exports.Add(new FunctionDescriptor() { Name = ExportNames[i], VirtualAddress = (UInt32)(ImageBase + VirtualAddresses[Ordinals[i]]) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Imports
|
||||||
|
// TODO: Proper support for 64-bit files
|
||||||
|
if (ImportDirectoryVirtualOffset != 0)
|
||||||
|
{
|
||||||
|
Section ImportsSection = GetSectionForVirtualAddress((uint)(ImageBase + ImportDirectoryVirtualOffset));
|
||||||
|
IMAGE_IMPORT_DESCRIPTOR ImportDirectory;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ImportDirectory = MarshalBytesTo<IMAGE_IMPORT_DESCRIPTOR>(ImportsSection.Buffer, (int)(ImportDirectoryVirtualOffset - (ImportsSection.VirtualAddress - ImageBase)));
|
||||||
|
if (ImportDirectory.OriginalFirstThunk != 0)
|
||||||
|
{
|
||||||
|
// ImportDirectory.OriginalFirstThunk is the VirtualOffset to an array of VirtualOffsets. They point to a struct with a word-value, followed by a zero-terminated ascii-string, which is the name of the import.
|
||||||
|
// ImportDirectory.FirstThunk points to an array pointers which is the actual import table.
|
||||||
|
UInt32 NameArrayOffset = ImportDirectory.OriginalFirstThunk - (ImportsSection.VirtualAddress - (UInt32)ImageBase);
|
||||||
|
UInt32 NameOffset;
|
||||||
|
int i = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
NameOffset = ByteOperations.ReadUInt32(ImportsSection.Buffer, NameArrayOffset);
|
||||||
|
if ((NameOffset < (ImportsSection.VirtualAddress - ImageBase)) || (NameOffset >= (ImportsSection.VirtualAddress + ImportsSection.VirtualSize - ImageBase)))
|
||||||
|
NameOffset = 0; // ImportDirectory.OriginalFirstThunk seems to contain Characteristics, not an offset to an array.
|
||||||
|
NameArrayOffset += sizeof(UInt32);
|
||||||
|
if (NameOffset != 0)
|
||||||
|
{
|
||||||
|
string Name = ByteOperations.ReadAsciiString(ImportsSection.Buffer, NameOffset + 2 - (ImportsSection.VirtualAddress - (UInt32)ImageBase));
|
||||||
|
Imports.Add(new FunctionDescriptor() { Name = Name, VirtualAddress = ImportDirectory.FirstThunk + (UInt32)ImageBase + (UInt32)(i * sizeof(UInt32)) });
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (NameOffset != 0);
|
||||||
|
|
||||||
|
ImportDirectoryVirtualOffset += (UInt64)Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ImportDirectory.OriginalFirstThunk != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Runtime functions
|
||||||
|
// TODO: Proper support for 64-bit files
|
||||||
|
if (RuntimeDirectoryVirtualOffset != 0)
|
||||||
|
{
|
||||||
|
Section RuntimeSection = GetSectionForVirtualAddress((uint)(ImageBase + RuntimeDirectoryVirtualOffset));
|
||||||
|
RUNTIME_FUNCTION_32 RuntimeFunction;
|
||||||
|
for (int i = 0; i < (RuntimeDirectorySize / Marshal.SizeOf(typeof(RUNTIME_FUNCTION_32))); i++)
|
||||||
|
{
|
||||||
|
RuntimeFunction = MarshalBytesTo<RUNTIME_FUNCTION_32>(RuntimeSection.Buffer, (int)(RuntimeDirectoryVirtualOffset - (RuntimeSection.VirtualAddress - ImageBase)) + (i * Marshal.SizeOf(typeof(RUNTIME_FUNCTION_32))));
|
||||||
|
RuntimeFunctions.Add(new FunctionDescriptor() { Name = null, VirtualAddress = (UInt32)(RuntimeFunction.RVAofBeginAddress + ImageBase) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 GetChecksumOffset()
|
||||||
|
{
|
||||||
|
return ByteOperations.ReadUInt32(Buffer, 0x3C) + +0x58;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UInt32 CalculateChecksum()
|
||||||
|
{
|
||||||
|
UInt32 Checksum = 0;
|
||||||
|
UInt32 Hi;
|
||||||
|
|
||||||
|
// Clear file checksum
|
||||||
|
// ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(), 0);
|
||||||
|
UInt32 ChecksumOffset = GetChecksumOffset();
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < ((UInt32)Buffer.Length & 0xfffffffe); i += 2)
|
||||||
|
{
|
||||||
|
if ((i < ChecksumOffset) || (i >= (ChecksumOffset + 4)))
|
||||||
|
Checksum += ByteOperations.ReadUInt16(Buffer, i);
|
||||||
|
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((Buffer.Length % 2) != 0)
|
||||||
|
{
|
||||||
|
Checksum += (UInt32)ByteOperations.ReadUInt8(Buffer, (UInt32)Buffer.Length - 1);
|
||||||
|
Hi = Checksum >> 16;
|
||||||
|
if (Hi != 0)
|
||||||
|
{
|
||||||
|
Checksum = Hi + (Checksum & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Checksum += (UInt32)Buffer.Length;
|
||||||
|
|
||||||
|
// Write file checksum
|
||||||
|
// ByteOperations.WriteUInt32(Buffer, GetChecksumOffset(), Checksum);
|
||||||
|
|
||||||
|
return Checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_DOS_HEADER GetDOSHeader()
|
||||||
|
{
|
||||||
|
return DosHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 GetPESignature()
|
||||||
|
{
|
||||||
|
return NtHeaders.Signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_FILE_HEADER GetFileHeader()
|
||||||
|
{
|
||||||
|
return NtHeaders.FileHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_OPTIONAL_HEADER32 GetOptionalHeaders32()
|
||||||
|
{
|
||||||
|
return NtHeaders.OptionalHeader32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMAGE_OPTIONAL_HEADER64 GetOptionalHeaders64()
|
||||||
|
{
|
||||||
|
return NtHeaders.OptionalHeader64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<IMAGE_SECTION_HEADER> GetSectionHeaders()
|
||||||
|
{
|
||||||
|
return _sectionHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Is32bitAssembly()
|
||||||
|
{
|
||||||
|
return (NtHeaders.FileHeader.Characteristics & 0x0100) == 0x0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Load64bitOptionalHeaders(byte[] Buffer, int Offset)
|
||||||
|
{
|
||||||
|
NtHeaders.OptionalHeader64 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER64>(Buffer, Offset);
|
||||||
|
|
||||||
|
// Should have 10 data directories
|
||||||
|
if (NtHeaders.OptionalHeader64.NumberOfRvaAndSizes != 0x10)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid number of data directories in NT header");
|
||||||
|
}
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER64));
|
||||||
|
|
||||||
|
for (int i = 0; i < NtHeaders.FileHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
_sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(Buffer, Offset));
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Load32bitOptionalHeaders(byte[] Buffer, int Offset)
|
||||||
|
{
|
||||||
|
NtHeaders.OptionalHeader32 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER32>(Buffer, Offset);
|
||||||
|
|
||||||
|
// Should have 10 data directories
|
||||||
|
if (NtHeaders.OptionalHeader32.NumberOfRvaAndSizes != 0x10)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid number of data directories in NT header");
|
||||||
|
}
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER32));
|
||||||
|
|
||||||
|
for (int i = 0; i < NtHeaders.FileHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
_sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(Buffer, Offset));
|
||||||
|
Offset += Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 ConvertVirtualOffsetToRawOffset(UInt32 VirtualOffset)
|
||||||
|
{
|
||||||
|
// TODO: Add 64-bit support
|
||||||
|
if (VirtualOffset < (Sections.OrderBy(s => s.VirtualAddress).First().VirtualAddress - GetOptionalHeaders32().ImageBase))
|
||||||
|
return VirtualOffset;
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER? SectionHeaderSelection = _sectionHeaders.FirstOrDefault(h => (h.VirtualAddress <= VirtualOffset) && ((h.VirtualAddress + h.SizeOfRawData) > VirtualOffset));
|
||||||
|
if (SectionHeaderSelection == null)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER SectionHeader = (IMAGE_SECTION_HEADER)SectionHeaderSelection;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(SectionHeader.Name) || (SectionHeader.SizeOfRawData == 0))
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
return SectionHeader.PointerToRawData + (VirtualOffset - SectionHeader.VirtualAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt32 ConvertVirtualAddressToRawOffset(UInt32 VirtualAddress)
|
||||||
|
{
|
||||||
|
return ConvertVirtualOffsetToRawOffset((UInt32)(VirtualAddress - ImageBase));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint ConvertRawOffsetToVirtualAddress(uint RawOffset)
|
||||||
|
{
|
||||||
|
// TODO: Add 64-bit support
|
||||||
|
if (RawOffset < Sections.OrderBy(s => s.VirtualAddress).First().Header.PointerToRawData)
|
||||||
|
return RawOffset + GetOptionalHeaders32().ImageBase;
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER? SectionHeaderSelection = _sectionHeaders.FirstOrDefault(h => (h.PointerToRawData <= RawOffset) && ((h.PointerToRawData + h.SizeOfRawData) > RawOffset));
|
||||||
|
if (SectionHeaderSelection == null)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
IMAGE_SECTION_HEADER SectionHeader = (IMAGE_SECTION_HEADER)SectionHeaderSelection;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(SectionHeader.Name) || (SectionHeader.SizeOfRawData == 0))
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
return RawOffset - SectionHeader.PointerToRawData + SectionHeader.VirtualAddress + GetOptionalHeaders32().ImageBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Section GetSectionForVirtualAddress(UInt32 VirtualAddress)
|
||||||
|
{
|
||||||
|
return Sections.Find(s => (VirtualAddress >= s.VirtualAddress) && (VirtualAddress < (s.VirtualAddress + s.VirtualSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T MarshalBytesTo<T>(BinaryReader reader)
|
||||||
|
{
|
||||||
|
// Unmanaged data
|
||||||
|
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
|
||||||
|
|
||||||
|
// Create a pointer to the unmanaged data pinned in memory to be accessed by unmanaged code
|
||||||
|
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||||
|
|
||||||
|
// Use our previously created pointer to unmanaged data and marshal to the specified type
|
||||||
|
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||||
|
|
||||||
|
// Deallocate pointer
|
||||||
|
handle.Free();
|
||||||
|
|
||||||
|
return theStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T MarshalBytesTo<T>(byte[] Binary, int Offset)
|
||||||
|
{
|
||||||
|
// Unmanaged data
|
||||||
|
byte[] bytes = new byte[Marshal.SizeOf(typeof(T))];
|
||||||
|
System.Buffer.BlockCopy(Binary, Offset, bytes, 0, Marshal.SizeOf(typeof(T)));
|
||||||
|
|
||||||
|
// Create a pointer to the unmanaged data pinned in memory to be accessed by unmanaged code
|
||||||
|
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||||
|
|
||||||
|
// Use our previously created pointer to unmanaged data and marshal to the specified type
|
||||||
|
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||||
|
|
||||||
|
// Deallocate pointer
|
||||||
|
handle.Free();
|
||||||
|
|
||||||
|
return theStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal byte[] GetResource(int[] Index)
|
||||||
|
{
|
||||||
|
UInt32 PEPointer = ByteOperations.ReadUInt32(Buffer, 0x3C);
|
||||||
|
UInt16 OptionalHeaderSize = ByteOperations.ReadUInt16(Buffer, PEPointer + 0x14);
|
||||||
|
UInt32 SectionTablePointer = PEPointer + 0x18 + OptionalHeaderSize;
|
||||||
|
UInt16 SectionCount = ByteOperations.ReadUInt16(Buffer, PEPointer + 0x06);
|
||||||
|
UInt32? ResourceSectionEntryPointer = null;
|
||||||
|
for (int i = 0; i < SectionCount; i++)
|
||||||
|
{
|
||||||
|
string SectionName = ByteOperations.ReadAsciiString(Buffer, (UInt32)(SectionTablePointer + (i * 0x28)), 8);
|
||||||
|
int e = SectionName.IndexOf('\0');
|
||||||
|
if (e >= 0)
|
||||||
|
SectionName = SectionName.Substring(0, e);
|
||||||
|
if (SectionName == ".rsrc")
|
||||||
|
{
|
||||||
|
ResourceSectionEntryPointer = (UInt32)(SectionTablePointer + (i * 0x28));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ResourceSectionEntryPointer == null)
|
||||||
|
throw new Exception("Resource-section not found");
|
||||||
|
UInt32 ResourceRawSize = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x10);
|
||||||
|
UInt32 ResourceRawPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x14);
|
||||||
|
UInt32 ResourceVirtualPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x0C);
|
||||||
|
|
||||||
|
UInt32 p = ResourceRawPointer;
|
||||||
|
for (int i = 0; i < Index.Length; i++)
|
||||||
|
{
|
||||||
|
UInt16 ResourceNamedEntryCount = ByteOperations.ReadUInt16(Buffer, p + 0x0c);
|
||||||
|
UInt16 ResourceIdEntryCount = ByteOperations.ReadUInt16(Buffer, p + 0x0e);
|
||||||
|
for (int j = ResourceNamedEntryCount; j < ResourceNamedEntryCount + ResourceIdEntryCount; j++)
|
||||||
|
{
|
||||||
|
UInt32 ResourceID = ByteOperations.ReadUInt32(Buffer, (UInt32)(p + 0x10 + (j * 8)));
|
||||||
|
UInt32 NextPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)(p + 0x10 + (j * 8) + 4));
|
||||||
|
if (ResourceID == (UInt32)Index[i])
|
||||||
|
{
|
||||||
|
// Check high bit
|
||||||
|
if ((NextPointer & 0x80000000) == 0 != (i == (Index.Length - 1)))
|
||||||
|
throw new Exception("Bad resource path");
|
||||||
|
|
||||||
|
p = ResourceRawPointer + (NextPointer & 0x7fffffff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 ResourceValuePointer = ByteOperations.ReadUInt32(Buffer, p) - ResourceVirtualPointer + ResourceRawPointer;
|
||||||
|
UInt32 ResourceValueSize = ByteOperations.ReadUInt32(Buffer, p + 4);
|
||||||
|
|
||||||
|
byte[] ResourceValue = new byte[ResourceValueSize];
|
||||||
|
Array.Copy(Buffer, ResourceValuePointer, ResourceValue, 0, ResourceValueSize);
|
||||||
|
|
||||||
|
return ResourceValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Version GetFileVersion()
|
||||||
|
{
|
||||||
|
byte[] version = GetResource(new int[] { (int)ResourceType.RT_VERSION, 1, 1033 });
|
||||||
|
|
||||||
|
// RT_VERSION format:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx
|
||||||
|
const UInt32 FixedFileInfoPointer = 0x28;
|
||||||
|
UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0A);
|
||||||
|
UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x08);
|
||||||
|
UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0E);
|
||||||
|
UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0C);
|
||||||
|
|
||||||
|
return new Version(Major, Minor, Build, Revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Version GetProductVersion()
|
||||||
|
{
|
||||||
|
byte[] version = GetResource(new int[] { (int)ResourceType.RT_VERSION, 1, 1033 });
|
||||||
|
|
||||||
|
// RT_VERSION format:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx
|
||||||
|
const UInt32 FixedFileInfoPointer = 0x28;
|
||||||
|
UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x12);
|
||||||
|
UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x10);
|
||||||
|
UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x16);
|
||||||
|
UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x14);
|
||||||
|
|
||||||
|
return new Version(Major, Minor, Build, Revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Section
|
||||||
|
{
|
||||||
|
public IMAGE_SECTION_HEADER Header;
|
||||||
|
public byte[] Buffer;
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
public UInt32 VirtualSize;
|
||||||
|
public bool IsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FunctionDescriptor
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public UInt32 VirtualAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Patcher
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("ARM Patcher")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("WPinternals.net")]
|
||||||
|
[assembly: AssemblyProduct("ARM Patcher")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018 by Rene Lergner")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("b9aebca3-bcf8-4e4a-bf0e-5e764867be07")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((resourceMan == null))
|
||||||
|
{
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Patcher.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Patcher.Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Workaround for intermittent issue
|
||||||
|
https://developercommunity.visualstudio.com/content/problem/983843/dotnet-build-task-does-not-use-nugetorg-for-one-pr.html
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<clear />
|
||||||
|
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user