CLIPA/IPA/Patcher/Patcher.cs
2016-12-15 21:07:03 +01:00

85 lines
2.5 KiB
C#

using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace IPA.Patcher
{
class PatchedModule
{
private const string ENTRY_TYPE = "Display";
private FileInfo _File;
private ModuleDefinition _Module;
public static PatchedModule Load(string engineFile)
{
return new PatchedModule(engineFile);
}
private PatchedModule(string engineFile)
{
_File = new FileInfo(engineFile);
LoadModules();
}
private void LoadModules()
{
var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(_File.DirectoryName);
var parameters = new ReaderParameters
{
AssemblyResolver = resolver,
};
_Module = ModuleDefinition.ReadModule(_File.FullName, parameters);
}
public bool IsPatched
{
get
{
foreach (var @ref in _Module.AssemblyReferences)
{
if (@ref.Name == "IllusionInjector") return true;
}
return false;
}
}
public void Patch()
{
// First, let's add the reference
var nameReference = new AssemblyNameReference("IllusionInjector", new Version(1, 0, 0, 0));
var injectorPath = Path.Combine(_File.DirectoryName, "IllusionInjector.dll");
_Module.AssemblyReferences.Add(nameReference);
var targetType = FindEntryType();
if (targetType == null) throw new Exception("Couldn't find entry class. Aborting.");
var targetMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic);
if (targetMethod == null)
{
throw new Exception("Couldn't find entry method. Aborting.");
}
var injector = ModuleDefinition.ReadModule(injectorPath);
var methodReference = _Module.Import(injector.GetType("IllusionInjector.Injector").Methods.First(m => m.Name == "Inject"));
targetMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference));
_Module.Write(_File.FullName);
}
private TypeDefinition FindEntryType()
{
return _Module.GetTypes().FirstOrDefault(m => m.Name == ENTRY_TYPE);
}
}
}