Beispiel #1
0
        internal static void ReversePatch(MethodInfo standin, MethodBase original, string instanceID, MethodInfo transpiler)
        {
            var emptyFixes  = new List <MethodInfo>();
            var transpilers = new List <MethodInfo>();

            if (transpiler != null)
            {
                transpilers.Add(transpiler);
            }

            var replacement = MethodPatcher.CreatePatchedMethod(standin, original, instanceID, emptyFixes, emptyFixes, transpilers, emptyFixes);

            if (replacement == null)
            {
                throw new MissingMethodException("Cannot create dynamic replacement for " + standin.FullDescription());
            }

            var errorString = Memory.DetourMethod(standin, replacement);

            if (errorString != null)
            {
                throw new FormatException("Method " + standin.FullDescription() + " cannot be patched. Reason: " + errorString);
            }

            PatchTools.RememberObject(standin, replacement);
        }
Beispiel #2
0
        internal static List <CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }
            if (method == null)
            {
                throw new ArgumentNullException(nameof(method));
            }

            var originalVariables     = MethodPatcher.DeclareLocalVariables(generator, method);
            var useStructReturnBuffer = StructReturnBuffer.NeedsFix(method);
            var copier = new MethodCopier(method, generator, originalVariables);

            copier.SetArgumentShift(useStructReturnBuffer);

            var info = Harmony.GetPatchInfo(method);

            if (info != null)
            {
                var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, info.Transpilers.ToArray(), false);
                for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++)
                {
                    copier.AddTranspiler(sortedTranspilers[i]);
                }
            }

            return(copier.Finalize(null, null, out var _));
        }
Beispiel #3
0
        /// <summary>Creates new dynamic 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>
        /// <param name="instanceID">Harmony ID</param>
        /// <returns>The newly created dynamic method</returns>
        ///
        internal static DynamicMethod UpdateWrapper(MethodBase original, PatchInfo patchInfo, string instanceID)
        {
            var sortedPrefixes    = GetSortedPatchMethods(original, patchInfo.prefixes);
            var sortedPostfixes   = GetSortedPatchMethods(original, patchInfo.postfixes);
            var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers);
            var sortedFinalizers  = GetSortedPatchMethods(original, patchInfo.finalizers);

            var replacement = MethodPatcher.CreatePatchedMethod(original, null, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers);

            if (replacement == null)
            {
                throw new MissingMethodException("Cannot create dynamic replacement for " + original.FullDescription());
            }

            var errorString = Memory.DetourMethod(original, replacement);

            if (errorString != null)
            {
                throw new FormatException("Method " + original.FullDescription() + " cannot be patched. Reason: " + errorString);
            }

            PatchTools.RememberObject(original, replacement);             // no gc for new value + release old value to gc

            return(replacement);
        }
Beispiel #4
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 debug = patchInfo.Debugging || Harmony.DEBUG;

            var sortedPrefixes    = GetSortedPatchMethods(original, patchInfo.prefixes, debug);
            var sortedPostfixes   = GetSortedPatchMethods(original, patchInfo.postfixes, debug);
            var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers, debug);
            var sortedFinalizers  = GetSortedPatchMethods(original, patchInfo.finalizers, debug);

            var patcher     = new MethodPatcher(original, null, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers, debug);
            var replacement = patcher.CreateReplacement(out var finalInstructions);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create replacement for {original.FullDescription()}");
            }

            try
            {
                Memory.DetourMethodAndPersist(original, replacement);
            }
            catch (Exception ex)
            {
                throw HarmonyException.Create(ex, finalInstructions);
            }
            return(replacement);
        }
Beispiel #5
0
        internal static List <CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }
            if (method == null)
            {
                throw new ArgumentNullException(nameof(method));
            }

            var originalVariables     = MethodPatcher.DeclareLocalVariables(generator, method);
            var useStructReturnBuffer = StructReturnBuffer.NeedsFix(method);
            var copier = new MethodCopier(method, generator, originalVariables);

            copier.SetArgumentShift(useStructReturnBuffer);

            var info = Harmony.GetPatchInfo(method);

            if (info != null)
            {
                var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, info.Transpilers.ToArray(), false);
                for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++)
                {
                    copier.AddTranspiler(sortedTranspilers[i]);
                }
            }

            var endLabels = new List <Label>();
            var emitter   = new Emitter(generator, false);

            copier.Finalize(emitter, endLabels, out var hasReturnCode);
            return(emitter.GetInstructions().OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList());
        }
Beispiel #6
0
        /// <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)
        {
            var patch = MethodPatcher.CreateDynamicMethod(original, $"_Copy{Guid.NewGuid()}");

            generator = patch.GetILGenerator();
            var reader = MethodBodyReader.GetInstructions(generator, original);

            return(reader.Select(ins => ins.GetCodeInstruction()).ToList());
        }
Beispiel #7
0
        internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler)
        {
            if (standin == null)
            {
                throw new ArgumentNullException(nameof(standin));
            }
            if (standin.method == null)
            {
                throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}");
            }

            var debug = (standin.debug ?? false) || Harmony.DEBUG;

            var transpilers = new List <MethodInfo>();

            if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
            {
                var info = Harmony.GetPatchInfo(original);
                transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray(), debug));
            }
            if (postTranspiler != null)
            {
                transpilers.Add(postTranspiler);
            }

            var empty       = new List <MethodInfo>();
            var patcher     = new MethodPatcher(standin.method, original, empty, empty, transpilers, empty, debug);
            var replacement = patcher.CreateReplacement(out var finalInstructions);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create replacement for {standin.method.FullDescription()}");
            }

            try
            {
                var errorString = Memory.DetourMethod(standin.method, replacement);
                if (errorString != null)
                {
                    throw new FormatException($"Method {standin.method.FullDescription()} cannot be patched. Reason: {errorString}");
                }
            }
            catch (Exception ex)
            {
                throw HarmonyException.Create(ex, finalInstructions);
            }

            PatchTools.RememberObject(standin.method, replacement);
            return(replacement);
        }
Beispiel #8
0
        /// <summary>Creates new dynamic 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>
        /// <param name="instanceID">Harmony ID</param>
        /// <returns>The newly created dynamic method</returns>
        ///
        internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo, string instanceID)
        {
            var sortedPrefixes    = GetSortedPatchMethods(original, patchInfo.prefixes);
            var sortedPostfixes   = GetSortedPatchMethods(original, patchInfo.postfixes);
            var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers);
            var sortedFinalizers  = GetSortedPatchMethods(original, patchInfo.finalizers);

            var replacement = MethodPatcher.CreatePatchedMethod(original, null, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create dynamic replacement for {original.FullDescription()}");
            }

            Memory.DetourMethodAndPersist(original, replacement);
            return(replacement);
        }
Beispiel #9
0
        internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, Harmony instance, MethodInfo postTranspiler)
        {
            if (standin == null)
            {
                throw new ArgumentNullException(nameof(standin));
            }
            if (standin.method == null)
            {
                throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}");
            }

            var transpilers = new List <MethodInfo>();

            if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
            {
                var info = Harmony.GetPatchInfo(original);
                transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray()));
            }
            if (postTranspiler != null)
            {
                transpilers.Add(postTranspiler);
            }

            var empty       = new List <MethodInfo>();
            var replacement = MethodPatcher.CreatePatchedMethod(standin.method, original, instance.Id, empty, empty, transpilers, empty);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create dynamic replacement for {standin.method.FullDescription()}");
            }

            var errorString = Memory.DetourMethod(standin.method, replacement);

            if (errorString != null)
            {
                throw new FormatException($"Method {standin.method.FullDescription()} cannot be patched. Reason: {errorString}");
            }

            PatchTools.RememberObject(standin.method, replacement);
            return(replacement);
        }
Beispiel #10
0
        internal static void UpdateRecompiledMethod(MethodBase original, IntPtr codeStart, PatchInfo patchInfo)
        {
            try
            {
                var sortedPrefixes    = GetSortedPatchMethods(original, patchInfo.prefixes, false);
                var sortedPostfixes   = GetSortedPatchMethods(original, patchInfo.postfixes, false);
                var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers, false);
                var sortedFinalizers  = GetSortedPatchMethods(original, patchInfo.finalizers, false);

                var patcher     = new MethodPatcher(original, null, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers, false);
                var replacement = patcher.CreateReplacement(out var finalInstructions);
                if (replacement is null)
                {
                    throw new MissingMethodException($"Cannot create replacement for {original.FullDescription()}");
                }

                Memory.DetourCompiledMethod(codeStart, replacement);
            }
            catch
            {
            }
        }