private void applybutton_Click(object sender, EventArgs e) { if (nametextbox.TextLength < 3) { MessageBox.Show(MainForm, "Name is too short!", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (hooknametextbox.TextLength < 3) { MessageBox.Show(MainForm, "Hook name is too short!", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } Hook.Name = nametextbox.Text; Hook.HookName = hooknametextbox.Text; MainForm.UpdateHook(Hook); if (msilbefore != null && msilafter != null) { ILWeaver weaver = new ILWeaver(methoddef.Body); weaver.Module = methoddef.Module; msilbefore.Text = weaver.ToString(); Hook.ApplyPatch(methoddef, weaver, MainForm.OxideAssembly); msilafter.Text = weaver.ToString(); } applybutton.Enabled = false; }
/// <summary> /// Process current assembly /// </summary> public void Process() { ILWeaver.Weave(moduleDefinition); moduleDefinition.Write(fileName, new WriterParameters { WriteSymbols = hasPDB }); }
private bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, TypeDefinition currentArg, string[] target, Patcher patcher) { if (currentArg == null || target == null || target.Length == 0) { return(false); } int i; var arg = currentArg; for (i = 0; i < target.Length; i++) { if (GetFieldOrProperty(weaver, originalMethod, ref arg, target[i], patcher)) { continue; } ShowMsg($"Could not find the field or property `{target[i]}` in any of the base classes or interfaces of `{currentArg.Name}`.", "Invalid field or property", patcher); return(false); } if (arg.IsValueType || arg.IsByReference) { weaver.Add(arg.Module == originalMethod.Module ? Instruction.Create(OpCodes.Box, arg.Resolve()) : Instruction.Create(OpCodes.Box, originalMethod.Module.Import(arg.Resolve()))); } return(i >= 1); }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly, Patching.Patcher patcher = null) { // Get the call hook method (only grab object parameters: ignore the object[] hook) List <MethodDefinition> callhookmethods = oxideassembly.MainModule.Types .Single(t => t.FullName == "Oxide.Core.Interface") .Methods.Where(m => m.IsStatic && m.Name == "CallHook" && m.HasParameters && m.Parameters.Any(p => p.ParameterType.IsArray) == false) .OrderBy(x => x.Parameters.Count) .ToList(); // Start injecting where requested weaver.Pointer = InjectionIndex; // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { ShowMsg($"The injection index specified for {Name} is invalid!", "Invalid Index", patcher); return(false); } // Load the hook name Instruction hookname = weaver.Add(Instruction.Create(OpCodes.Ldstr, HookName)); // Push the arguments array to the stack and make the call //VariableDefinition argsvar; //This is the object array // Create an object array and load all arguments into it Instruction firstinjected = PushArgsArray(original, weaver, out int argCount, patcher) ?? hookname; /*if (argsvar != null) * weaver.Ldloc(argsvar); * else * weaver.Add(Instruction.Create(OpCodes.Ldnull));*/ weaver.Add(Instruction.Create(OpCodes.Call, original.Module.Import(callhookmethods[argCount]))); // Deal with the return value DealWithReturnValue(original, null, weaver); //DealWithReturnValue(original, argsvar, weaver); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) { ins.Operand = firstinjected; } } } return(true); }
private async void applybutton_Click(object sender, EventArgs e) { Hook.Name = nametextbox.Text; Hook.HookName = hooknametextbox.Text; MainForm.UpdateHook(Hook, false); if (msilbefore != null && msilafter != null) { ILWeaver weaver = new ILWeaver(methoddef.Body) { Module = methoddef.Module }; Hook.PreparePatch(assembly, methoddef, weaver, MainForm.OxideAssembly); msilbefore.Text = weaver.ToString(); codebefore.Text = await Decompiler.GetSourceCode(methoddef, weaver); Hook.ApplyPatch(assembly, methoddef, weaver, MainForm.OxideAssembly); msilafter.Text = weaver.ToString(); codeafter.Text = await Decompiler.GetSourceCode(methoddef, weaver); } applybutton.Enabled = false; }
public static async Task<string> GetSourceCode(MethodDefinition methodDefinition, ILWeaver weaver = null) { return await Task.Run(() => { try { if (weaver != null) weaver.Apply(methodDefinition.Body); var settings = new DecompilerSettings { UsingDeclarations = false }; var context = new DecompilerContext(methodDefinition.Module) { CurrentType = methodDefinition.DeclaringType, Settings = settings }; var astBuilder = new AstBuilder(context); astBuilder.AddMethod(methodDefinition); var textOutput = new PlainTextOutput(); astBuilder.GenerateCode(textOutput); return textOutput.ToString(); } catch (Exception ex) { return "Error in creating source code from IL: " + ex.Message + Environment.NewLine + ex.StackTrace; } finally { if (weaver != null) methodDefinition.Body = null; } }); }
/// <summary> /// PrePatches this hook into the target weaver /// </summary> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="original"></param> /// <param name="console"></param> public bool PreparePatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, bool console) { if (BaseHook != null) { return(BaseHook.PreparePatch(original, weaver, oxidemodule, console) && BaseHook.ApplyPatch(original, weaver, oxidemodule, console)); } return(true); }
/// <summary> /// PrePatches this hook into the target weaver /// </summary> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="original"></param> /// <param name="patcher"></param> public bool PreparePatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patching.Patcher patcher = null) { if (BaseHook != null) { return(BaseHook.PreparePatch(original, weaver, oxidemodule, patcher) && BaseHook.ApplyPatch(original, weaver, oxidemodule, patcher)); } return(true); }
static PatternTest() { ILWeaver.Weave <FrozenObject>(); ILWeaver.Weave <PatternModel>(); ILWeaver.Weave <ImmutableObject>(); ILWeaver.Weave <ReaderWriterObject>(); ILWeaver.Weave <LoggingObject>(); //ILWeaver.SaveAssembly(); }
public override void ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly) { MethodDefinition initoxidemethod = oxideassembly.MainModule.Types .Single((t) => t.FullName == "Oxide.Core.Interface") .Methods.Single((m) => m.IsStatic && m.Name == "Initialise"); weaver.Pointer = 0; weaver.Add(Instruction.Create(OpCodes.Call, weaver.Module.Import(initoxidemethod))); }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly, bool console) { // Get the call hook method MethodDefinition callhookmethod = oxideassembly.MainModule.Types .Single((t) => t.FullName == "Oxide.Core.Interface") .Methods.Single((m) => m.IsStatic && m.Name == "CallHook"); // Start injecting where requested weaver.Pointer = InjectionIndex; // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { if (console == false) { MessageBox.Show(string.Format("The injection index specified for {0} is invalid!", this.Name), "Invalid Index", MessageBoxButtons.OK, MessageBoxIcon.Error); } return false; } // Load the hook name // Push the arguments array to the stack and make the call VariableDefinition argsvar; var firstinjected = PushArgsArray(original, weaver, out argsvar); var hookname = weaver.Add(Instruction.Create(OpCodes.Ldstr, HookName)); if (firstinjected == null) firstinjected = hookname; if (argsvar != null) weaver.Ldloc(argsvar); else weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Call, original.Module.Import(callhookmethod))); // Deal with the return value DealWithReturnValue(original, argsvar, weaver); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) ins.Operand = firstinjected; } } return true; }
/// <summary> /// Weave field into current aspect /// </summary> /// <param name="il">IL Generator</param> /// <param name="field">Field</param> /// <param name="fieldMethod">Field Method</param> private void BlockField(Mono.Cecil.Cil.ILProcessor il, Mono.Cecil.FieldDefinition field, MethodInfo fieldMethod) { var fieldName = field.Name; // Return if it is a backing field if (fieldName.IndexOf("k__BackingField") >= 0) { return; } var aspect = field.GetCustomAttribute <MemberInterceptionAspect>() ?? field.DeclaringType.GetCustomAttribute <MemberInterceptionAspect>() ?? field.DeclaringType.Module.Assembly.GetCustomAttribute <MemberInterceptionAspect>(); if (!ILWeaver.IsValidAspectFor(field, aspect)) { return; } var fieldType = field.FieldType; var isStatic = field.IsStatic; var fieldLocal = il.DeclareLocal(fieldType); var memberLocal = il.DeclareLocal(typeof(MemberContext)); var aspectField = ILWeaver.TypeFieldAspects[field.DeclaringType.FullName][aspect.GetType().FullName]; // Store current get field value il.Emit(Mono.Cecil.Cil.OpCodes.Stloc, fieldLocal); // MemberContext(object instance, string locationName, object value) il.Emit(isStatic ? Mono.Cecil.Cil.OpCodes.Ldnull : Mono.Cecil.Cil.OpCodes.Ldarg_0); il.Emit(Mono.Cecil.Cil.OpCodes.Ldstr, fieldName); il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, fieldLocal); if (fieldType.IsValueType) { il.Emit(Mono.Cecil.Cil.OpCodes.Box, fieldType); } il.Emit(Mono.Cecil.Cil.OpCodes.Newobj, MemberContextCtor); il.Emit(Mono.Cecil.Cil.OpCodes.Stloc, memberLocal); il.Emit(Mono.Cecil.Cil.OpCodes.Ldsfld, aspectField); il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, memberLocal); il.Emit(Mono.Cecil.Cil.OpCodes.Callvirt, fieldMethod); // Load value back to stack and reflect changes if any il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, memberLocal); il.Emit(Mono.Cecil.Cil.OpCodes.Callvirt, MemberContextValueMethod); // Convert to expected type il.Emit(fieldType.IsValueType ? Mono.Cecil.Cil.OpCodes.Unbox_Any : Mono.Cecil.Cil.OpCodes.Isinst, fieldType); }
public void TestWeave() { using (FileStream input = new FileStream(_executable, FileMode.Open, FileAccess.Read)) using (FileStream output = new FileStream(_executableWeaved, FileMode.Create, FileAccess.Write)) { var weaver = new ILWeaver(); var assemblyDefinition = weaver.Weave(input, new string[0], false); assemblyDefinition.Write(output); } string weavedOutput = this.GetWeavedOutput(); Assert.That(weavedOutput, Is.Not.StringContaining("Original Void2"), "Execution of AnnotatedClass.Void2 should have been skipped"); }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patcher patcher = null) { var insts = new List<Instruction>(); foreach (var instructionData in Instructions) { var instruction = CreateInstruction(original, weaver, instructionData, insts, patcher); if (instruction == null) return false; insts.Add(instruction); } // Start injecting where requested weaver.Pointer = InjectionIndex; if (!weaver.RemoveAfter(RemoveCount)) { ShowMsg(string.Format("The remove count specified for {0} is invalid!", Name), "Invalid Remove Count", patcher); return false; } if (Instructions.Count == 0) return true; // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { ShowMsg(string.Format("The injection index specified for {0} is invalid!", Name), "Invalid Index", patcher); return false; } foreach (var inst in insts) weaver.Add(inst); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) ins.Operand = insts[0]; } } return true; }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly, bool console) { MethodDefinition initoxidemethod = oxideassembly.MainModule.Types .Single((t) => t.FullName == "Oxide.Core.Interface") .Methods.Single((m) => m.IsStatic && m.Name == "Initialize"); // Start injecting where requested weaver.Pointer = InjectionIndex; // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { if (console == false) { MessageBox.Show(string.Format("The injection index specified for {0} is invalid!", this.Name), "Invalid Index", MessageBoxButtons.OK, MessageBoxIcon.Error); } return(false); } // Load the hook name Instruction firstinjected = weaver.Add(Instruction.Create(OpCodes.Call, weaver.Module.Import(initoxidemethod))); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) { ins.Operand = firstinjected; } } } return(true); }
private TypeDefinition GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, TypeDefinition currentArg, string[] target, Patcher patcher, bool boxed = true) { if (resolver == null) { resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(patcher != null ? patcher.PatchProject.TargetDirectory : PatcherForm.MainForm.CurrentProject.TargetDirectory); } if (currentArg == null || target == null || target.Length == 0) { return(null); } int i; var arg = currentArg; for (i = 0; i < target.Length; i++) { if (GetFieldOrProperty(weaver, originalMethod, ref arg, target[i])) { continue; } ShowMsg($"Could not find the field or property `{target[i]}` in any of the base classes or interfaces of `{currentArg.Name}`.", "Invalid field or property", patcher); break; } if (boxed && (arg.IsValueType || arg.IsByReference)) { var type_reference = arg.Module == originalMethod.Module ? arg.Resolve() : originalMethod.Module.Import(arg.Resolve()); weaver?.Add(Instruction.Create(OpCodes.Box, type_reference)); } if (i >= 1) { return(arg); } return(null); }
public override void ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly) { // Get the call hook method MethodDefinition callhookmethod = oxideassembly.MainModule.Types .Single((t) => t.FullName == "Oxide.Core.Interface") .Methods.Single((m) => m.IsStatic && m.Name == "CallHook"); // Start injecting where requested weaver.Pointer = InjectionIndex; // Get the existing instruction we're going to inject behind Instruction existing = weaver.Instructions[weaver.Pointer]; // Load the hook name Instruction firstinjected = weaver.Add(Instruction.Create(OpCodes.Ldstr, HookName)); // Push the arguments array to the stack and make the call PushArgsArray(original, weaver); weaver.Add(Instruction.Create(OpCodes.Call, original.Module.Import(callhookmethod))); // Deal with the return value DealWithReturnValue(original, weaver); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) { ins.Operand = firstinjected; } } } }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly, Patcher patcher = null) { MethodDefinition initoxidemethod = oxideassembly.MainModule.Types .Single((t) => t.FullName == "Oxide.Core.Interface") .Methods.Single((m) => m.IsStatic && m.Name == "Initialize"); // Start injecting where requested weaver.Pointer = InjectionIndex; // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { ShowMsg(string.Format("The injection index specified for {0} is invalid!", Name), "Invalid Index", patcher); return false; } // Load the hook name Instruction firstinjected = weaver.Add(Instruction.Create(OpCodes.Call, weaver.Module.Import(initoxidemethod))); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) ins.Operand = firstinjected; } } return true; }
/// <summary> /// Performs the patch process /// </summary> public void Patch(bool console) { // Load oxide assembly string oxidefilename = Path.Combine(System.Windows.Forms.Application.StartupPath, "Oxide.Core.dll"); if (!File.Exists(oxidefilename)) throw new FileNotFoundException(string.Format("Failed to locate Oxide.dll assembly")); AssemblyDefinition oxideassembly = AssemblyDefinition.ReadAssembly(oxidefilename); if (PatchProject == null) { return; } // CReate reader params ReaderParameters readerparams = new ReaderParameters(); readerparams.AssemblyResolver = new AssemblyResolver { TargetDirectory = PatchProject.TargetDirectory }; DateTime now = DateTime.Now; WriteToLog("----------------------------------------"); WriteToLog(now.ToShortDateString() + " " + now.ToString("hh:mm:ss tt zzz")); WriteToLog("----------------------------------------"); // Loop each manifest foreach (var manifest in PatchProject.Manifests) { // Get the assembly filename string filename; if (!console) { filename = GetAssemblyFilename(manifest.AssemblyName, true); if (!File.Exists(filename)) { WriteToLog(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName)); throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename); } } else { filename = GetAssemblyFilename(manifest.AssemblyName, true); if (!File.Exists(filename)) { filename = GetAssemblyFilename(manifest.AssemblyName, false); if (!File.Exists(filename)) { WriteToLog(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName)); throw new FileNotFoundException(string.Format("Failed to locate target assembly {0}", manifest.AssemblyName), filename); } else { System.IO.File.Copy(filename, Path.GetFileNameWithoutExtension(filename) + "_Original" + Path.GetExtension(filename), true); filename = Path.GetFileNameWithoutExtension(filename) + "_Original" + Path.GetExtension(filename); } } } // Load it if (console) { Console.WriteLine(string.Format("Loading assembly {0}", manifest.AssemblyName)); } else { Log("Loading assembly {0}", manifest.AssemblyName); } WriteToLog(string.Format("Loading assembly {0}", manifest.AssemblyName)); AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filename, readerparams); var baseHooks = (from hook in manifest.Hooks where hook.BaseHook != null select hook.BaseHook).ToList(); // Loop each hook foreach (var hook in manifest.Hooks) { if (baseHooks.Contains(hook)) continue; // Check if it's flagged if (hook.Flagged) { // Log if (console) { Console.WriteLine(string.Format("Ignored hook {0} as it is flagged", hook.Name)); } else { Log("Ignored hook {0} as it is flagged", hook.Name); } WriteToLog(string.Format("Ignored hook {0} as it is flagged", hook.Name)); } else { // Locate the method MethodDefinition method; try { var type = assembly.Modules .SelectMany((m) => m.GetTypes()) .Single((t) => t.FullName == hook.TypeName); method = type.Methods .Single((m) => Utility.GetMethodSignature(m).Equals(hook.Signature)); } catch (Exception) { WriteToLog(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName)); throw new Exception(string.Format("Failed to locate method {0}::{1} in assembly {2}", hook.TypeName, hook.Signature.Name, manifest.AssemblyName)); } // Let the hook do it's work var weaver = new ILWeaver(method.Body) {Module = method.Module}; try { // Apply bool patchApplied = hook.PreparePatch(method, weaver, oxideassembly, console) && hook.ApplyPatch(method, weaver, oxideassembly, console); if (patchApplied) { weaver.Apply(method.Body); } else { if (console) { Console.WriteLine(string.Format("The injection index specified for {0} is invalid!", hook.Name)); } WriteToLog(string.Format("The injection index specified for {0} is invalid!", hook.Name)); hook.Flagged = true; } // Log if (console) { if (patchApplied) { Console.WriteLine(string.Format("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name)); WriteToLog(string.Format("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name)); } else { Console.WriteLine(string.Format("Failed to apply hook {0}", hook.Name)); WriteToLog(string.Format("Failed to apply hook {0}", hook.Name)); } } else { if (patchApplied) { Log("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name); WriteToLog(string.Format("Applied hook {0} to {1}::{2}", hook.Name, hook.TypeName, hook.Signature.Name)); } else { Log("Failed to apply hook {0}", hook.Name); WriteToLog(string.Format("Failed to apply hook {0}", hook.Name)); } } } catch (Exception ex) { if (console) { Console.WriteLine(string.Format("Failed to apply hook {0}", hook.Name)); Console.WriteLine(ex.ToString()); } else { Log("Failed to apply hook {0}", hook.Name); Log("{0}", ex.ToString()); } WriteToLog(string.Format("Failed to apply hook {0}", hook.Name)); WriteToLog(ex.ToString()); } } } // Save it if (console) { Console.WriteLine(string.Format("Saving assembly {0}", manifest.AssemblyName)); } else { Log("Saving assembly {0}", manifest.AssemblyName); } WriteToLog(string.Format("Saving assembly {0}", manifest.AssemblyName)); filename = GetAssemblyFilename(manifest.AssemblyName, false); assembly.Write(filename); } }
private Instruction PushArgsArray(MethodDefinition method, ILWeaver weaver, out VariableDefinition argsvar) { // Are we going to use arguments? if (ArgumentBehavior == Hooks.ArgumentBehavior.None) { // Push null and we're done argsvar = null; return null; } // Create array variable Instruction firstInstruction; // Are we using the argument string? if (ArgumentBehavior == Hooks.ArgumentBehavior.UseArgumentString) { string retvalue; string[] args = ParseArgumentString(out retvalue); if (args == null) { // Silently fail, but at least produce valid IL argsvar = null; return null; } // Create the array argsvar = weaver.AddVariable(new ArrayType(method.Module.TypeSystem.Object), "args"); firstInstruction = weaver.Add(ILWeaver.Ldc_I4_n(args.Length)); weaver.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); weaver.Stloc(argsvar); // Populate it for (int i = 0; i < args.Length; i++) { weaver.Ldloc(argsvar); string arg = args[i].ToLowerInvariant(); weaver.Add(ILWeaver.Ldc_I4_n(i)); if (string.IsNullOrEmpty(arg)) weaver.Add(Instruction.Create(OpCodes.Ldnull)); else if (arg == "this") { if (method.IsStatic) weaver.Add(Instruction.Create(OpCodes.Ldnull)); else weaver.Add(ILWeaver.Ldarg(null)); } else if (arg[0] == 'p' || arg[0] == 'a') { int index; if (int.TryParse(arg.Substring(1), out index)) { ParameterDefinition pdef; /*if (method.IsStatic) pdef = method.Parameters[index]; else pdef = method.Parameters[index + 1];*/ pdef = method.Parameters[index]; weaver.Add(ILWeaver.Ldarg(pdef)); if (pdef.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, pdef.ParameterType)); weaver.Add(Instruction.Create(OpCodes.Box, pdef.ParameterType)); } else if (pdef.ParameterType.IsValueType) weaver.Add(Instruction.Create(OpCodes.Box, pdef.ParameterType)); } else weaver.Add(Instruction.Create(OpCodes.Ldnull)); } else if (arg[0] == 'l' || arg[0] == 'v') { int index; if (int.TryParse(arg.Substring(1), out index)) { VariableDefinition vdef = weaver.Variables[index]; weaver.Ldloc(vdef); if (vdef.VariableType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, vdef.VariableType)); weaver.Add(Instruction.Create(OpCodes.Box, vdef.VariableType)); } else if (vdef.VariableType.IsValueType) weaver.Add(Instruction.Create(OpCodes.Box, vdef.VariableType)); } else weaver.Add(Instruction.Create(OpCodes.Ldnull)); } else weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } } else { // Figure out what we're doing bool includeargs = ArgumentBehavior == Hooks.ArgumentBehavior.All || ArgumentBehavior == Hooks.ArgumentBehavior.JustParams; bool includethis = ArgumentBehavior == Hooks.ArgumentBehavior.All || ArgumentBehavior == Hooks.ArgumentBehavior.JustThis; if (method.IsStatic) includethis = false; // Work out what arguments we're going to transmit List<ParameterDefinition> args = new List<ParameterDefinition>(); if (includeargs) { for (int i = 0; i < method.Parameters.Count; i++) { ParameterDefinition arg = method.Parameters[i]; if (!arg.IsOut) args.Add(arg); } } argsvar = weaver.AddVariable(new ArrayType(method.Module.TypeSystem.Object), "args"); // Load arg count, create array, store if (includethis) firstInstruction = weaver.Add(ILWeaver.Ldc_I4_n(args.Count + 1)); else firstInstruction = weaver.Add(ILWeaver.Ldc_I4_n(args.Count)); weaver.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); weaver.Stloc(argsvar); // Include this if (includethis) { weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(0)); weaver.Add(ILWeaver.Ldarg(null)); weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } // Loop each argument for (int i = 0; i < args.Count; i++) { // Load array, load index load arg, store in array ParameterDefinition arg = args[i]; weaver.Ldloc(argsvar); if (includethis) weaver.Add(ILWeaver.Ldc_I4_n(i + 1)); else weaver.Add(ILWeaver.Ldc_I4_n(i)); weaver.Add(ILWeaver.Ldarg(args[i])); if (arg.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, arg.ParameterType)); weaver.Add(Instruction.Create(OpCodes.Box, arg.ParameterType)); } else if (arg.ParameterType.IsValueType) weaver.Add(Instruction.Create(OpCodes.Box, arg.ParameterType)); weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } } return firstInstruction; }
/// <summary> /// Patches this hook into the target weaver /// </summary> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="original"></param> /// <param name="console"></param> public abstract bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, bool console);
private bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, TypeDefinition currentArg, string[] target, Patcher patcher) { if (resolver == null) { resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(patcher != null ? patcher.PatchProject.TargetDirectory : PatcherForm.MainForm.CurrentProject.TargetDirectory); } if (currentArg == null || target == null || target.Length == 0) return false; int i; var arg = currentArg; for (i = 0; i < target.Length; i++) { if (GetFieldOrProperty(weaver, originalMethod, ref arg, target[i])) continue; ShowMsg($"Could not find the field or property `{target[i]}` in any of the base classes or interfaces of `{currentArg.Name}`.", "Invalid field or property", patcher); break; } if (arg.IsValueType || arg.IsByReference) weaver.Add(arg.Module == originalMethod.Module ? Instruction.Create(OpCodes.Box, arg.Resolve()) : Instruction.Create(OpCodes.Box, originalMethod.Module.Import(arg.Resolve()))); return i >= 1; }
private VariableDefinition LoadDispatchArgs(MethodDefinition method, ILWeaver weaver, Patcher patcher, out Instruction first_instruction) { // Are we going to use arguments? if (ArgumentBehavior == ArgumentBehavior.None) { first_instruction = null; return(null); } VariableDefinition ret_var = null; // Are we using the argument string? if (ArgumentBehavior == ArgumentBehavior.UseArgumentString) { string retvalue; string[] args = ParseArgumentString(out retvalue); if (args == null) { // Silently fail, but at least produce valid IL first_instruction = null; return(null); } ret_var = weaver.AddVariable(method.Module.Import(method.ReturnType), "return_value"); // Load the ret local variable by reference onto the stack first first_instruction = weaver.Ldloc(ret_var); weaver.Add(Instruction.Create(OpCodes.Ldobj, ret_var.VariableType)); // Load all arguments on the stack for (int i = 0; i < args.Length; i++) { var arg = args[i]; var target = ParseTargetString(ref arg); if (string.IsNullOrEmpty(arg)) { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } else if (arg == "this") { if (method.IsStatic) { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } else { weaver.Add(ILWeaver.Ldarg(null)); } GetFieldOrProperty(weaver, method, method.DeclaringType.Resolve(), target, patcher); } else if (arg[0] == 'p' || arg[0] == 'a') { int index; if (int.TryParse(arg.Substring(1), out index)) { ParameterDefinition pdef; /*if (method.IsStatic) * pdef = method.Parameters[index]; * else * pdef = method.Parameters[index + 1];*/ pdef = method.Parameters[index]; weaver.Add(ILWeaver.Ldarg(pdef)); if (pdef.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, pdef.ParameterType)); //weaver.Add(Instruction.Create(OpCodes.Box, pdef.ParameterType)); } GetFieldOrProperty(weaver, method, pdef.ParameterType.Resolve(), target, patcher); } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } } else if (arg[0] == 'l' || arg[0] == 'v') { int index; if (int.TryParse(arg.Substring(1), out index)) { VariableDefinition vdef = weaver.Variables[index]; weaver.Ldloc(vdef); if (vdef.VariableType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, vdef.VariableType)); //weaver.Add(Instruction.Create(OpCodes.Box, vdef.VariableType)); } GetFieldOrProperty(weaver, method, vdef.VariableType.Resolve(), target, patcher); } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } } } else { ret_var = weaver.AddVariable(method.Module.Import(method.ReturnType), "return_value"); // Load the ret local variable by reference onto the stack first first_instruction = weaver.Ldloc(ret_var); weaver.Add(Instruction.Create(OpCodes.Ldobj, ret_var.VariableType)); // Figure out what we're doing var has_params = ArgumentBehavior == ArgumentBehavior.All || ArgumentBehavior == ArgumentBehavior.JustParams; var has_this = ArgumentBehavior == ArgumentBehavior.All || ArgumentBehavior == ArgumentBehavior.JustThis; if (method.IsStatic) { has_this = false; } // Work out what arguments we're going to include var parameters = new List <ParameterDefinition>(); if (has_params) { for (int i = 0; i < method.Parameters.Count; i++) { var parameter = method.Parameters[i]; if (!parameter.IsOut) { parameters.Add(parameter); } } } if (has_this) { first_instruction = weaver.Add(ILWeaver.Ldarg(null)); } foreach (var arg in parameters) { var instruction = weaver.Add(ILWeaver.Ldarg(arg)); if (first_instruction == null) { first_instruction = instruction; } if (arg.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, arg.ParameterType)); //if (arg.ParameterType.Full?Name == "System.Object") weaver.Add(Instruction.Create(OpCodes.Box, arg.ParameterType)); } } } return(ret_var); }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly, Patcher patcher = null) { // Get the call hook method MethodDefinition callhookmethod = oxideassembly.MainModule.Types .Single((t) => t.FullName == "Oxide.Core.Interface") .Methods.Single((m) => m.IsStatic && m.Name == "CallHook"); // Start injecting where requested weaver.Pointer = InjectionIndex; // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { ShowMsg(string.Format("The injection index specified for {0} is invalid!", Name), "Invalid Index", patcher); return(false); } // Load the hook name // Push the arguments array to the stack and make the call VariableDefinition argsvar; var firstinjected = PushArgsArray(original, weaver, out argsvar, patcher); var hookname = weaver.Add(Instruction.Create(OpCodes.Ldstr, HookName)); if (firstinjected == null) { firstinjected = hookname; } if (argsvar != null) { weaver.Ldloc(argsvar); } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } weaver.Add(Instruction.Create(OpCodes.Call, original.Module.Import(callhookmethod))); // Deal with the return value DealWithReturnValue(original, argsvar, weaver); // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) { ins.Operand = firstinjected; } } } return(true); }
private bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, ref TypeDefinition currentArg, string target, Patcher patcher) { if (currentArg == null || string.IsNullOrEmpty(target)) { return(false); } while (currentArg != null) { if (currentArg.IsClass) { if (currentArg.HasFields) { foreach (var field in currentArg.Fields) { if (!string.Equals(field.Name, target, StringComparison.CurrentCultureIgnoreCase)) { continue; } weaver.Add(field.Module == originalMethod.Module ? Instruction.Create(OpCodes.Ldfld, field) : Instruction.Create(OpCodes.Ldfld, originalMethod.Module.Import(field))); currentArg = field.FieldType.Resolve(); return(true); } } } if (currentArg.HasProperties) { foreach (var property in currentArg.Properties) { if (!string.Equals(property.Name, target, StringComparison.CurrentCultureIgnoreCase)) { continue; } weaver.Add(property.GetMethod.Module == originalMethod.Module ? Instruction.Create(OpCodes.Callvirt, property.GetMethod) : Instruction.Create(OpCodes.Callvirt, originalMethod.Module.Import(property.GetMethod))); currentArg = property.PropertyType.Resolve(); return(true); } } if (currentArg.HasInterfaces) { foreach (var intf in currentArg.Interfaces) { var previousArg = currentArg; currentArg = intf.Resolve(); if (GetFieldOrProperty(weaver, originalMethod, ref currentArg, target, patcher)) { return(true); } currentArg = previousArg; } } if (currentArg.BaseType != null && originalMethod.Module.Assembly != currentArg.BaseType.Module.Assembly) { var baseType = currentArg.BaseType; var baseTypeAssembly = AssemblyDefinition.ReadAssembly($"{(patcher != null ? patcher.PatchProject.TargetDirectory : PatcherForm.MainForm.CurrentProject.TargetDirectory)}\\{baseType.Scope.Name}{(baseType.Scope.Name.EndsWith(".dll") ? "" : ".dll")}"); currentArg = baseTypeAssembly.MainModule.Types.Single(x => x.FullName == baseType.FullName); } else { currentArg = currentArg.BaseType?.Resolve(); } } return(false); }
private async void applybutton_Click(object sender, EventArgs e) { if (nametextbox.TextLength < 3) { MessageBox.Show(MainForm, "Name is too short!", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (hooknametextbox.TextLength < 3) { MessageBox.Show(MainForm, "Hook name is too short!", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } Hook.Name = nametextbox.Text; Hook.HookName = hooknametextbox.Text; MainForm.UpdateHook(Hook, false); if (msilbefore != null && msilafter != null) { var weaver = new ILWeaver(methoddef.Body) {Module = methoddef.Module}; Hook.PreparePatch(methoddef, weaver, MainForm.OxideAssembly); msilbefore.Text = weaver.ToString(); codebefore.Text = await Decompiler.GetSourceCode(methoddef, weaver); Hook.ApplyPatch(methoddef, weaver, MainForm.OxideAssembly); msilafter.Text = weaver.ToString(); codeafter.Text = await Decompiler.GetSourceCode(methoddef, weaver); } applybutton.Enabled = false; }
private Instruction PushArgsArray(MethodDefinition method, ILWeaver weaver, out VariableDefinition argsvar, Patcher patcher) { // Are we going to use arguments? if (ArgumentBehavior == Hooks.ArgumentBehavior.None) { // Push null and we're done argsvar = null; return(null); } // Create array variable Instruction firstInstruction; // Are we using the argument string? if (ArgumentBehavior == Hooks.ArgumentBehavior.UseArgumentString) { string retvalue; string[] args = ParseArgumentString(out retvalue); if (args == null) { // Silently fail, but at least produce valid IL argsvar = null; return(null); } // Create the array argsvar = weaver.AddVariable(new ArrayType(method.Module.TypeSystem.Object), "args"); firstInstruction = weaver.Add(ILWeaver.Ldc_I4_n(args.Length)); weaver.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); weaver.Stloc(argsvar); // Populate it for (int i = 0; i < args.Length; i++) { string arg = args[i].ToLowerInvariant(); string[] target = null; if (!string.IsNullOrEmpty(arg) && args[i].Contains(".")) { string[] split = args[i].Split('.'); arg = split[0]; target = split.Skip(1).ToArray(); } weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(i)); if (string.IsNullOrEmpty(arg)) { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } else if (arg == "this") { if (method.IsStatic) { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } else { weaver.Add(ILWeaver.Ldarg(null)); } GetFieldOrProperty(weaver, method, method.DeclaringType.Resolve(), target, patcher); } else if (arg[0] == 'p' || arg[0] == 'a') { int index; if (int.TryParse(arg.Substring(1), out index)) { ParameterDefinition pdef; /*if (method.IsStatic) * pdef = method.Parameters[index]; * else * pdef = method.Parameters[index + 1];*/ if (index < method.Parameters.Count) { pdef = method.Parameters[index]; weaver.Add(ILWeaver.Ldarg(pdef)); if (pdef.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, pdef.ParameterType)); weaver.Add(Instruction.Create(OpCodes.Box, pdef.ParameterType)); } if ( !GetFieldOrProperty(weaver, method, pdef.ParameterType.Resolve(), target, patcher) && pdef.ParameterType.IsValueType) { weaver.Add(Instruction.Create(OpCodes.Box, pdef.ParameterType)); } } else { ShowMsg($"Invalid argument `{arg}` supplied for {HookName}", "Invalid argument supplied", patcher); } } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } } else if (arg[0] == 'l' || arg[0] == 'v') { int index; if (int.TryParse(arg.Substring(1), out index)) { if (index < method.Body.Variables.Count) { VariableDefinition vdef = weaver.Variables[index]; weaver.Ldloc(vdef); if (vdef.VariableType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, vdef.VariableType)); weaver.Add(Instruction.Create(OpCodes.Box, vdef.VariableType)); } if (!GetFieldOrProperty(weaver, method, vdef.VariableType.Resolve(), target, patcher) && vdef.VariableType.IsValueType) { weaver.Add(Instruction.Create(OpCodes.Box, vdef.VariableType)); } } else { ShowMsg($"Invalid variable `{arg}` supplied for {HookName}", "Invalid variable supplied", patcher); } } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } } else { // Figure out what we're doing bool includeargs = ArgumentBehavior == Hooks.ArgumentBehavior.All || ArgumentBehavior == Hooks.ArgumentBehavior.JustParams; bool includethis = ArgumentBehavior == Hooks.ArgumentBehavior.All || ArgumentBehavior == Hooks.ArgumentBehavior.JustThis; if (method.IsStatic) { includethis = false; } // Work out what arguments we're going to transmit List <ParameterDefinition> args = new List <ParameterDefinition>(); if (includeargs) { for (int i = 0; i < method.Parameters.Count; i++) { ParameterDefinition arg = method.Parameters[i]; if (!arg.IsOut) { args.Add(arg); } } } argsvar = weaver.AddVariable(new ArrayType(method.Module.TypeSystem.Object), "args"); // Load arg count, create array, store if (includethis) { firstInstruction = weaver.Add(ILWeaver.Ldc_I4_n(args.Count + 1)); } else { firstInstruction = weaver.Add(ILWeaver.Ldc_I4_n(args.Count)); } weaver.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); weaver.Stloc(argsvar); // Include this if (includethis) { weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(0)); weaver.Add(ILWeaver.Ldarg(null)); weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } // Loop each argument for (int i = 0; i < args.Count; i++) { // Load array, load index load arg, store in array ParameterDefinition arg = args[i]; weaver.Ldloc(argsvar); if (includethis) { weaver.Add(ILWeaver.Ldc_I4_n(i + 1)); } else { weaver.Add(ILWeaver.Ldc_I4_n(i)); } weaver.Add(ILWeaver.Ldarg(args[i])); if (arg.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, arg.ParameterType)); weaver.Add(Instruction.Create(OpCodes.Box, arg.ParameterType)); } else if (arg.ParameterType.IsValueType) { weaver.Add(Instruction.Create(OpCodes.Box, arg.ParameterType)); } weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } } return(firstInstruction); }
private bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, ref TypeDefinition currentArg, string target) { if (currentArg == null || string.IsNullOrEmpty(target)) { return(false); } while (currentArg != null) { if (currentArg.IsClass) { if (currentArg.HasFields) { foreach (var field in currentArg.Fields) { if (!string.Equals(field.Name, target, StringComparison.CurrentCultureIgnoreCase)) { continue; } weaver?.Add(field.Module == originalMethod.Module ? Instruction.Create(OpCodes.Ldfld, field) : Instruction.Create(OpCodes.Ldfld, originalMethod.Module.Import(field))); currentArg = field.FieldType.Resolve(); return(true); } } } if (currentArg.HasProperties) { foreach (var property in currentArg.Properties) { if (!string.Equals(property.Name, target, StringComparison.CurrentCultureIgnoreCase)) { continue; } weaver?.Add(property.GetMethod.Module == originalMethod.Module ? Instruction.Create(OpCodes.Callvirt, property.GetMethod) : Instruction.Create(OpCodes.Callvirt, originalMethod.Module.Import(property.GetMethod))); currentArg = property.PropertyType.Resolve(); return(true); } } if (currentArg.HasInterfaces) { foreach (var intf in currentArg.Interfaces) { var previousArg = currentArg; currentArg = intf.Resolve(); if (GetFieldOrProperty(weaver, originalMethod, ref currentArg, target)) { return(true); } currentArg = previousArg; } } currentArg = currentArg.BaseType?.Resolve(); } return(false); }
/// <summary> /// Attempts to deobfuscate the specified type /// </summary> /// <param name="typedef"></param> protected virtual void DeobfuscateType(TypeDefinition typedef) { // Deal with method parameters foreach (MethodDefinition method in typedef.Methods .Where(m => m.HasParameters) ) { for (int i = 0; i < method.Parameters.Count; i++) { ParameterDefinition paramdef = method.Parameters[i]; if (IdentifyObfuscatedName(paramdef.Name)) { string name = $"arg{i}"; paramdef.Name = name; } } } // Deal with field names FieldDefinition[] fields = typedef.Fields .Where(f => IdentifyObfuscatedName(f.Name)) .ToArray(); Array.Sort(fields, (a, b) => { // Sort firstly by type // Then sort by offset // Finally, sort by obfuscated name int tmp = Comparer <string> .Default.Compare(a.FieldType.FullName, b.FieldType.FullName); if (tmp != 0) { return(tmp); } tmp = Comparer <int> .Default.Compare(a.Offset, b.Offset); if (tmp != 0) { return(tmp); } return(Comparer <string> .Default.Compare(a.Name, b.Name)); }); for (int i = 0; i < fields.Length; i++) { FieldDefinition field = fields[i]; string name; if (field.IsPublic) { name = $"Field{i + 1}"; } else { name = $"field{i + 1}"; } field.Name = name; } // Deal with property names PropertyDefinition[] properties = typedef.Properties .Where(f => IdentifyObfuscatedName(f.Name)) .ToArray(); Array.Sort(properties, (a, b) => { // Sort firstly by type, then by obfuscated name int tmp = Comparer <string> .Default.Compare(a.PropertyType.FullName, b.PropertyType.FullName); if (tmp != 0) { return(tmp); } return(Comparer <string> .Default.Compare(a.Name, b.Name)); }); for (int i = 0; i < properties.Length; i++) { PropertyDefinition property = properties[i]; string name = $"property{i + 1}"; // NOTE: Do we need to rename the get and set methods too? property.Name = name; } // Deal with method names MethodDefinition[] methods = typedef.Methods .Where(f => IdentifyObfuscatedName(f.Name)) .ToArray(); Array.Sort(methods, (a, b) => { // Sort by the following in order: return type, parameter count, parameter types, obfuscated name int tmp = Comparer <string> .Default.Compare(a.ReturnType.FullName, b.ReturnType.FullName); if (tmp != 0) { return(tmp); } tmp = Comparer <int> .Default.Compare(a.Parameters.Count, b.Parameters.Count); if (tmp != 0) { return(tmp); } // TODO: Sort by parameter types return(Comparer <string> .Default.Compare(a.Name, b.Name)); }); for (int i = 0; i < methods.Length; i++) { MethodDefinition method = methods[i]; string name; if (method.IsPublic) { name = $"Method{i + 1}"; } else { name = $"method{i + 1}"; } method.Name = name; } // Deal with proxy methods HashSet <MethodDefinition> toremove = new HashSet <MethodDefinition>(); foreach (MethodDefinition method in typedef.Methods .Where(m => m.HasBody) ) { // Identify a proxy call via IL Collection <Instruction> instructions = method.Body.Instructions; if (instructions.Count != 3) { continue; } if (instructions[0].OpCode.Code != Code.Ldarg_0) { continue; } if (instructions[1].OpCode.Code != Code.Callvirt) { continue; } if (instructions[2].OpCode.Code != Code.Ret) { continue; } // Check that it's calling an obfuscated method in our type MethodReference proxymethod = instructions[1].Operand as MethodReference; if (proxymethod.DeclaringType.FullName != typedef.FullName) { continue; } if (!methods.Any(m => m.FullName == proxymethod.FullName)) { continue; } // Check that the target method is not referenced by anything else if (!refcounts.TryGetValue(proxymethod, out int refcount)) { refcount = 0; } if (refcount > 1) { continue; } // Resolve it MethodDefinition proxymethoddef = proxymethod.Resolve(); if (!proxymethoddef.HasBody) { continue; } // It passed, collapse the proxy method's IL into this method and remove it ILWeaver weaver = new ILWeaver(proxymethoddef.Body); weaver.Apply(method.Body); toremove.Add(proxymethoddef); } // Remove any proxy methods foreach (MethodDefinition method in toremove) { typedef.Methods.Remove(method); } }
/// <summary> /// Weave event invoke /// </summary> /// <param name="il">IL Generator</param> /// <param name="method">Method</param> /// <param name="field">Field</param> private void BlockInvokeEvent(Mono.Cecil.Cil.ILProcessor il, Mono.Cecil.MethodDefinition method, Mono.Cecil.FieldDefinition field) { var isStatic = method.IsStatic; var eventContext = il.DeclareLocal(typeof(EventContext)); var locals = new List <Mono.Cecil.Cil.VariableDefinition>(); var objLocal = il.DeclareLocal(typeof(object[])); var parameters = method.Parameters; var parameterLength = parameters.Count; var fieldDeclaringType = field.DeclaringType; var aspect = field.GetCustomAttribute <EventInterceptionAspect>() ?? fieldDeclaringType.GetCustomAttribute <EventInterceptionAspect>() ?? fieldDeclaringType.Module.Assembly.GetCustomAttribute <EventInterceptionAspect>(); if (!ILWeaver.IsValidAspectFor(field, aspect, allowEvents: true)) { return; } var aspectField = ILWeaver.TypeFieldAspects[fieldDeclaringType.FullName][aspect.GetType().FullName]; il.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4, parameterLength); il.Emit(Mono.Cecil.Cil.OpCodes.Newarr, typeof(object)); il.Emit(Mono.Cecil.Cil.OpCodes.Stloc, objLocal); for (var i = 0; i < parameterLength; i++) { var parameter = parameters[i]; var parameterType = parameter.ParameterType; var local = il.DeclareLocal(parameterType); il.Emit(Mono.Cecil.Cil.OpCodes.Stloc, local); il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, objLocal); il.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4, parameterLength - i - 1); il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, local); if (parameterType.IsValueType) { il.Emit(Mono.Cecil.Cil.OpCodes.Box, parameterType); } il.Emit(Mono.Cecil.Cil.OpCodes.Stelem_Ref); locals.Add(local); } if (!isStatic) { il.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0); } il.Emit(Mono.Cecil.Cil.OpCodes.Ldnull); il.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4, 1); il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, objLocal); il.Emit(Mono.Cecil.Cil.OpCodes.Newobj, EventContextCtor); il.Emit(Mono.Cecil.Cil.OpCodes.Stloc, eventContext); //InvokeEventMethod il.Emit(Mono.Cecil.Cil.OpCodes.Ldsfld, aspectField); il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, eventContext); il.Emit(Mono.Cecil.Cil.OpCodes.Callvirt, InvokeEventMethod); //Restore original invoke event parameters //locals.Reverse(); foreach (var local in locals) { il.Emit(Mono.Cecil.Cil.OpCodes.Ldloc, local); } }
/// <summary> /// PrePatches this hook into the target weaver /// </summary> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="original"></param> /// <param name="patcher"></param> public override bool PreparePatch(AssemblyDefinition assembly, MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patching.Patcher patcher = null) { if (DependsOnField != null) { if (!DependsOnField.Apply(assembly)) { return(false); } } return(base.PreparePatch(assembly, original, weaver, oxidemodule, patcher)); }
unsafe static void Main(string[] args) { var tdMethod = typeof(TestData).GetMethod("ToString"); var tdsMethod = typeof(TestData).GetMethod("ToStringEx"); tdMethod.SwapWith(tdsMethod); var tdata = new TestData(); var ttdatas = tdata.ToString(); Console.WriteLine(ttdatas); return; ILWeaver.Weave(); ILWeaver.SaveAssembly(); var ctor = typeof(TestMyClass3).GetConstructor(Type.EmptyTypes); var ctor2 = typeof(TestMyClass).GetConstructor(Type.EmptyTypes); var d = (uint *)ctor.MethodHandle.Value.ToPointer(); var sa = (uint *)ctor2.MethodHandle.Value.ToPointer(); *d = *sa; var tobj = new TestMyClass3(); tobj.Value = "*****@*****.**"; var evt = new EventHandler((s, e) => { Console.WriteLine("Simple Delegate"); }); tobj.myEvent += evt; tobj.TestParameterMethod(tobj.Value); Console.ReadLine(); return; TestPerf("RAspect-Empty Method", () => { var obj = new TestMyClass3(); obj.Test(10, 10, new Complex { ID = 100 }); obj.Test(10, 10, new Complex { ID = 100 }); }); TestPerf("Empty Method", () => { var obj = new TestMyClass(); obj.Test(10, 10, new Complex { ID = 100 }); obj.Test(10, 10, new Complex { ID = 100 }); }); System.Console.Read(); }
protected override async void OnLoad(EventArgs e) { base.OnLoad(e); methoddef = MainForm.GetMethod(Hook.AssemblyName, Hook.TypeName, Hook.Signature); hooktypes = new List<Type>(); int selindex = 0; int i = 0; foreach (var hooktype in Hook.GetHookTypes()) { string typename = hooktype.GetCustomAttribute<HookType>().Name; hooktypedropdown.Items.Add(typename); hooktypes.Add(hooktype); if (typename == Hook.HookTypeName) selindex = i; i++; } var hooks = MainForm.CurrentProject.GetManifest(Hook.AssemblyName).Hooks; var baseHooks = (from hook in hooks where hook.BaseHook != null select hook.BaseHook).ToList(); basehookdropdown.Items.Add(""); int selindex2 = 0; i = 1; foreach (var hook in hooks) { if (hook.BaseHook == Hook) clonebutton.Enabled = false; if (hook != Hook.BaseHook && baseHooks.Contains(hook)) continue; basehookdropdown.Items.Add(hook.Name); if (hook == Hook.BaseHook) selindex2 = i; i++; } assemblytextbox.Text = Hook.AssemblyName; typenametextbox.Text = Hook.TypeName; if (methoddef != null) methodnametextbox.Text = Hook.Signature.ToString(); else methodnametextbox.Text = Hook.Signature + " (METHOD MISSING)"; nametextbox.Text = Hook.Name; hooknametextbox.Text = Hook.HookName; ignoretypechange = true; hooktypedropdown.SelectedIndex = selindex; basehookdropdown.SelectedIndex = selindex2; ignoretypechange = false; applybutton.Enabled = false; if (Hook.Flagged) { flagbutton.Enabled = false; unflagbutton.Enabled = true; unflagbutton.Focus(); } else { flagbutton.Enabled = true; unflagbutton.Enabled = false; flagbutton.Focus(); } HookSettingsControl settingsview = Hook.CreateSettingsView(); if (settingsview == null) { Label tmp = new Label(); tmp.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; tmp.AutoSize = false; tmp.Text = "No settings."; tmp.Dock = DockStyle.Fill; hooksettingstab.Controls.Add(tmp); } else { settingsview.Dock = DockStyle.Fill; settingsview.OnSettingsChanged += settingsview_OnSettingsChanged; hooksettingstab.Controls.Add(settingsview); } if (methoddef == null) { Label missinglabel1 = new Label(); missinglabel1.Dock = DockStyle.Fill; missinglabel1.AutoSize = false; missinglabel1.Text = "METHOD MISSING"; missinglabel1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; beforetab.Controls.Add(missinglabel1); Label missinglabel2 = new Label(); missinglabel2.Dock = DockStyle.Fill; missinglabel2.AutoSize = false; missinglabel2.Text = "METHOD MISSING"; missinglabel2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; aftertab.Controls.Add(missinglabel2); return; } var weaver = new ILWeaver(methoddef.Body) {Module = methoddef.Module}; Hook.PreparePatch(methoddef, weaver, MainForm.OxideAssembly); msilbefore = new TextEditorControl { Dock = DockStyle.Fill, Text = weaver.ToString() }; codebefore = new TextEditorControl { Dock = DockStyle.Fill, Text = await Decompiler.GetSourceCode(methoddef, weaver), Document = { HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("C#") } }; Hook.ApplyPatch(methoddef, weaver, MainForm.OxideAssembly); msilafter = new TextEditorControl { Dock = DockStyle.Fill, Text = weaver.ToString() }; codeafter = new TextEditorControl { Dock = DockStyle.Fill, Text = await Decompiler.GetSourceCode(methoddef, weaver), Document = { HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("C#") } }; beforetab.Controls.Add(msilbefore); aftertab.Controls.Add(msilafter); codebeforetab.Controls.Add(codebefore); codeaftertab.Controls.Add(codeafter); }
/// <summary> /// Patches this hook into the target weaver /// </summary> /// <param name="original"></param> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="patcher"></param> public abstract bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patcher patcher = null);
private void DealWithReturnValue(MethodDefinition method, VariableDefinition argsvar, ILWeaver weaver) { // What return behavior do we use? switch (ReturnBehavior) { case Hooks.ReturnBehavior.Continue: // Just discard the return value weaver.Add(Instruction.Create(OpCodes.Pop)); break; case Hooks.ReturnBehavior.ExitWhenValidType: // Is there a return value or not? if (method.ReturnType.FullName == "System.Void") { // If the hook returned something that was non-null, return Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Add(Instruction.Create(OpCodes.Ret)); } else { // Create variable VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the return type, return it - else continue weaver.Add(Instruction.Create(OpCodes.Isinst, method.ReturnType)); Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); weaver.Add(Instruction.Create(OpCodes.Ret)); } break; case Hooks.ReturnBehavior.ModifyRefArg: string wayne; var args = ParseArgumentString(out wayne); if (args == null) { break; } for (int i = 0; i < args.Length; i++) { string arg = args[i].ToLowerInvariant(); if (arg[0] == 'p' || arg[0] == 'a') { int index; if (int.TryParse(arg.Substring(1), out index)) { var pdef = method.Parameters[index]; if (pdef.ParameterType.IsValueType) { weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(i)); weaver.Add(Instruction.Create(OpCodes.Ldelem_Ref)); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, pdef.ParameterType)); weaver.Starg(pdef); } } } else if (arg[0] == 'l' || arg[0] == 'v') { int index; if (int.TryParse(arg.Substring(1), out index)) { var vdef = weaver.Variables[index]; if (vdef.VariableType.IsValueType) { weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(i)); weaver.Add(Instruction.Create(OpCodes.Ldelem_Ref)); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, vdef.VariableType)); weaver.Stloc(vdef); } } } } weaver.Add(Instruction.Create(OpCodes.Pop)); break; case Hooks.ReturnBehavior.UseArgumentString: // Deal with it according to the retvalue of the arg string string retvalue; ParseArgumentString(out retvalue); if (!string.IsNullOrEmpty(retvalue)) { if (retvalue[0] == 'l' && retvalue.Length > 1) { int localindex; if (int.TryParse(retvalue.Substring(1), out localindex)) { // Create variable and get the target variable VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); VariableDefinition targetvar = weaver.Variables[localindex]; // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the variable type, store it in the target variable weaver.Add(Instruction.Create(OpCodes.Isinst, targetvar.VariableType)); Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, targetvar.VariableType)); weaver.Stloc(targetvar); // Handled return; } } else if (retvalue[0] == 'a' && retvalue.Length > 1) { int localindex; if (int.TryParse(retvalue.Substring(1), out localindex)) { // Create variable and get the target parameter VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); ParameterDefinition targetvar = method.Parameters[localindex]; var byReferenceType = targetvar.ParameterType as ByReferenceType; TypeReference targettype = byReferenceType != null ? byReferenceType.ElementType : targetvar.ParameterType; // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the variable type, store it in the target parameter variable Instruction i = weaver.Add(Instruction.Create(OpCodes.Isinst, targettype)); weaver.Add(Instruction.Create(OpCodes.Brfalse_S, i.Next)); if (!targetvar.ParameterType.IsValueType) { weaver.Add(ILWeaver.Ldarg(targetvar)); } weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, targettype)); if (!targetvar.ParameterType.IsValueType) { weaver.Add(Instruction.Create(OpCodes.Stobj, targettype)); } else { weaver.Starg(targetvar); } // Handled return; } } else if (retvalue == "ret" || retvalue == "return") { // Create variable VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the return type, return it - else continue weaver.Add(Instruction.Create(OpCodes.Isinst, method.ReturnType)); Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); weaver.Add(Instruction.Create(OpCodes.Ret)); // Handled return; } } // Not handled weaver.Add(Instruction.Create(OpCodes.Pop)); break; } }
private Instruction CreateInstruction(MethodDefinition method, ILWeaver weaver, InstructionData instructionData, List <Instruction> insts, Patcher patcher) { var opcode = opCodes[instructionData.OpCode]; var optype = instructionData.OpType; Instruction Instruction = null; int start; int end; switch (optype) { case OpType.None: Instruction = Instruction.Create(opcode); break; case OpType.Byte: Instruction = Instruction.Create(opcode, Convert.ToByte(instructionData.Operand)); break; case OpType.SByte: Instruction = Instruction.Create(opcode, Convert.ToSByte(instructionData.Operand)); break; case OpType.Int32: Instruction = Instruction.Create(opcode, Convert.ToInt32(instructionData.Operand)); break; case OpType.Int64: Instruction = Instruction.Create(opcode, Convert.ToInt64(instructionData.Operand)); break; case OpType.Single: Instruction = Instruction.Create(opcode, Convert.ToSingle(instructionData.Operand)); break; case OpType.Double: Instruction = Instruction.Create(opcode, Convert.ToDouble(instructionData.Operand)); break; case OpType.String: Instruction = Instruction.Create(opcode, Convert.ToString(instructionData.Operand)); break; case OpType.VerbatimString: Instruction = Instruction.Create(opcode, Regex.Unescape(Convert.ToString(instructionData.Operand))); break; case OpType.Instruction: var index = Convert.ToInt32(instructionData.Operand); Instruction = Instruction.Create(opcode, index < 1024 ? weaver.Instructions[index] : insts[index - 1024]); break; case OpType.Variable: Instruction = Instruction.Create(opcode, method.Body.Variables[Convert.ToInt32(instructionData.Operand)]); break; case OpType.Parameter: Instruction = Instruction.Create(opcode, method.Parameters[Convert.ToInt32(instructionData.Operand)]); break; case OpType.Field: var fieldData = Convert.ToString(instructionData.Operand).Split('|'); var fieldType = GetType(fieldData[0], fieldData[1], patcher); if (fieldType == null) { return(null); } var fieldField = fieldType.Fields.FirstOrDefault(f => f.Name.Equals(fieldData[2])); if (fieldField == null) { ShowMsg(string.Format("The Field '{0}' for '{1}' could not be found!", fieldData[2], Name), "Missing Field", patcher); return(null); } Instruction = Instruction.Create(opcode, method.Module.Import(fieldField)); break; case OpType.Method: var methodData = Convert.ToString(instructionData.Operand).Split('|'); var methodType = GetType(methodData[0], methodData[1], patcher); if (methodType == null) { return(null); } if (methodData.Length > 3) { methodData[2] = string.Join("|", methodData.Skip(2).ToArray()); } MethodReference methodMethod; start = methodData[2].IndexOf('('); end = methodData[2].IndexOf(')'); if (start >= 0 && end >= 0 && start < end) { var name = TagsRegex.Replace(methodData[2], string.Empty).Trim(); var methodSig = methodData[2].Substring(start + 1, end - start - 1); var sigData = methodSig.Split(','); var sigTypes = new TypeDefinition[sigData.Length]; for (int i = 0; i < sigData.Length; i++) { var s = sigData[i]; var sigName = s.Trim(); var assem = "mscorlib"; if (sigName.Contains('|')) { var split = sigName.Split('|'); assem = split[0].Trim(); sigName = split[1].Trim(); } var sigType = GetType(assem, sigName, patcher); if (sigType == null) { ShowMsg($"SigType '{sigName}' not found", "Missing Method", patcher); return(null); } sigTypes[i] = sigType; } methodMethod = null; foreach (var methodDefinition in methodType.Methods) { if (!methodDefinition.Name.Equals(name) || methodDefinition.Parameters.Count != sigTypes.Length) { continue; } var match = true; for (int i = 0; i < methodDefinition.Parameters.Count; i++) { var parameter = methodDefinition.Parameters[i]; if (!parameter.ParameterType.FullName.Equals(sigTypes[i].FullName)) { match = false; break; } } if (!match) { continue; } methodMethod = methodDefinition; break; } } else { var methodName = methodData[2]; var position = methodName.IndexOf('['); if (position > 0) { methodName = methodName.Substring(0, position); } methodMethod = methodType.Methods.FirstOrDefault(f => f.Name.Equals(methodName) && (position <= 0 || f.HasGenericParameters)); } if (methodMethod == null) { ShowMsg($"The Method '{methodData[2]}' for '{Name}' could not be found!", "Missing Method", patcher); return(null); } start = methodData[2].IndexOf('['); end = methodData[2].IndexOf(']'); if (start >= 0 && end >= 0 && start < end) { var generic = new GenericInstanceMethod(methodMethod); var methodG = methodData[2].Substring(start + 1, end - start - 1); var genData = methodG.Split(','); var genTypes = new TypeDefinition[genData.Length]; for (int i = 0; i < genData.Length; i++) { var s = genData[i]; var genName = s.Trim(); var assem = "mscorlib"; if (genName.Contains('|')) { var split = genName.Split('|'); assem = split[0].Trim(); genName = split[1].Trim(); } var genType = GetType(assem, genName, patcher); if (genType == null) { ShowMsg($"GenericType '{genName}' not found", "Missing Method", patcher); return(null); } genTypes[i] = genType; } foreach (var type in genTypes) { generic.GenericArguments.Add(type); } methodMethod = generic; } Instruction = Instruction.Create(opcode, method.Module.Import(methodMethod)); break; case OpType.Generic: break; case OpType.Type: var typeData = Convert.ToString(instructionData.Operand).Split('|'); TypeReference typeType = GetType(typeData[0], TagsRegex.Replace(typeData[1], string.Empty).Trim(), patcher); if (typeType == null) { return(null); } start = typeData[1].IndexOf('['); end = typeData[1].IndexOf(']'); if (start >= 0 && end >= 0 && start < end) { var generic = new GenericInstanceType(typeType); var typeG = typeData[1].Substring(start + 1, end - start - 1); var genData = typeG.Split(','); var genTypes = new TypeDefinition[genData.Length]; for (int i = 0; i < genData.Length; i++) { var s = genData[i]; var genName = s.Trim(); var assem = "mscorlib"; if (genName.Contains('|')) { var split = genName.Split('|'); assem = split[0].Trim(); genName = split[1].Trim(); } var genType = GetType(assem, genName, patcher); if (genType == null) { ShowMsg($"GenericType '{genName}' not found", "Missing Type", patcher); return(null); } genTypes[i] = genType; } foreach (var type in genTypes) { generic.GenericArguments.Add(type); } typeType = generic; } Instruction = Instruction.Create(opcode, method.Module.Import(typeType)); break; default: throw new ArgumentOutOfRangeException(); } return(Instruction); }
private Instruction CreateInstruction(MethodDefinition method, ILWeaver weaver, InstructionData instructionData, List<Instruction> insts, Patcher patcher) { var opcode = opCodes[instructionData.OpCode]; var optype = instructionData.OpType; Instruction Instruction = null; switch (optype) { case OpType.None: Instruction = Instruction.Create(opcode); break; case OpType.Byte: Instruction = Instruction.Create(opcode, Convert.ToByte(instructionData.Operand)); break; case OpType.SByte: Instruction = Instruction.Create(opcode, Convert.ToSByte(instructionData.Operand)); break; case OpType.Int32: Instruction = Instruction.Create(opcode, Convert.ToInt32(instructionData.Operand)); break; case OpType.Int64: Instruction = Instruction.Create(opcode, Convert.ToInt64(instructionData.Operand)); break; case OpType.Single: Instruction = Instruction.Create(opcode, Convert.ToSingle(instructionData.Operand)); break; case OpType.Double: Instruction = Instruction.Create(opcode, Convert.ToDouble(instructionData.Operand)); break; case OpType.String: Instruction = Instruction.Create(opcode, Convert.ToString(instructionData.Operand)); break; case OpType.VerbatimString: Instruction = Instruction.Create(opcode, Regex.Unescape(Convert.ToString(instructionData.Operand))); break; case OpType.Instruction: var index = Convert.ToInt32(instructionData.Operand); Instruction = Instruction.Create(opcode, index < 1024 ? weaver.Instructions[index] : insts[index - 1024]); break; case OpType.Variable: Instruction = Instruction.Create(opcode, method.Body.Variables[Convert.ToInt32(instructionData.Operand)]); break; case OpType.Parameter: Instruction = Instruction.Create(opcode, method.Parameters[Convert.ToInt32(instructionData.Operand)]); break; case OpType.Field: var fieldData = Convert.ToString(instructionData.Operand).Split('|'); var fieldType = GetType(fieldData[0], fieldData[1], patcher); if (fieldType == null) return null; var fieldField = fieldType.Fields.FirstOrDefault(f => f.Name.Equals(fieldData[2])); if (fieldField == null) { ShowMsg(string.Format("The Field '{0}' for '{1}' could not be found!", fieldData[2], Name), "Missing Field", patcher); return null; } Instruction = Instruction.Create(opcode, method.Module.Import(fieldField)); break; case OpType.Method: var methodData = Convert.ToString(instructionData.Operand).Split('|'); var methodType = GetType(methodData[0], methodData[1], patcher); if (methodType == null) return null; var methodMethod = methodType.Methods.FirstOrDefault(f => f.Name.Equals(methodData[2])); if (methodMethod == null) { ShowMsg(string.Format("The Method '{0}' for '{1}' could not be found!", methodData[2], Name), "Missing Method", patcher); return null; } Instruction = Instruction.Create(opcode, method.Module.Import(methodMethod)); break; case OpType.Generic: break; case OpType.Type: var typeData = Convert.ToString(instructionData.Operand).Split('|'); var typeType = GetType(typeData[0], typeData[1], patcher); if (typeType == null) return null; Instruction = Instruction.Create(opcode, method.Module.Import(typeType)); break; default: throw new ArgumentOutOfRangeException(); } return Instruction; }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patcher patcher = null) { var insts = new List <Instruction>(); foreach (var instructionData in Instructions) { Instruction instruction; try { instruction = CreateInstruction(original, weaver, instructionData, insts, patcher); } catch (ArgumentOutOfRangeException) { instruction = null; ShowMsg(string.Format("Could not create instruction for {0}!", Name), "Instruction failed", patcher); } if (instruction == null) { return(false); } insts.Add(instruction); } // Start injecting where requested weaver.Pointer = InjectionIndex; if (!weaver.RemoveAfter(RemoveCount)) { ShowMsg(string.Format("The remove count specified for {0} is invalid!", Name), "Invalid Remove Count", patcher); return(false); } if (Instructions.Count == 0) { return(true); } // Get the existing instruction we're going to inject behind Instruction existing; try { existing = weaver.Instructions[weaver.Pointer]; } catch (ArgumentOutOfRangeException) { ShowMsg(string.Format("The injection index specified for {0} is invalid!", Name), "Invalid Index", patcher); return(false); } foreach (var inst in insts) { weaver.Add(inst); } // Find all instructions which pointed to the existing and redirect them for (int i = 0; i < weaver.Instructions.Count; i++) { Instruction ins = weaver.Instructions[i]; if (ins.Operand != null && ins.Operand.Equals(existing)) { // Check if the instruction lies within our injection range // If it does, it's an instruction we just injected so we don't want to edit it if (i < InjectionIndex || i > weaver.Pointer) { ins.Operand = insts[0]; } } } return(true); }
private bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, ref TypeDefinition currentArg, string target) { if (currentArg == null || string.IsNullOrEmpty(target)) return false; while (currentArg != null) { if (currentArg.IsClass) { if (currentArg.HasFields) { foreach (var field in currentArg.Fields) { if (!string.Equals(field.Name, target, StringComparison.CurrentCultureIgnoreCase)) continue; weaver.Add(field.Module == originalMethod.Module ? Instruction.Create(OpCodes.Ldfld, field) : Instruction.Create(OpCodes.Ldfld, originalMethod.Module.Import(field))); currentArg = field.FieldType.Resolve(); return true; } } } if (currentArg.HasProperties) { foreach (var property in currentArg.Properties) { if (!string.Equals(property.Name, target, StringComparison.CurrentCultureIgnoreCase)) continue; weaver.Add(property.GetMethod.Module == originalMethod.Module ? Instruction.Create(OpCodes.Callvirt, property.GetMethod) : Instruction.Create(OpCodes.Callvirt, originalMethod.Module.Import(property.GetMethod))); currentArg = property.PropertyType.Resolve(); return true; } } if (currentArg.HasInterfaces) { foreach (var intf in currentArg.Interfaces) { var previousArg = currentArg; currentArg = intf.Resolve(); if (GetFieldOrProperty(weaver, originalMethod, ref currentArg, target)) return true; currentArg = previousArg; } } currentArg = currentArg.BaseType?.Resolve(); } return false; }
private void optypes_SelectedIndexChanged(object sender, EventArgs e) { Control control = null; var optype = (Modify.OpType)optypes.SelectedItem; switch (optype) { case Modify.OpType.None: break; case Modify.OpType.Byte: case Modify.OpType.SByte: case Modify.OpType.Int32: case Modify.OpType.Int64: case Modify.OpType.Single: case Modify.OpType.Double: case Modify.OpType.String: case Modify.OpType.VerbatimString: case Modify.OpType.Field: case Modify.OpType.Method: case Modify.OpType.Generic: case Modify.OpType.Type: textBox.Text = Instruction?.Operand?.ToString() ?? string.Empty; control = textBox; break; case Modify.OpType.Instruction: var instructions = new List <ListData>(); IList <Instruction> instructionset = method.Body.Instructions; if (hook.BaseHook != null) { var methoddef = PatcherForm.MainForm.GetMethod(hook.AssemblyName, hook.TypeName, hook.Signature); var weaver = new ILWeaver(methoddef.Body) { Module = methoddef.Module }; hook.BaseHook.ApplyPatch(methoddef, weaver, PatcherForm.MainForm.OxideAssembly); instructionset = weaver.Instructions; } for (var i = 0; i < instructionset.Count; i++) { var instruction = instructionset[i]; instructions.Add(new ListData { Text = $"({i}) {instruction.OpCode} {instruction.Operand}", Value = i }); } for (int i = 0; i < hook.Instructions.Count; i++) { var instructionData = hook.Instructions[i]; instructions.Add(new ListData { Text = $"({i + 1024}) {instructionData.OpCode} {instructionData.Operand}", Value = i + 1024 }); } comboBox.DataSource = instructions; control = comboBox; break; case Modify.OpType.Variable: var variables = new List <ListData>(); foreach (var variable in method.Body.Variables) { variables.Add(new ListData { Text = $"({variable.Index}) ({variable.VariableType.FullName})", Value = variable.Index }); } comboBox.DataSource = variables; control = comboBox; break; case Modify.OpType.Parameter: var parameters = new List <ListData>(); foreach (var parameter in method.Parameters) { parameters.Add(new ListData { Text = $"({parameter.Index}) {parameter.Name} ({parameter.ParameterType.FullName})", Value = parameter.Index }); } comboBox.DataSource = parameters; control = comboBox; break; } var current = tablepanel.GetControlFromPosition(1, 2); if (current != control) { if (current != null) { tablepanel.Controls.Remove(current); } if (control != null) { tablepanel.Controls.Add(control, 1, 2); } operandlabel.Visible = control != null; } if (control is ComboBox && Instruction?.Operand != null) { comboBox.SelectedItem = ((List <ListData>)comboBox.DataSource).FirstOrDefault(i => Convert.ToInt32(i.Value) == Convert.ToInt32(Instruction.Operand)); } }
private void DealWithReturnValue(MethodDefinition method, VariableDefinition argsvar, ILWeaver weaver) { // What return behavior do we use? switch (ReturnBehavior) { case Hooks.ReturnBehavior.Continue: // Just discard the return value weaver.Add(Instruction.Create(OpCodes.Pop)); break; case Hooks.ReturnBehavior.ExitWhenValidType: // Is there a return value or not? if (method.ReturnType.FullName == "System.Void") { // If the hook returned something that was non-null, return Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Add(Instruction.Create(OpCodes.Ret)); } else { // Create variable VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the return type, return it - else continue weaver.Add(Instruction.Create(OpCodes.Isinst, method.ReturnType)); Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); weaver.Add(Instruction.Create(OpCodes.Ret)); } break; case Hooks.ReturnBehavior.ModifyRefArg: string wayne; var args = ParseArgumentString(out wayne); if (args == null) { break; } for (int i = 0; i < args.Length; i++) { string arg = args[i].ToLowerInvariant(); if (arg[0] == 'p' || arg[0] == 'a') { int index; if (int.TryParse(arg.Substring(1), out index)) { var pdef = method.Parameters[index]; if (pdef.ParameterType.IsValueType) { weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(i)); weaver.Add(Instruction.Create(OpCodes.Ldelem_Ref)); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, pdef.ParameterType)); weaver.Starg(pdef); } } } else if (arg[0] == 'l' || arg[0] == 'v') { int index; if (int.TryParse(arg.Substring(1), out index)) { var vdef = weaver.Variables[index]; if (vdef.VariableType.IsValueType) { weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(i)); weaver.Add(Instruction.Create(OpCodes.Ldelem_Ref)); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, vdef.VariableType)); weaver.Stloc(vdef); } } } } weaver.Add(Instruction.Create(OpCodes.Pop)); break; case Hooks.ReturnBehavior.UseArgumentString: // Deal with it according to the retvalue of the arg string string retvalue; ParseArgumentString(out retvalue); if (!string.IsNullOrEmpty(retvalue)) { if (retvalue[0] == 'l' && retvalue.Length > 1) { int localindex; if (int.TryParse(retvalue.Substring(1), out localindex)) { // Create variable and get the target variable VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); VariableDefinition targetvar = weaver.Variables[localindex]; // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the variable type, store it in the target variable weaver.Add(Instruction.Create(OpCodes.Isinst, targetvar.VariableType)); Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, targetvar.VariableType)); weaver.Stloc(targetvar); // Handled return; } } else if (retvalue[0] == 'a' && retvalue.Length > 1) { int localindex; if (int.TryParse(retvalue.Substring(1), out localindex)) { // Create variable and get the target parameter VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); ParameterDefinition targetvar = method.Parameters[localindex]; var byReferenceType = targetvar.ParameterType as ByReferenceType; TypeReference targettype = byReferenceType != null ? byReferenceType.ElementType : targetvar.ParameterType; // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the variable type, store it in the target parameter variable Instruction i = weaver.Add(Instruction.Create(OpCodes.Isinst, targettype)); weaver.Add(Instruction.Create(OpCodes.Brfalse_S, i.Next)); if(!targetvar.ParameterType.IsValueType) weaver.Add(ILWeaver.Ldarg(targetvar)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, targettype)); if (!targetvar.ParameterType.IsValueType) weaver.Add(Instruction.Create(OpCodes.Stobj, targettype)); else weaver.Starg(targetvar); // Handled return; } } else if (retvalue == "ret" || retvalue == "return") { // Create variable VariableDefinition returnvar = weaver.AddVariable(method.Module.TypeSystem.Object, "returnvar"); // Store the return value in it weaver.Stloc(returnvar); weaver.Ldloc(returnvar); // If it's non-null and matches the return type, return it - else continue weaver.Add(Instruction.Create(OpCodes.Isinst, method.ReturnType)); Instruction i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); weaver.Add(Instruction.Create(OpCodes.Beq_S, i.Next)); weaver.Ldloc(returnvar); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); weaver.Add(Instruction.Create(OpCodes.Ret)); // Handled return; } } // Not handled weaver.Add(Instruction.Create(OpCodes.Pop)); break; } }
private MethodDefinition BuildDispatchMethod(Patcher patcher, ILWeaver weaver, AssemblyDefinition oxideassembly, ModuleDefinition module, TypeDefinition type, MethodDefinition method, string name) { var parameter_types = new List <TypeReference>(); var object_type = module.Import(typeof(object)); var bool_type = module.Import(typeof(bool)); // Are we going to use arguments? if (ArgumentBehavior != ArgumentBehavior.None) { // Are we using the argument string? if (ArgumentBehavior == ArgumentBehavior.UseArgumentString) { string retvalue; var args = ParseArgumentString(out retvalue); if (args != null) { for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (string.IsNullOrEmpty(arg)) { parameter_types.Add(object_type); continue; } var tokens = new string[0]; if (arg.Contains(".")) { var parts = arg.Split('.'); arg = parts[0]; tokens = parts.Skip(1).ToArray(); } var parameter_type = object_type; if (arg == "this") { if (!method.IsStatic) { parameter_type = type; } } else if (arg[0] == 'p' || arg[0] == 'a') { int index; if (int.TryParse(arg.Substring(1), out index)) { parameter_type = method.Parameters[index].ParameterType; } } else if (arg[0] == 'l' || arg[0] == 'v') { int index; if (int.TryParse(arg.Substring(1), out index)) { parameter_type = weaver.Variables[index].VariableType; } } if (tokens.Length > 0) { parameter_type = GetFieldOrProperty(null, method, parameter_type.Resolve(), tokens, patcher); if (parameter_type == null) { //TODO: Show error? parameter_type = object_type; } } parameter_types.Add(parameter_type); } } } else { // Figure out what we're doing bool includeargs = ArgumentBehavior == ArgumentBehavior.All || ArgumentBehavior == ArgumentBehavior.JustParams; bool includethis = ArgumentBehavior == ArgumentBehavior.All || ArgumentBehavior == ArgumentBehavior.JustThis; if (includethis && !method.IsStatic) { parameter_types.Add(type); } if (includeargs) { for (int i = 0; i < method.Parameters.Count; i++) { var parameter = method.Parameters[i]; if (!parameter.IsOut) { parameter_types.Add(parameter.ParameterType); } } } } } var attributes = MethodAttributes.CompilerControlled | MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig; var new_method = new MethodDefinition("Dispatch_" + name, attributes, module.Import(bool_type)) { DeclaringType = type }; ParameterDefinition ret_parameter = null; if (method.ReturnType.MetadataType != MetadataType.Void) { var ret_type = new ByReferenceType(module.Import(method.ReturnType)); ret_parameter = new ParameterDefinition(ret_type) { Name = "return_value", IsOut = true }; new_method.Parameters.Add(ret_parameter); } foreach (var parameter_type in parameter_types) { new_method.Parameters.Add(new ParameterDefinition(parameter_type.Name.ToLower(), ParameterAttributes.None, module.Import(parameter_type))); } new_method.ImplAttributes = MethodImplAttributes.Managed; var body = new MethodBody(new_method); weaver = new ILWeaver(body) { Module = module }; if (parameter_types.Count > 0) { var argsvar = weaver.AddVariable(new ArrayType(method.Module.TypeSystem.Object), "args"); weaver.Add(ILWeaver.Ldc_I4_n(parameter_types.Count)); weaver.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); weaver.Stloc(argsvar); for (var i = 1; i < new_method.Parameters.Count; i++) { var parameter = new_method.Parameters[i]; weaver.Ldloc(argsvar); weaver.Add(ILWeaver.Ldc_I4_n(i - 1)); weaver.Add(ILWeaver.Ldarg(parameter)); if (parameter.ParameterType.IsByReference) { weaver.Add(Instruction.Create(OpCodes.Ldobj, parameter.ParameterType)); weaver.Add(Instruction.Create(OpCodes.Box, parameter.ParameterType)); } else if (parameter.ParameterType.IsValueType) { weaver.Add(Instruction.Create(OpCodes.Box, parameter.ParameterType)); } weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } weaver.Add(Instruction.Create(OpCodes.Ldstr, HookName)); weaver.Ldloc(argsvar); } else { weaver.Add(Instruction.Create(OpCodes.Ldnull)); } var callhook = oxideassembly.MainModule.GetType("Oxide.Core.Interface").Methods.Single(m => m.Name == "CallHook"); weaver.Add(Instruction.Create(OpCodes.Call, module.Import(callhook))); if (ret_parameter != null) { var result = weaver.AddVariable(module.Import(module.TypeSystem.Object), "result"); weaver.Stloc(result); weaver.Ldloc(result); // Check if the CallHook return is not null and matches the return type weaver.Add(Instruction.Create(OpCodes.Isinst, method.ReturnType)); var i = weaver.Add(Instruction.Create(OpCodes.Ldnull)); var skip_ret_handling = weaver.Add(Instruction.Create(OpCodes.Beq_S, i)); // Unbox return and set it to the ret out parameter weaver.Ldloc(result); weaver.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); weaver.Starg(ret_parameter); // Return true weaver.Add(Instruction.Create(OpCodes.Ldc_I4_1)); weaver.Add(Instruction.Create(OpCodes.Ret)); skip_ret_handling.Operand = weaver.Add(Instruction.Create(OpCodes.Ldc_I4_0)); } else { weaver.Add(Instruction.Create(OpCodes.Ldc_I4_0)); } weaver.Add(Instruction.Create(OpCodes.Ret)); weaver.Apply(body); //body.SimplifyMacros(); //TODO: Add Cecil.Rocks if this is needed new_method.Body = body; type.Methods.Add(new_method); return(new_method); }
public static async Task <string> GetSourceCode(MethodDefinition methodDefinition, ILWeaver weaver = null) { return(await Task.Run(() => { try { if (weaver != null) { weaver.Apply(methodDefinition.Body); } var settings = new DecompilerSettings { UsingDeclarations = false }; var context = new DecompilerContext(methodDefinition.Module) { CurrentType = methodDefinition.DeclaringType, Settings = settings }; var astBuilder = new AstBuilder(context); astBuilder.AddMethod(methodDefinition); var textOutput = new PlainTextOutput(); astBuilder.GenerateCode(textOutput); return textOutput.ToString(); } catch (Exception ex) { return "Error in creating source code from IL: " + ex.Message + Environment.NewLine + ex.StackTrace; } finally { if (weaver != null) { methodDefinition.Body = null; } } })); }
/// <summary> /// Attempts to deobfuscate the specified type /// </summary> /// <param name="typedef"></param> protected virtual void DeobfuscateType(TypeDefinition typedef) { // Deal with method parameters foreach (MethodDefinition method in typedef.Methods .Where((m) => m.HasParameters) ) { for (int i = 0; i < method.Parameters.Count; i++) { ParameterDefinition paramdef = method.Parameters[i]; if (IdentifyObfuscatedName(paramdef.Name)) { string name = string.Format("arg{0}", i); paramdef.Name = name; } } } // Deal with field names FieldDefinition[] fields = typedef.Fields .Where((f) => IdentifyObfuscatedName(f.Name)) .ToArray(); Array.Sort(fields, (a, b) => { // Sort firstly by type // Then sort by offset // Finally, sort by obfuscated name int tmp = Comparer<string>.Default.Compare(a.FieldType.FullName, b.FieldType.FullName); if (tmp != 0) return tmp; tmp = Comparer<int>.Default.Compare(a.Offset, b.Offset); if (tmp != 0) return tmp; return Comparer<string>.Default.Compare(a.Name, b.Name); }); for (int i = 0; i < fields.Length; i++) { FieldDefinition field = fields[i]; string name; if (field.IsPublic) name = string.Format("Field{0}", i + 1); else name = string.Format("field{0}", i + 1); field.Name = name; } // Deal with property names PropertyDefinition[] properties = typedef.Properties .Where((f) => IdentifyObfuscatedName(f.Name)) .ToArray(); Array.Sort(properties, (a, b) => { // Sort firstly by type, then by obfuscated name int tmp = Comparer<string>.Default.Compare(a.PropertyType.FullName, b.PropertyType.FullName); if (tmp != 0) return tmp; return Comparer<string>.Default.Compare(a.Name, b.Name); }); for (int i = 0; i < properties.Length; i++) { PropertyDefinition property = properties[i]; string name = string.Format("property{0}", i + 1); // NOTE: Do we need to rename the get and set methods too? property.Name = name; } // Deal with method names MethodDefinition[] methods = typedef.Methods .Where((f) => IdentifyObfuscatedName(f.Name)) .ToArray(); Array.Sort(methods, (a, b) => { // Sort by the following in order: return type, parameter count, parameter types, obfuscated name int tmp = Comparer<string>.Default.Compare(a.ReturnType.FullName, b.ReturnType.FullName); if (tmp != 0) return tmp; tmp = Comparer<int>.Default.Compare(a.Parameters.Count, b.Parameters.Count); if (tmp != 0) return tmp; // TODO: Sort by parameter types return Comparer<string>.Default.Compare(a.Name, b.Name); }); for (int i = 0; i < methods.Length; i++) { MethodDefinition method = methods[i]; string name; if (method.IsPublic) name = string.Format("Method{0}", i + 1); else name = string.Format("method{0}", i + 1); method.Name = name; } // Deal with proxy methods HashSet<MethodDefinition> toremove = new HashSet<MethodDefinition>(); foreach (MethodDefinition method in typedef.Methods .Where((m) => m.HasBody) ) { // Identify a proxy call via IL var instructions = method.Body.Instructions; if (instructions.Count != 3) continue; if (instructions[0].OpCode.Code != Code.Ldarg_0) continue; if (instructions[1].OpCode.Code != Code.Callvirt) continue; if (instructions[2].OpCode.Code != Code.Ret) continue; // Check that it's calling an obfuscated method in our type MethodReference proxymethod = instructions[1].Operand as MethodReference; if (proxymethod.DeclaringType.FullName != typedef.FullName) continue; if (!methods.Any((m) => m.FullName == proxymethod.FullName)) continue; // Check that the target method is not referenced by anything else int refcount; if (!refcounts.TryGetValue(proxymethod, out refcount)) refcount = 0; if (refcount > 1) continue; // Resolve it MethodDefinition proxymethoddef = proxymethod.Resolve(); if (!proxymethoddef.HasBody) continue; // It passed, collapse the proxy method's IL into this method and remove it ILWeaver weaver = new ILWeaver(proxymethoddef.Body); weaver.Apply(method.Body); toremove.Add(proxymethoddef); } // Remove any proxy methods foreach (MethodDefinition method in toremove) { typedef.Methods.Remove(method); } }
protected override async void OnLoad(EventArgs e) { base.OnLoad(e); assembly = MainForm.LoadAssembly(Hook.AssemblyName); methoddef = MainForm.GetMethod(Hook.AssemblyName, Hook.TypeName, Hook.Signature); hooktypes = new List <Type>(); int selindex = 0; int i = 0; foreach (Type hooktype in Hook.GetHookTypes()) { string typename = hooktype.GetCustomAttribute <HookType>().Name; hooktypedropdown.Items.Add(typename); hooktypes.Add(hooktype); if (typename == Hook.HookTypeName) { selindex = i; } i++; } List <Hook> hooks = MainForm.CurrentProject.GetManifest(Hook.AssemblyName).Hooks; List <Hook> baseHooks = (from hook in hooks where hook.BaseHook != null select hook.BaseHook).ToList(); basehookdropdown.Items.Add(""); int selindex2 = 0; i = 1; foreach (Hook hook in hooks) { if (hook.BaseHook == Hook) { clonebutton.Enabled = false; } if (hook != Hook.BaseHook && baseHooks.Contains(hook)) { continue; } basehookdropdown.Items.Add(hook.Name); if (hook == Hook.BaseHook) { selindex2 = i; } i++; } assemblytextbox.Text = Hook.AssemblyName; typenametextbox.Text = Hook.TypeName; if (methoddef != null) { methodnametextbox.Text = Hook.Signature.ToString(); } else { methodnametextbox.Text = Hook.Signature + " (METHOD MISSING)"; } nametextbox.Text = Hook.Name; hooknametextbox.Text = Hook.HookName; ignoretypechange = true; hooktypedropdown.SelectedIndex = selindex; basehookdropdown.SelectedIndex = selindex2; ignoretypechange = false; applybutton.Enabled = false; if (Hook.Flagged) { flagbutton.Enabled = false; unflagbutton.Enabled = true; unflagbutton.Focus(); } else { flagbutton.Enabled = true; unflagbutton.Enabled = false; flagbutton.Focus(); } HookSettingsControl settingsview = Hook.CreateSettingsView(); if (settingsview == null) { Label tmp = new Label(); tmp.TextAlign = ContentAlignment.MiddleCenter; tmp.AutoSize = false; tmp.Text = "No settings."; tmp.Dock = DockStyle.Fill; hooksettingstab.Controls.Add(tmp); } else { settingsview.Dock = DockStyle.Fill; settingsview.OnSettingsChanged += settingsview_OnSettingsChanged; hooksettingstab.Controls.Add(settingsview); } if (methoddef == null) { Label missinglabel1 = new Label(); missinglabel1.Dock = DockStyle.Fill; missinglabel1.AutoSize = false; missinglabel1.Text = "METHOD MISSING"; missinglabel1.TextAlign = ContentAlignment.MiddleCenter; beforetab.Controls.Add(missinglabel1); Label missinglabel2 = new Label(); missinglabel2.Dock = DockStyle.Fill; missinglabel2.AutoSize = false; missinglabel2.Text = "METHOD MISSING"; missinglabel2.TextAlign = ContentAlignment.MiddleCenter; aftertab.Controls.Add(missinglabel2); return; } ILWeaver weaver = new ILWeaver(methoddef.Body) { Module = methoddef.Module }; Hook.PreparePatch(assembly, methoddef, weaver, MainForm.OxideAssembly); msilbefore = new TextEditorControl { Dock = DockStyle.Fill, Text = weaver.ToString(), IsReadOnly = true }; codebefore = new TextEditorControl { Dock = DockStyle.Fill, Text = await Decompiler.GetSourceCode(methoddef, weaver), Document = { HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("C#") }, IsReadOnly = true }; Hook.ApplyPatch(assembly, methoddef, weaver, MainForm.OxideAssembly); msilafter = new TextEditorControl { Dock = DockStyle.Fill, Text = weaver.ToString(), IsReadOnly = true }; codeafter = new TextEditorControl { Dock = DockStyle.Fill, Text = await Decompiler.GetSourceCode(methoddef, weaver), Document = { HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("C#") }, IsReadOnly = true }; beforetab.Controls.Add(msilbefore); aftertab.Controls.Add(msilafter); codebeforetab.Controls.Add(codebefore); codeaftertab.Controls.Add(codeafter); }
/// <summary> /// PrePatches this hook into the target weaver /// </summary> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="original"></param> /// <param name="patcher"></param> public bool PreparePatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patcher patcher = null) { if (BaseHook != null) { return BaseHook.PreparePatch(original, weaver, oxidemodule, patcher) && BaseHook.ApplyPatch(original, weaver, oxidemodule, patcher); } return true; }