public override MethodBase DetourTo(MethodBase replacement) { DebugCheck(); DynamicMethodDefinition newreplacementdmd = CopyOriginal(); HarmonyManipulator.Manipulate(Original, Original.GetPatchInfo(), new ILContext(newreplacementdmd.Definition)); MethodInfo newreplacement = newreplacementdmd.Generate(); MethodInfo il2CppShim = CreateIl2CppShim(newreplacement).Generate(); Type il2CppShimDelegateType = DelegateTypeFactory.instance.CreateDelegateType(il2CppShim, CallingConvention.Cdecl); Delegate il2CppShimDelegate = il2CppShim.CreateDelegate(il2CppShimDelegateType); IntPtr il2CppShimDelegatePtr = il2CppShimDelegate.GetFunctionPointer(); if (methodDetourPointer != IntPtr.Zero) { MelonUtils.NativeHookDetach(copiedMethodInfoPointer, methodDetourPointer); } MelonUtils.NativeHookAttach(copiedMethodInfoPointer, il2CppShimDelegatePtr); methodDetourPointer = il2CppShimDelegatePtr; PatchTools_RememberObject(Original, new LemonTuple <MethodInfo, MethodInfo, Delegate> { Item1 = newreplacement, Item2 = il2CppShim, Item3 = il2CppShimDelegate }); return(newreplacement); }
/// <inheritdoc /> public override MethodBase DetourTo(MethodBase replacement) { // Unpatch an existing detour if it exists nativeDetour?.Dispose(); // Generate a new DMD of the modified unhollowed method, and apply harmony patches to it var copiedDmd = CopyOriginal(); HarmonyManipulator.Manipulate(copiedDmd.OriginalMethod, copiedDmd.OriginalMethod.GetPatchInfo(), new ILContext(copiedDmd.Definition)); // Generate the MethodInfo instances var managedHookedMethod = copiedDmd.Generate(); var unmanagedTrampolineMethod = GenerateNativeToManagedTrampoline(managedHookedMethod).Generate(); // Apply a detour from the unmanaged implementation to the patched harmony method var unmanagedDelegateType = DelegateTypeFactory.instance.CreateDelegateType(unmanagedTrampolineMethod, CallingConvention.Cdecl); var detourPtr = Marshal.GetFunctionPointerForDelegate(unmanagedTrampolineMethod.CreateDelegate(unmanagedDelegateType)); nativeDetour = new FastNativeDetour(originalNativeMethodInfo->methodPointer, detourPtr); nativeDetour.Apply(); // TODO: Add an ILHook for the original unhollowed method to go directly to managedHookedMethod // Right now it goes through three times as much interop conversion as it needs to, when being called from managed side return(managedHookedMethod); }
/// <summary>Creates new replacement method with the latest patches and detours the original method</summary> /// <param name="original">The original method</param> /// <param name="patchInfo">Information describing the patches</param> /// <returns>The newly created replacement method</returns> /// internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo) { var patcher = original.GetMethodPatcher(); var dmd = patcher.PrepareOriginal(); if (dmd != null) { var ctx = new ILContext(dmd.Definition); HarmonyManipulator.Manipulate(original, patchInfo, ctx); } try { return(patcher.DetourTo(dmd?.Generate()) as MethodInfo); } catch (Exception ex) { throw HarmonyException.Create(ex, dmd?.Definition?.Body); } }
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 {