public static void UpdateWrapper(MethodBase original, PatchInfo patchInfo) { var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers); if (HarmonyInstance.DEBUG) { //MethodPatcher.SavePatchedMethod(original, sortedPrefixes, sortedPostfixes, sortedTranspilers); } var replacement = MethodPatcher.CreatePatchedMethod(original, sortedPrefixes, sortedPostfixes, sortedTranspilers); if (replacement == null) { throw new MissingMethodException("Cannot create dynamic replacement for " + original); } var originalCodeStart = Memory.GetMethodStart(original); var patchCodeStart = Memory.GetMethodStart(replacement); Memory.WriteJump(originalCodeStart, patchCodeStart); PatchTools.RememberObject(original, replacement); // no gc for new value + release old value to gc }
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); var replacement = MethodPatcher.CreatePatchedMethod(original, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers); 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); } if (UnhollowerSupport.IsGeneratedAssemblyType(original.DeclaringType)) { var il2CppShim = CreateIl2CppShim(replacement, original.DeclaringType); Imports.Hook(UnhollowerSupport.MethodBaseToIntPtr(original), il2CppShim.MethodHandle.GetFunctionPointer()); PatchTools.RememberObject(original, new PotatoTuple { First = replacement, Second = il2CppShim }); } else { PatchTools.RememberObject(original, replacement); // no gc for new value + release old value to gc } return(replacement); }
private static PatchHandle Apply(MethodBase original, MethodInfo postfix) { if (postfix == null) { throw new ArgumentNullException(nameof(postfix)); } var originalCodeStart = Memory.GetMethodStart(original); var replacement = MethodPatcher.CreatePatchedMethod(original, postfix); if (replacement == null) { throw new MissingMethodException($"Cannot create dynamic replacement for {original}"); } var patchCodeStart = Memory.GetMethodStart(replacement); // This part effectively corrupts the original compiled method, so we should prepare to restore the overwritten part later // (It doesn't look like it breaks something, but... better safe than sorry?) var oldBytes = new byte[IntPtr.Size == sizeof(long) ? 12 : 6]; Marshal.Copy((IntPtr)originalCodeStart, oldBytes, 0, oldBytes.Length); Memory.WriteJump(originalCodeStart, patchCodeStart); return(new PatchHandle(patchedMethod: replacement, overwrittenCode: oldBytes)); }
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); var replacement = MethodPatcher.CreatePatchedMethod(original, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers); 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); } if (IsIl2CppType(original.DeclaringType)) { var il2CppShim = CreateIl2CppShim(replacement, original.DeclaringType); Imports.Hook(NET_SDK.SDK.GetClass(original.DeclaringType.FullName).GetMethod(original.Name).Ptr, il2CppShim.MethodHandle.GetFunctionPointer()); PatchTools.RememberObject(original, new Tuple <MethodBase, MethodBase>(replacement, il2CppShim)); } else { PatchTools.RememberObject(original, replacement); // no gc for new value + release old value to gc } return(replacement); }
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); }
public static void UpdateWrapper(MethodBase original, PatchInfo patchInfo) { var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers); var originalCodeStart = Memory.GetMethodStart(original); // If we're overwriting an old patch, restore the original 12 (or 6) bytes of the method beforehand object oldHandle; if (PatchTools.RecallObject(original, out oldHandle)) { var oldPatchHandle = (PatchHandle)oldHandle; Memory.WriteBytes(originalCodeStart, oldPatchHandle.OverwrittenCode); } if (patchInfo.postfixes.Length + patchInfo.prefixes.Length + patchInfo.transpilers.Length == 0) { // No patches, can just leave the original method intact PatchTools.ForgetObject(originalCodeStart); return; } var replacement = MethodPatcher.CreatePatchedMethod(original, sortedPrefixes, sortedPostfixes, sortedTranspilers); if (replacement == null) { throw new MissingMethodException("Cannot create dynamic replacement for " + original); } var patchCodeStart = Memory.GetMethodStart(replacement); // This part effectively corrupts the original compiled method, so we should prepare to restore the overwritten part later // (It doesn't look like it breaks something, but... better safe than sorry?) var oldBytes = new byte[(IntPtr.Size == sizeof(long)) ? 12 : 6]; Marshal.Copy((IntPtr)originalCodeStart, oldBytes, 0, oldBytes.Length); // Store code being overwritten by the jump for the restoration PatchTools.RememberObject(original, new PatchHandle { PatchedMethod = replacement, OverwrittenCode = oldBytes }); Memory.WriteJump(originalCodeStart, patchCodeStart); }
public static void UpdateWrapper(MethodBase original, PatchInfo patchInfo, PatchFlags flags) { var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers).Select(m => TranspilerImpl.From(m)).ToList(); var replacement = MethodPatcher.CreatePatchedMethod(original, sortedPrefixes, sortedPostfixes, sortedTranspilers, flags); if (replacement == null) { throw new MissingMethodException("Cannot create dynamic replacement for " + original); } patchInfo.patchdata.orgaddress = Memory.GetMethodStart(original); patchInfo.patchdata.jmpaddress = Memory.GetMethodStart(replacement); Memory.WriteJump(patchInfo.patchdata.orgaddress, patchInfo.patchdata.jmpaddress, out patchInfo.patchdata.orgbytes, out patchInfo.patchdata.jmpbytes); PatchTools.RememberObject(original, replacement); // no gc for new value + release old value to gc }
/// <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 replacement = MethodPatcher.CreatePatchedMethod(original, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers); 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); }