public override bool ApplyPatch(AssemblyDefinition assembly, 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); }
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, 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 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 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 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); }
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; }
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); }
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); }
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 void PushArgsArray(MethodDefinition method, ILWeaver weaver) { // Are we going to use arguments? if (ArgumentBehaviour == Hooks.ArgumentBehaviour.None) { // Push null and we're done weaver.Add(Instruction.Create(OpCodes.Ldnull)); return; } // Create array variable VariableDefinition argsvar = weaver.AddVariable(new ArrayType(method.Module.TypeSystem.Object), "args"); // Are we using the argument string? if (ArgumentBehaviour == Hooks.ArgumentBehaviour.UseArgumentString) { string retvalue; string[] args = ParseArgumentString(out retvalue); if (args == null) { // Silently fail, but at least produce valid IL weaver.Add(Instruction.Create(OpCodes.Ldnull)); return; } // Create the array 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_n(0)); } } 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_n(pdef.Sequence)); 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]; 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)); } weaver.Ldloc(vdef); } 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 = ArgumentBehaviour == Hooks.ArgumentBehaviour.All || ArgumentBehaviour == Hooks.ArgumentBehaviour.JustParams; bool includethis = ArgumentBehaviour == Hooks.ArgumentBehaviour.All || ArgumentBehaviour == Hooks.ArgumentBehaviour.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); } } } // Load arg count, create array, store if (includethis) { weaver.Add(ILWeaver.Ldc_I4_n(args.Count + 1)); } else { 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_n(0)); 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_n(args[i].Sequence)); 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)); } } // Finally, load it weaver.Ldloc(argsvar); }
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 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 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 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; }
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; } }
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, 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 void DealWithReturnValue(MethodDefinition method, ILWeaver weaver) { // What return behaviour do we use? switch (ReturnBehaviour) { case Hooks.ReturnBehaviour.Continue: // Just discard the return value weaver.Add(Instruction.Create(OpCodes.Pop)); break; case Hooks.ReturnBehaviour.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.ReturnBehaviour.ModifyRefArg: // TODO: This weaver.Add(Instruction.Create(OpCodes.Pop)); break; case Hooks.ReturnBehaviour.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 == "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); }
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 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; }