예제 #1
0
        /// <summary>Gets Harmony version for all active Harmony instances</summary>
        /// <param name="currentVersion">[out] The current Harmony version</param>
        /// <returns>A dictionary containing assembly versions keyed by Harmony IDs</returns>
        ///
        public static Dictionary <string, Version> VersionInfo(out Version currentVersion)
        {
            currentVersion = typeof(HarmonyInstance).Assembly.GetName().Version;
            var assemblies = new Dictionary <string, Assembly>();

            GetAllPatchedMethods().Do(method =>
            {
                var info = HarmonySharedState.GetPatchInfo(method);
                info.prefixes.Do(fix => assemblies[fix.owner]    = fix.patch.DeclaringType.Assembly);
                info.postfixes.Do(fix => assemblies[fix.owner]   = fix.patch.DeclaringType.Assembly);
                info.transpilers.Do(fix => assemblies[fix.owner] = fix.patch.DeclaringType.Assembly);
            });

            var result = new Dictionary <string, Version>();

            assemblies.Do(info =>
            {
                var assemblyName = info.Value.GetReferencedAssemblies().FirstOrDefault(a => a.FullName.StartsWith("0Harmony, Version"));
                if (assemblyName != null)
                {
                    result[info.Key] = assemblyName.Version;
                }
            });
            return(result);
        }
예제 #2
0
        /// <summary>
        /// 执行Patch
        /// </summary>
        /// <returns></returns>
        public PatchInfoData Patch(PatchFlags flags)
        {
            PatchInfo patchInfo = null;

            lock (locker)
            {
#if RECORD_PATCH_STATE
                patchInfo = HarmonySharedState.GetPatchInfo(original);
                if (patchInfo == null)
                {
                    patchInfo = new PatchInfo();
                }
#endif
                patchInfo = new PatchInfo();

                PatchFunctions.AddPrefix(patchInfo, instance.id, prefix);
                PatchFunctions.AddPostfix(patchInfo, instance.id, postfix);
                PatchFunctions.AddTranspiler(patchInfo, instance.id, transpiler);
                PatchFunctions.UpdateWrapper(original, patchInfo, flags);
#if RECORD_PATCH_STATE
                HarmonySharedState.UpdatePatchInfo(original, patchInfo);
#endif
            }

            return(patchInfo.patchdata);
        }
예제 #3
0
        /// <summary>Unpatches patches of a given type and/or Harmony ID</summary>
        /// <param name="type">The patch type</param>
        /// <param name="harmonyID">Harmony ID or (*) for any</param>
        ///
        public void Unpatch(HarmonyPatchType type, string harmonyID)
        {
            lock (locker)
            {
                foreach (var original in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(original);
                    if (patchInfo == null)
                    {
                        patchInfo = new PatchInfo();
                    }

                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix)
                    {
                        PatchFunctions.RemovePrefix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix)
                    {
                        PatchFunctions.RemovePostfix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler)
                    {
                        PatchFunctions.RemoveTranspiler(patchInfo, harmonyID);
                    }
                    PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id);

                    HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                }
            }
        }
예제 #4
0
        public void Unpatch(HarmonyPatchType type, string harmonyID)
        {
            lock (locker)
            {
                foreach (var original in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(original);
                    if (patchInfo == null)
                    {
                        patchInfo = new PatchInfo();
                    }

                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix)
                    {
                        PatchFunctions.RemovePrefix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix)
                    {
                        PatchFunctions.RemovePostfix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler)
                    {
                        PatchFunctions.RemoveTranspiler(patchInfo, harmonyID);
                    }

                    PatchHandler.Get(original).Apply();
                }
            }
        }
예제 #5
0
        public void Unpatch(HarmonyPatchType type, string harmonyID)
        {
            var obj = locker;

            lock (obj)
            {
                foreach (var methodBase in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(methodBase) ?? new PatchInfo();
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix)
                    {
                        PatchFunctions.RemovePrefix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix)
                    {
                        PatchFunctions.RemovePostfix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler)
                    {
                        PatchFunctions.RemoveTranspiler(patchInfo, harmonyID);
                    }
                    PatchFunctions.UpdateWrapper(methodBase, patchInfo, instance.Id);
                    HarmonySharedState.UpdatePatchInfo(methodBase, patchInfo);
                }
            }
        }
