Created
September 25, 2018 10:04
-
-
Save HurricanKai/3c8354d952d6c6bb72d9a6f0e5501d75 to your computer and use it in GitHub Desktop.
Repointing Types isnt fun
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Mono.Cecil; | |
| using Mono.Cecil.Cil; | |
| using Mono.Collections.Generic; | |
| using System; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Reflection; | |
| using System.Reflection.Emit; | |
| using System.Runtime.CompilerServices; | |
| using System.Runtime.InteropServices; | |
| using OpCodes = System.Reflection.Emit.OpCodes; | |
| namespace Test | |
| { | |
| public static class Repointer | |
| { | |
| private static void Repoint() | |
| { | |
| var location = Assembly.GetExecutingAssembly().Location; | |
| var definition = AssemblyDefinition.ReadAssembly(location); | |
| definition = OverrideFunction(definition, nameof(Test), nameof(Test.WriteA), | |
| definition, nameof(Test), nameof(Test.WriteB)); | |
| definition.Write("Patched.dll"); | |
| patched = Assembly.Load(File.ReadAllBytes("Patched.dll")); | |
| File.Delete("Patched.dll"); | |
| } | |
| public static AssemblyDefinition OverrideFunction( | |
| AssemblyDefinition target, string targetClass, string targetMethode, | |
| AssemblyDefinition from, string fromClass, string fromMethode) | |
| { | |
| TypeDefinition fromClassDef = from.MainModule.GetType("Test", fromClass); | |
| if (fromClassDef == null) | |
| throw new Exception($"Source {from.FullName}/{fromClass} not found"); | |
| TypeDefinition toClassDef = target.MainModule.GetType("Test", targetClass); | |
| if (toClassDef == null) | |
| throw new Exception($"Target {target.FullName}/{targetClass} not found"); | |
| MethodDefinition copyFromMethode = fromClassDef.Methods.FirstOrDefault(method => method.Name == fromMethode); | |
| if (copyFromMethode == null) | |
| throw new Exception($"Target {from.FullName}.{fromClass}.{fromMethode} not found"); | |
| MethodDefinition copyToMethode = toClassDef.Methods.FirstOrDefault(method => method.Name == targetMethode); | |
| if (copyToMethode == null) | |
| throw new Exception($"Source {target.FullName}.{targetClass}.{targetMethode} not found"); | |
| ILProcessor copyFromProcessor = copyFromMethode.Body.GetILProcessor(); | |
| ILProcessor copyToProcessor = copyToMethode.Body.GetILProcessor(); | |
| Collection<Instruction> copyFromMethodeIL = copyFromProcessor.Body.Instructions; | |
| Collection<Instruction> copyToMethodeIL = copyToProcessor.Body.Instructions; | |
| Console.WriteLine("Copying Instructions:"); | |
| Console.WriteLine(); | |
| copyToMethodeIL.Clear(); | |
| for (int i = 0; i < copyFromMethodeIL.Count; i++) | |
| { | |
| Console.WriteLine(copyFromMethodeIL[i].OpCode.Name); | |
| copyToMethodeIL.Add(copyFromMethodeIL[i]); | |
| } | |
| Console.WriteLine(); | |
| Console.WriteLine("Written"); | |
| Console.WriteLine("To Confirm, here are the Instructions Read again:"); | |
| Console.WriteLine(); | |
| foreach (var instruction in copyToMethodeIL) | |
| { | |
| Console.WriteLine(instruction.OpCode.Name); | |
| } | |
| Console.WriteLine(); | |
| Console.WriteLine("Please work..."); | |
| return target; | |
| } | |
| private static Assembly patched; | |
| public static Assembly Patched { get { if (patched == null) Repoint(); return patched; } } | |
| } | |
| public static class ActualMain | |
| { | |
| public static void Main(string[] args) | |
| { | |
| try | |
| { | |
| Test.WriteA(); | |
| Console.WriteLine("Repointing"); | |
| // Repoint(); | |
| Console.WriteLine("Repointed"); | |
| Test.WriteA(); | |
| Console.ReadLine(); | |
| } | |
| finally | |
| { | |
| } | |
| } | |
| } | |
| class Program | |
| { | |
| static void Main(string[] args) | |
| { | |
| // Lets first call initial nonrepointed Test.WriteA() | |
| Test.WriteA(); | |
| // First we create a temp Assembly | |
| var name = new AssemblyName("InMemory"); | |
| var a = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect); | |
| var mB = a.DefineDynamicModule(name.Name); | |
| // Then we define the Type "TestType" | |
| var tb = mB.DefineType("TestType", System.Reflection.TypeAttributes.Public); | |
| // Create a Constructor | |
| var ctor = tb.DefineConstructor(System.Reflection.MethodAttributes.Public, CallingConventions.Standard, new Type[0]); | |
| var ctorIL = ctor.GetILGenerator(); | |
| // and add a Call to the Test Type in the *Repointed* Assembly | |
| var repointedTest = Repointer.Patched.GetType(/* The Namespace */"Test." + nameof(Test)); | |
| var repointedMethod = repointedTest.GetMethod(nameof(Test.WriteA)); | |
| ctorIL.EmitCall(OpCodes.Call, repointedMethod, new Type[0]); | |
| ctorIL.Emit(OpCodes.Ret); | |
| // Next we call the just created type | |
| // We just told it to in its constructor call the Test.WriteA() Methode in the *Repointed* Assembly | |
| var testType = tb.CreateType(); | |
| var testCtor = testType.GetConstructor(new Type[0]); | |
| var v = testCtor.Invoke(new object[0]); | |
| // v in theory shoud now be "TestType" | |
| Console.ReadLine(); | |
| } | |
| } | |
| public static class Test | |
| { | |
| public static void WriteA() | |
| { | |
| Console.WriteLine("1"); | |
| Console.WriteLine("2"); | |
| // ret; | |
| } | |
| public static void WriteB() | |
| { | |
| Console.WriteLine("C"); | |
| Console.WriteLine("B"); | |
| // ret; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment