private TypeDefinition GetType(string assemblyName, string typeName, Patching.Patcher patcher) { string targetDir = patcher != null ? patcher.PatchProject.TargetDirectory : PatcherForm.MainForm.CurrentProject.TargetDirectory; DefaultAssemblyResolver resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(targetDir); string filename = Path.Combine(targetDir, assemblyName.Replace(".dll", "") + ".dll"); AssemblyDefinition assem = AssemblyDefinition.ReadAssembly(filename, new ReaderParameters { AssemblyResolver = resolver }); if (assem == null) { ShowMsg($"The Assembly '{assemblyName}' for '{Name}' could not be found!", "Missing Assembly", patcher); return(null); } TypeDefinition type = assem.MainModule.GetType(typeName); if (type == null) { ShowMsg($"The Type '{typeName}' for '{Name}' could not be found!", "Missing Type", patcher); return(null); } return(type); }
protected void ShowMsg(string msg, string header, Patching.Patcher patcher = null) { if (patcher != null) { patcher.Log(msg); } else { MessageBox.Show(msg, header, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxideassembly, Patching.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($"The injection index specified for {Name} is invalid!", "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); }
public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patching.Patcher patcher = null) { List <Instruction> insts = new List <Instruction>(); foreach (InstructionData instructionData in Instructions) { Instruction instruction; try { instruction = CreateInstruction(original, weaver, instructionData, insts, patcher); } catch (ArgumentOutOfRangeException) { instruction = null; ShowMsg($"Could not create instruction for {Name}!", "Instruction failed", patcher); } if (instruction == null) { return(false); } insts.Add(instruction); } // Start injecting where requested weaver.Pointer = InjectionIndex; if (!weaver.RemoveAfter(RemoveCount)) { ShowMsg($"The remove count specified for {Name} is invalid!", "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($"The injection index specified for {Name} is invalid!", "Invalid Index", patcher); return(false); } foreach (Instruction 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 Instruction CreateInstruction(MethodDefinition method, ILWeaver weaver, InstructionData instructionData, List <Instruction> insts, Patching.Patcher patcher) { OpCode opcode = opCodes[instructionData.OpCode]; OpType 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: int 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: string[] fieldData = Convert.ToString(instructionData.Operand).Split('|'); TypeDefinition fieldType = GetType(fieldData[0], fieldData[1], patcher); if (fieldType == null) { return(null); } FieldDefinition fieldField = fieldType.Fields.FirstOrDefault(f => f.Name.Equals(fieldData[2])); if (fieldField == null) { ShowMsg($"The Field '{fieldData[2]}' for '{Name}' could not be found!", "Missing Field", patcher); return(null); } Instruction = Instruction.Create(opcode, method.Module.Import(fieldField)); break; case OpType.Method: string[] methodData = Convert.ToString(instructionData.Operand).Split('|'); TypeDefinition 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) { string name = TagsRegex.Replace(methodData[2], string.Empty).Trim(); string methodSig = methodData[2].Substring(start + 1, end - start - 1); string[] sigData = methodSig.Split(','); TypeDefinition[] sigTypes = new TypeDefinition[sigData.Length]; for (int i = 0; i < sigData.Length; i++) { string s = sigData[i]; string sigName = s.Trim(); string assem = "mscorlib"; if (sigName.Contains('|')) { string[] split = sigName.Split('|'); assem = split[0].Trim(); sigName = split[1].Trim(); } TypeDefinition sigType = GetType(assem, sigName, patcher); if (sigType == null) { ShowMsg($"SigType '{sigName}' not found", "Missing Method", patcher); return(null); } sigTypes[i] = sigType; } methodMethod = null; foreach (MethodDefinition methodDefinition in methodType.Methods) { if (!methodDefinition.Name.Equals(name) || methodDefinition.Parameters.Count != sigTypes.Length) { continue; } bool match = true; for (int i = 0; i < methodDefinition.Parameters.Count; i++) { ParameterDefinition parameter = methodDefinition.Parameters[i]; if (!parameter.ParameterType.FullName.Equals(sigTypes[i].FullName)) { match = false; break; } } if (!match) { continue; } methodMethod = methodDefinition; break; } } else { string methodName = methodData[2]; int position = methodName.IndexOf('['); if (position > 0) { methodName = methodName.Substring(0, position); } methodMethod = methodType.Methods.FirstOrDefault(f => { if (!f.Name.Equals(methodName)) { return(false); } if (position <= 0) { return(true); } return(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) { GenericInstanceMethod generic = new GenericInstanceMethod(methodMethod); string methodG = methodData[2].Substring(start + 1, end - start - 1); string[] genData = methodG.Split(','); TypeDefinition[] genTypes = new TypeDefinition[genData.Length]; for (int i = 0; i < genData.Length; i++) { string s = genData[i]; string genName = s.Trim(); string assem = "mscorlib"; if (genName.Contains('|')) { string[] split = genName.Split('|'); assem = split[0].Trim(); genName = split[1].Trim(); } TypeDefinition genType = GetType(assem, genName, patcher); if (genType == null) { ShowMsg($"GenericType '{genName}' not found", "Missing Method", patcher); return(null); } genTypes[i] = genType; } foreach (TypeDefinition 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: string[] 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) { GenericInstanceType generic = new GenericInstanceType(typeType); string typeG = typeData[1].Substring(start + 1, end - start - 1); string[] genData = typeG.Split(','); TypeDefinition[] genTypes = new TypeDefinition[genData.Length]; for (int i = 0; i < genData.Length; i++) { string s = genData[i]; string genName = s.Trim(); string assem = "mscorlib"; if (genName.Contains('|')) { string[] split = genName.Split('|'); assem = split[0].Trim(); genName = split[1].Trim(); } TypeDefinition genType = GetType(assem, genName, patcher); if (genType == null) { ShowMsg($"GenericType '{genName}' not found", "Missing Type", patcher); return(null); } genTypes[i] = genType; } foreach (TypeDefinition type in genTypes) { generic.GenericArguments.Add(type); } typeType = generic; } Instruction = Instruction.Create(opcode, method.Module.Import(typeType)); break; default: throw new ArgumentOutOfRangeException(); } return(Instruction); }
/// <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)); }
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); }
private bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, ref TypeDefinition currentArg, string target, Patching.Patcher patcher) { if (currentArg == null || string.IsNullOrEmpty(target)) { return(false); } while (currentArg != null) { if (currentArg.IsClass) { if (currentArg.HasFields) { foreach (FieldDefinition 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 (PropertyDefinition 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 (TypeReference intf in currentArg.Interfaces) { TypeDefinition 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) { TypeReference baseType = currentArg.BaseType; AssemblyDefinition 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 bool GetFieldOrProperty(ILWeaver weaver, MethodDefinition originalMethod, TypeDefinition currentArg, string[] target, Patching.Patcher patcher) { if (currentArg == null || target == null || target.Length == 0) { return(false); } int i; TypeDefinition 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); }
private Instruction PushArgsArray(MethodDefinition method, ILWeaver weaver, /*out VariableDefinition argsvar*/ out int argCount, Patching.Patcher patcher) { argCount = 0; // Are we going to use arguments? if (ArgumentBehavior == ArgumentBehavior.None) { // Push null and we're done //argsvar = null; return(null); } // Create array variable Instruction firstInstruction = null; // Are we using the argument string? if (ArgumentBehavior == ArgumentBehavior.UseArgumentString) { string[] args = ParseArgumentString(out string 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++) { argCount++; 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') { if (int.TryParse(arg.Substring(1), out int 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') { if (int.TryParse(arg.Substring(1), out int 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 == ArgumentBehavior.All || ArgumentBehavior == ArgumentBehavior.JustParams; bool includethis = ArgumentBehavior == ArgumentBehavior.All || ArgumentBehavior == 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)); argCount++; weaver.Add(ILWeaver.Ldarg(null)); //weaver.Add(Instruction.Create(OpCodes.Stelem_Ref)); } // Loop each argument for (int i = 0; i < args.Count; i++) { argCount++; // 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="original"></param> /// <param name="weaver"></param> /// <param name="oxidemodule"></param> /// <param name="patcher"></param> public abstract bool ApplyPatch(MethodDefinition original, ILWeaver weaver, AssemblyDefinition oxidemodule, Patching.Patcher patcher = null);
/// <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); }