예제 #6
0
        public void Patch()
        {
            var obj = locker;

            lock (obj)
            {
                foreach (var methodBase in originals)
                {
                    if (methodBase == null)
                    {
                        throw new NullReferenceException("original");
                    }
                    if (RunMethod <HarmonyPrepare, bool>(true, methodBase))
                    {
                        var patchInfo = HarmonySharedState.GetPatchInfo(methodBase) ?? new PatchInfo();
                        PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                        PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                        PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);
                        PatchFunctions.UpdateWrapper(methodBase, patchInfo, instance.Id);
                        HarmonySharedState.UpdatePatchInfo(methodBase, patchInfo);
                        RunMethod <HarmonyCleanup>(methodBase);
                    }
                }
            }
        }
예제 #7
0
 public static IEnumerable <MethodBase> AllPatchedMethods()
 {
     lock (locker)
     {
         return(HarmonySharedState.GetPatchedMethods());
     }
 }
예제 #8
0
        public List <DynamicMethod> Patch()
        {
            lock (locker)
            {
                var dynamicMethods = new List <DynamicMethod>();
                foreach (var original in originals)
                {
                    if (original == null)
                    {
                        throw new NullReferenceException("original");
                    }

                    var individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, original);
                    if (individualPrepareResult)
                    {
                        var patchInfo = HarmonySharedState.GetPatchInfo(original);
                        if (patchInfo == null)
                        {
                            patchInfo = new PatchInfo();
                        }

                        PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                        PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                        PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);
                        dynamicMethods.Add(PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id));

                        HarmonySharedState.UpdatePatchInfo(original, patchInfo);

                        RunMethod <HarmonyCleanup>(original);
                    }
                }
                return(dynamicMethods);
            }
        }
        private static IEnumerable <CodeInstruction> UnhollowerTranspiler(MethodBase method, IEnumerable <CodeInstruction> instructionsIn)
        {
            List <CodeInstruction> instructions = new List <CodeInstruction>(instructionsIn);
            PatchInfo patchInfo        = HarmonySharedState.GetPatchInfo(method);
            IntPtr    copiedMethodInfo = patchInfo.copiedMethodInfoPointer;

            bool found        = false;
            int  replaceIdx   = 0;
            int  replaceCount = 0;

            for (int i = instructions.Count - 2; i >= 0; --i)
            {
                if (instructions[i].opcode != OpCodes.Ldsfld)
                {
                    continue;
                }

                found = true;
                CodeInstruction next = instructions[i + 1];
                if (next.opcode == OpCodes.Call && ((MethodInfo)next.operand).Name == "il2cpp_object_get_virtual_method")
                {
                    // Virtual method: Replace the sequence
                    // - ldarg.0
                    // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::Il2CppObjectBaseToPtr(class [UnhollowerBaseLib] UnhollowerBaseLib.Il2CppObjectBase)
                    // - ldsfld native int SomeClass::NativeMethodInfoPtr_Etc
                    // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::il2cpp_object_get_virtual_method(native int, native int)

                    replaceIdx   = i - 2;
                    replaceCount = 4;
                }
                else
                {
                    // Everything else: Just replace the static load
                    replaceIdx   = i;
                    replaceCount = 1;
                }
                break;
            }

            if (!found)
            {
                MelonLogger.Error("Harmony transpiler could not rewrite Unhollower method. Expect a stack overflow.");
                return(instructions);
            }

            CodeInstruction[] replacement =
            {
                new CodeInstruction(OpCodes.Ldc_I8, copiedMethodInfo.ToInt64()),
                new CodeInstruction(OpCodes.Conv_I)
            };

            instructions.RemoveRange(replaceIdx, replaceCount);
            instructions.InsertRange(replaceIdx, replacement);

            return(instructions);
        }
예제 #10
0
        public static Patches IsPatched(MethodBase method)
        {
            var patchInfo = HarmonySharedState.GetPatchInfo(method);

            if (patchInfo == null)
            {
                return(null);
            }
            return(new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers));
        }
예제 #11
0
        public Dictionary <string, Version> VersionInfo(out Version currentVersion)
        {
            currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
            var            assemblies = new Dictionary <string, Assembly>();
            Action <Patch> a1         = null;
            Action <Patch> a2         = null;
            Action <Patch> a3         = null;

            GetPatchedMethods().Do(delegate(MethodBase method)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(method);
                IEnumerable <Patch> prefixes = patchInfo.prefixes;
                Action <Patch> action;
                if ((action = a1) == null)
                {
                    action = (a1 = delegate(Patch fix)
                    {
                        assemblies[fix.owner] = fix.patch.DeclaringType.Assembly;
                    });
                }
                prefixes.Do(action);
                IEnumerable <Patch> postfixes = patchInfo.postfixes;
                Action <Patch> action2;
                if ((action2 = a2) == null)
                {
                    action2 = (a2 = delegate(Patch fix)
                    {
                        assemblies[fix.owner] = fix.patch.DeclaringType.Assembly;
                    });
                }
                postfixes.Do(action2);
                IEnumerable <Patch> transpilers = patchInfo.transpilers;
                Action <Patch> action3;
                if ((action3 = a3) == null)
                {
                    action3 = (a3 = delegate(Patch fix)
                    {
                        assemblies[fix.owner] = fix.patch.DeclaringType.Assembly;
                    });
                }
                transpilers.Do(action3);
            });
            var result = new Dictionary <string, Version>();

            assemblies.Do(delegate(KeyValuePair <string, Assembly> info)
            {
                var assemblyName = info.Value.GetReferencedAssemblies()
                                   .FirstOrDefault(a => a.FullName.StartsWith("0Harmony, Version"));
                if (assemblyName != null)
                {
                    result[info.Key] = assemblyName.Version;
                }
            });
            return(result);
        }
예제 #12
0
        public static IEnumerable <MethodBase> AllPatchedMethods()
        {
            var obj = locker;
            IEnumerable <MethodBase> patchedMethods;

            lock (obj)
            {
                patchedMethods = HarmonySharedState.GetPatchedMethods();
            }

            return(patchedMethods);
        }
        public 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);
            bool isIl2Cpp          = UnhollowerSupport.IsGeneratedAssemblyType(original.DeclaringType);

            if (isIl2Cpp)
            {
                if (sortedTranspilers.Count > 0)
                {
                    throw new NotSupportedException("IL2CPP patches cannot use transpilers (got " + sortedTranspilers.Count + ")");
                }

                if (patchInfo.copiedMethodInfoPointer == IntPtr.Zero)
                {
                    IntPtr origMethodPtr = UnhollowerSupport.MethodBaseToIl2CppMethodInfoPointer(original);
                    patchInfo.copiedMethodInfoPointer = CopyMethodInfoStruct(origMethodPtr);
                    HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                }

                sortedTranspilers.Add(AccessTools.DeclaredMethod(typeof(PatchFunctions), "UnhollowerTranspiler"));
            }

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

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

            if (isIl2Cpp)
            {
                DynamicMethod il2CppShim = CreateIl2CppShim(replacement, original);
                InstallIl2CppPatch(patchInfo, il2CppShim);
                PatchTools.RememberObject(original, new PotatoTuple {
                    First = replacement, Second = il2CppShim
                });
            }
            else
            {
                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);
        }
예제 #14
0
        public void Unpatch(MethodInfo patch)
        {
            var obj = locker;

            lock (obj)
            {
                foreach (var methodBase in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(methodBase) ?? new PatchInfo();
                    PatchFunctions.RemovePatch(patchInfo, patch);
                    PatchFunctions.UpdateWrapper(methodBase, patchInfo, instance.Id);
                    HarmonySharedState.UpdatePatchInfo(methodBase, patchInfo);
                }
            }
        }
예제 #15
0
 public void Patch()
 {
     lock (locker)
     {
         var patchInfo = HarmonySharedState.GetPatchInfo(original);
         if (patchInfo == null)
         {
             patchInfo = new PatchInfo();
         }
         PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
         PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
         PatchFunctions.AddInfix(patchInfo, instance.Id, infix);
         PatchFunctions.UpdateWrapper(original, patchInfo);
         HarmonySharedState.UpdatePatchInfo(original, patchInfo);
     }
 }
예제 #16
0
        public void Patch()
        {
            lock (locker)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(original);
                if (patchInfo == null)
                {
                    patchInfo = new PatchInfo();
                }

                PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);

                PatchHandler.Get(original).Apply();
            }
        }
예제 #17
0
        public void Unpatch(MethodInfo patch)
        {
            lock (locker)
            {
                foreach (var original in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(original);
                    if (patchInfo == null)
                    {
                        patchInfo = new PatchInfo();
                    }

                    PatchFunctions.RemovePatch(patchInfo, patch);
                    PatchHandler.Get(original).Apply();
                }
            }
        }
