Upgrade patcher to work with any game

This commit is contained in:
Bepis committed 2018-04-27 20:25:31 +10:00
1 parent 980dada146
commit e8bee855d2
6 files changed
+106 -182

No files matched your search

+7 -15
View File
@@ -38,6 +38,9 @@
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>BepInEx.Patcher.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Cecil, Version=0.10.0.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.10.0\lib\net35\Mono.Cecil.dll</HintPath>
@@ -51,28 +54,17 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="EmbeddedResource.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="Resources\0Harmony.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\BepInEx.dll" />
<EmbeddedResource Include="..\bin\0Harmony.dll" />
<EmbeddedResource Include="..\bin\BepInEx.dll" />
</ItemGroup>
<Import Project="..\BepInEx.Common\BepInEx.Common.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+26
View File
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace BepInEx.Patcher
{
internal static class EmbeddedResource
{
public static byte[] Get(string resourceName)
{
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
int length = (int)stream.Length;
byte[] buffer = new byte[length];
stream.Read(buffer, 0, length);
return buffer;
}
}
}
}
+70 -13
View File
@@ -3,39 +3,88 @@ using Mono.Cecil.Cil;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using MethodAttributes = Mono.Cecil.MethodAttributes;
namespace BepInEx.Patcher
{
class Program
{
static void Error(string message)
static void WriteError(string message)
{
Console.WriteLine($"Error: {message}");
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
Environment.Exit(1);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Failed");
Console.ResetColor();
Console.WriteLine(message);
}
static void WriteSuccess()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Success");
Console.ResetColor();
}
static void Main(string[] args)
{
Console.WriteLine($"BepInEx Patcher v{Assembly.GetExecutingAssembly().GetName().Version}");
if (args.Length >= 1) //short circuit for specific dll patch
Environment.Exit(PatchUnityExe(Path.GetDirectoryName(args[0]), args[0], out string message) ? 0 : 9999);
bool hasFound = false;
int patchCount = 0;
foreach (string exePath in Directory.GetFiles(Directory.GetCurrentDirectory()))
{
string gameName = Path.GetFileNameWithoutExtension(exePath);
string managedDir = Environment.CurrentDirectory + $@"\{Path.GetFileNameWithoutExtension(exePath)}_Data\Managed";
string managedDir = Environment.CurrentDirectory + $@"\{gameName}_Data\Managed";
string unityOutputDLL = Path.GetFullPath($"{managedDir}\\UnityEngine.dll");
if (!Directory.Exists(managedDir) || !File.Exists(unityOutputDLL))
continue;
hasFound = true;
Console.Write($"Patching {gameName}... ");
if (PatchUnityExe(managedDir, unityOutputDLL, out string message))
{
WriteSuccess();
patchCount++;
}
else
{
WriteError(message);
}
}
Console.WriteLine();
if (!hasFound)
Console.WriteLine("Didn't find any games to patch! Exiting.");
else
Console.WriteLine($"Patched {patchCount} assemblies!");
System.Threading.Thread.Sleep(2000);
}
static bool PatchUnityExe(string managedDir, string unityOutputDLL, out string message)
{
message = null;
try
{
string unityOriginalDLL = Path.GetFullPath($"{managedDir}\\UnityEngine.dll.bak");
if (!File.Exists(unityOriginalDLL))
File.Copy(unityOutputDLL, unityOriginalDLL);
string harmony = Path.GetFullPath($"{managedDir}\\0Harmony.dll");
File.WriteAllBytes(harmony, Resources._0Harmony);
File.WriteAllBytes(harmony, EmbeddedResource.Get("BepInEx.Patcher.0Harmony.dll"));
string injectedDLL = Path.GetFullPath($"{managedDir}\\BepInEx.dll");
File.WriteAllBytes(injectedDLL, Resources.BepInEx);
File.WriteAllBytes(injectedDLL, EmbeddedResource.Get("BepInEx.Patcher.BepInEx.dll"));
var defaultResolver = new DefaultAssemblyResolver();
defaultResolver.AddSearchDirectory(managedDir);
@@ -44,13 +93,21 @@ namespace BepInEx.Patcher
AssemblyResolver = defaultResolver
};
AssemblyDefinition unity = AssemblyDefinition.ReadAssembly(unityOriginalDLL, rp);
AssemblyDefinition injected = AssemblyDefinition.ReadAssembly(injectedDLL, rp);
InjectAssembly(unity, injected);
using (AssemblyDefinition unity = AssemblyDefinition.ReadAssembly(unityOriginalDLL, rp))
using (AssemblyDefinition injected = AssemblyDefinition.ReadAssembly(injectedDLL, rp))
{
InjectAssembly(unity, injected);
unity.Write(unityOutputDLL);
unity.Write(unityOutputDLL);
}
}
catch (Exception e)
{
message = e.ToString();
return false;
}
return true;
}
static void InjectAssembly(AssemblyDefinition unity, AssemblyDefinition injected)
+3 -3
View File
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BepInEx.Patcher")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyCopyright("Copyright © Bepis 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 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")]
[assembly: AssemblyVersion("3.1.0.0")]
[assembly: AssemblyFileVersion("3.1.0.0")]
-83
View File
@@ -1,83 +0,0 @@
//------------------------------------------------------------------------------
// <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 BepInEx.Patcher {
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("BepInEx.Patcher.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;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] _0Harmony {
get {
object obj = ResourceManager.GetObject("_0Harmony", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] BepInEx {
get {
object obj = ResourceManager.GetObject("BepInEx", resourceCulture);
return ((byte[])(obj));
}
}
}
}
-68
View File
@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<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=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>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="BepInEx" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\bin\BepInEx.dll;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="_0Harmony" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\bin\0Harmony.dll;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>