public void Invoke(ILManipulator manip) { foreach (Instruction instr in Instrs) { if (instr.Operand is Instruction target) { instr.Operand = new HookILLabel(this, target); } else if (instr.Operand is Instruction[] targets) { instr.Operand = targets.Select(t => new HookILLabel(this, t)).ToArray(); } } manip(this); foreach (Instruction instr in Instrs) { if (instr.Operand is HookILLabel label) { instr.Operand = label.Target; } else if (instr.Operand is HookILLabel[] targets) { instr.Operand = targets.Select(l => l.Target).ToArray(); } } Method.ConvertShortLongOps(); }
internal static Exception Create(Exception ex, MethodBody body) { var match = Regex.Match(ex.Message.TrimEnd(), "Reason: Invalid IL code in.+: IL_(\\d{4}): (.+)$"); if (match.Success is false) { return(new HarmonyException("IL Compile Error (unknown location)", ex)); } var finalInstructions = ILManipulator.GetInstructions(body) ?? new Dictionary <int, CodeInstruction>(); var offset = int.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber); _ = Regex.Replace(match.Groups[2].Value, " {2,}", " "); if (ex is HarmonyException hEx) { if (finalInstructions.Count != 0) { hEx.instructions = finalInstructions; hEx.errorOffset = offset; } return(hEx); } return(new HarmonyException(ex, finalInstructions, offset)); }
private void ApplyReversePatch(ILContext ctx) { // Make a cecil copy of the original method for convenience sake var dmd = new DynamicMethodDefinition(original); var manipulator = new ILManipulator(dmd.Definition.Body); // Copy over variables from the original code ctx.Body.Variables.Clear(); foreach (var variableDefinition in dmd.Definition.Body.Variables) { ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(variableDefinition.VariableType))); } var transpiler = GetTranspiler(standin); if (transpiler != null) { manipulator.AddTranspiler(transpiler); } manipulator.WriteTo(ctx.Body, standin); // Write a ret in case it got removed (wrt. HarmonyManipulator) ctx.IL.Emit(OpCodes.Ret); }
internal void Invoke(ILManipulator manip) { manip(this); foreach (HookILLabel label in Labels) { IL.ReplaceOperands(label, label.Instr); } }
/// <summary>Returns the methods unmodified list of CodeInstructions</summary> /// <param name="original">The original method</param> /// <param name="generator">A new generator that now contains all local variables and labels contained in the result</param> /// <returns>A list containing all the original CodeInstructions</returns> public static List<CodeInstruction> GetOriginalInstructions(MethodBase original, out ILGenerator generator) { // Create a copy var dmd = new DynamicMethodDefinition(original); // Create a manipulator to obtain the instructions var manipulator = new ILManipulator(dmd.Definition.Body); generator = new CecilILGenerator(dmd.GetILProcessor()).GetProxy(); return manipulator.GetInstructions(generator); }
public void Invoke(ILManipulator manip) { manip(this); foreach (HookILLabel label in Labels) { IL.ReplaceOperands(label, label.Instr); } Method.RecalculateILOffsets(); Method.ConvertShortLongOps(); }
/// <summary>A low level way to read the body of a method. Used for quick searching in methods</summary> /// <param name="method">The original method</param> /// <param name="generator">An existing generator that will be used to create all local variables and labels contained in the result</param> /// <returns>All instructions as opcode/operand pairs</returns> /// public static IEnumerable <KeyValuePair <OpCode, object> > ReadMethodBody(MethodBase method, ILGenerator generator) { var original = method.GetMethodPatcher().CopyOriginal(); if (original == null) { return(null); } var manipulator = new ILManipulator(original.Definition.Body); // Force label generation _ = manipulator.GetInstructions(generator); return(manipulator.GetRawInstructions()); }
public void Invoke(ILManipulator manip) { foreach (Instruction instr in Instrs) { if (instr.Operand is Instruction target) { instr.Operand = new HookILLabel(this, target); } } manip(this); foreach (Instruction instr in Instrs) { if (instr.Operand is HookILLabel label) { instr.Operand = label.Target; } } }
internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler, MethodInfo postManipulator) { if (standin is null) { throw new ArgumentNullException(nameof(standin)); } if (standin.method is null) { throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}"); } var transpilers = new List <MethodInfo>(); var ilmanipulators = new List <MethodInfo>(); if (standin.reversePatchType == HarmonyReversePatchType.Snapshot) { var info = Harmony.GetPatchInfo(original); transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray())); ilmanipulators.AddRange(GetSortedPatchMethods(original, info.ILManipulators.ToArray())); } if (postTranspiler is object) { transpilers.Add(postTranspiler); } if (postManipulator is object) { ilmanipulators.Add(postManipulator); } MethodBody patchBody = null; var hook = new ILHook(standin.method, ctx => { if (!(original is MethodInfo mi)) { return; } patchBody = ctx.Body; var patcher = mi.GetMethodPatcher(); var dmd = patcher.CopyOriginal(); if (dmd == null) { throw new NullReferenceException($"Cannot reverse patch {mi.FullDescription()}: method patcher ({patcher.GetType().FullDescription()}) can't copy original method body"); } var manipulator = new ILManipulator(dmd.Definition.Body); // Copy over variables from the original code ctx.Body.Variables.Clear(); foreach (var variableDefinition in manipulator.Body.Variables) { ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(variableDefinition.VariableType))); } foreach (var methodInfo in transpilers) { manipulator.AddTranspiler(methodInfo); } manipulator.WriteTo(ctx.Body, standin.method); HarmonyManipulator.ApplyILManipulators(ctx, original, ilmanipulators, null); // Write a ret in case it got removed (wrt. HarmonyManipulator) ctx.IL.Emit(OpCodes.Ret); }, new ILHookConfig {