예제 #18
0
        public List <DynamicMethod> Patch()
        {
            lock (locker)
            {
                var dynamicMethods = new List <DynamicMethod>();
                foreach (var original in originals)
                {
                    if (original == null)
                    {
                        throw new NullReferenceException("original");
                    }

                    if ((original.DeclaringType.Assembly.GetCustomAttributes(typeof(HarmonyShield), false).Count() > 0) ||
                        (original.DeclaringType.GetCustomAttributes(typeof(HarmonyShield), false).Count() > 0) ||
                        (original.GetCustomAttributes(typeof(HarmonyShield), false).Count() > 0))
                    {
                        continue;
                    }

                    if (MelonDebug.IsEnabled() && UnhollowerSupport.IsGeneratedAssemblyType(original.DeclaringType))
                    {
                        WarnIfTargetMethodInlined(original);
                    }

                    var individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, original);
                    if (individualPrepareResult)
                    {
                        var patchInfo = HarmonySharedState.GetPatchInfo(original);
                        if (patchInfo == null)
                        {
                            patchInfo = new PatchInfo();
                        }

                        PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                        PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                        PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);
                        dynamicMethods.Add(PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id));

                        HarmonySharedState.UpdatePatchInfo(original, patchInfo);

                        RunMethod <HarmonyCleanup>(original);
                    }
                }
                return(dynamicMethods);
            }
        }
예제 #19
0
        public void Restore()
        {
            lock (locker)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(original);
                if (patchInfo == null)
                {
                    return;
                }

                PatchFunctions.RemovePrefix(patchInfo, prefix);
                PatchFunctions.RemovePostfix(patchInfo, postfix);
                PatchFunctions.RemoveTranspiler(patchInfo, transpiler);
                PatchFunctions.UpdateWrapper(original, patchInfo);

                HarmonySharedState.UpdatePatchInfo(original, patchInfo);
            }
        }
예제 #20
0
        public void Unpatch(MethodInfo patch)
        {
            lock (locker)
            {
                foreach (var original in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(original);
                    if (patchInfo == null)
                    {
                        patchInfo = new PatchInfo();
                    }

                    PatchFunctions.RemovePatch(patchInfo, patch);
                    PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id);

                    HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                }
            }
        }
예제 #21
0
        public static Patches GetPatchInfo(MethodBase method)
        {
            var     obj = locker;
            Patches result;

            lock (obj)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(method);
                if (patchInfo == null)
                {
                    result = null;
                }
                else
                {
                    result = new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers, patchInfo.finalizers);
                }
            }

            return(result);
        }
        public void Apply()
        {
            PatchMethod[] ToPatchMethod(Patch[] patches)
            {
                return(patches.Select(p => new PatchMethod
                {
                    after = p.after,
                    before = p.before,
                    method = p.patch,
                    priority = p.priority,
                    owner = p.owner,
                }).ToArray());
            }

            var info  = HarmonySharedState.GetPatchInfo(mb);
            var state = new PatchInfoWrapper
            {
                prefixes    = ToPatchMethod(info.prefixes),
                postfixes   = ToPatchMethod(info.postfixes),
                transpilers = ToPatchMethod(info.transpilers),
                finalizers  = new PatchMethod[0]
            };

            var add = new PatchInfoWrapper {
                finalizers = new PatchMethod[0]
            };
            var remove = new PatchInfoWrapper {
                finalizers = new PatchMethod[0]
            };

            Diff(previousState.prefixes, state.prefixes, out add.prefixes, out remove.prefixes);
            Diff(previousState.postfixes, state.postfixes, out add.postfixes, out remove.postfixes);
            Diff(previousState.transpilers, state.transpilers, out add.transpilers, out remove.transpilers);

            previousState = state;

            HarmonyInterop.ApplyPatch(mb, add, remove);
        }
예제 #23
0
 /// <summary>Gets a patched methods</summary>
 /// <returns>An enumeration of original methods</returns>
 ///
 public IEnumerable <MethodBase> GetPatchedMethods()
 {
     return(HarmonySharedState.GetPatchedMethods());
 }
예제 #24
0
 /// <summary>Gets the methods this instance has patched</summary>
 /// <returns>An enumeration of original methods</returns>
 ///
 public IEnumerable <MethodBase> GetPatchedMethods()
 {
     return(HarmonySharedState.GetPatchedMethods()
            .Where(original => GetPatchInfo(original).Owners.Contains(Id)));
 }