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);
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 3
0
        /// <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);
            }
        }
Exemplo n.º 4
0
        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 {