/// <summary> /// Primitive patching. Inserts a jump to 'target' at 'site'. Works even if both methods' /// callers have already been compiled. /// </summary> /// <param name="site"></param> /// <param name="target"></param> private static RedirectCallsState PatchJumpTo(IntPtr site, IntPtr target) { RedirectCallsState state = new RedirectCallsState(); // R11 is volatile. unsafe { byte* sitePtr = (byte*)site.ToPointer(); state.a = *sitePtr; state.b = *(sitePtr + 1); state.c = *(sitePtr + 10); state.d = *(sitePtr + 11); state.e = *(sitePtr + 12); state.f = *((ulong*) (sitePtr + 2)); *sitePtr = 0x49; // mov r11, target *(sitePtr + 1) = 0xBB; *((ulong*)(sitePtr + 2)) = (ulong)target.ToInt64(); *(sitePtr + 10) = 0x41; // jmp r11 *(sitePtr + 11) = 0xFF; *(sitePtr + 12) = 0xE3; } return state; }
public static void EnableHook() { if (hookEnabled) { return; } try { log = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("Log", new[] { typeof(object) }), typeof(UnityLoggingHook).GetMethod("Log", new[] { typeof(object) }) ); logFormat = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("LogFormat", new[] { typeof(string), typeof(object[]) }), typeof(UnityLoggingHook).GetMethod("LogFormat", new[] { typeof(string), typeof(object[]) }) ); logWarning = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("LogWarning", new[] { typeof(object) }), typeof(UnityLoggingHook).GetMethod("LogWarning", new[] { typeof(object) }) ); logWarningFormat = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("LogWarningFormat", new[] { typeof(string), typeof(object[]) }), typeof(UnityLoggingHook).GetMethod("LogWarningFormat", new[] { typeof(string), typeof(object[]) }) ); logError = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("LogError", new[] { typeof(object) }), typeof(UnityLoggingHook).GetMethod("LogError", new[] { typeof(object) }) ); logErrorFormat = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("LogErrorFormat", new[] { typeof(string), typeof(object[]) }), typeof(UnityLoggingHook).GetMethod("LogErrorFormat", new[] { typeof(string), typeof(object[]) }) ); logException = RedirectionHelper.RedirectCalls ( typeof(UnityEngine.Debug).GetMethod("LogException", new[] { typeof(Exception) }), typeof(UnityLoggingHook).GetMethod("LogException", new[] { typeof(Exception) }) ); } catch (Exception ex) { global::ModTools.Log.Error("Failed to hook Unity's debug logging, reason: " + ex.Message); } hookEnabled = true; global::ModTools.Log.Warning("Unity logging subsystem hooked by ModTools"); }
public static void Bootstrap() { if (thisGameObject == null) { thisGameObject = new GameObject(); thisGameObject.name = "ImprovedWorkshopIntegration"; thisGameObject.AddComponent<ImprovedWorkshopIntegration>(); thisGameObject.transform.parent = ModTools.Instance.gameObject.transform; } if (bootstrapped) { return; } var go = GameObject.Find("(Library) WorkshopModUploadPanel"); if (go == null) { return; } workshopModUploadPanel = go.GetComponent<WorkshopModUploadPanel>(); if (workshopModUploadPanel == null) { return; } UITabContainer categoryContainer = GameObject.Find("CategoryContainer").GetComponent<UITabContainer>(); var modsList = categoryContainer.Find("Mods").Find("Content"); if (modsList == null) { return; } m_StagingPath = Util.FindField(workshopModUploadPanel, "m_StagingPath"); m_PreviewPath = Util.FindField(workshopModUploadPanel, "m_PreviewPath"); m_ContentPath = Util.FindField(workshopModUploadPanel, "m_ContentPath"); m_CurrentHandle = Util.FindField(workshopModUploadPanel, "m_CurrentHandle"); m_ShareButton = Util.FindField(workshopModUploadPanel, "m_ShareButton"); m_TargetFolder = Util.FindField(workshopModUploadPanel, "m_TargetFolder"); m_ShareButton = Util.FindField(workshopModUploadPanel, "m_ShareButton"); m_Title = Util.FindField(workshopModUploadPanel, "m_Title"); m_Desc = Util.FindField(workshopModUploadPanel, "m_Desc"); m_ChangeNote = Util.FindField(workshopModUploadPanel, "m_ChangeNote"); m_DefaultModPreviewTexture = Util.FindField(workshopModUploadPanel, "m_DefaultModPreviewTexture"); reloadPreviewImage = typeof(WorkshopModUploadPanel).GetMethod("ReloadPreviewImage", BindingFlags.Instance | BindingFlags.NonPublic); startWatchingPath = typeof(WorkshopModUploadPanel).GetMethod("StartWatchingPath", BindingFlags.Instance | BindingFlags.NonPublic); revertState = RedirectionHelper.RedirectCalls ( typeof(WorkshopModUploadPanel).GetMethod("SetAssetInternal", BindingFlags.Instance | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("SetAssetInternal", BindingFlags.Instance | BindingFlags.NonPublic) ); bootstrapped = true; }
public static void Bootstrap() { if (thisGameObject == null) { thisGameObject = new GameObject(); thisGameObject.name = "ImprovedWorkshopIntegration"; thisGameObject.AddComponent<ImprovedWorkshopIntegration>(); thisGameObject.transform.parent = ModTools.Instance.gameObject.transform; } improvedModsPanelExists = CheckForImprovedModsPanel(); if (!improvedModsPanelExists) { InitializeModSortDropDown(); } if (bootstrapped) { return; } var go = GameObject.Find("(Library) WorkshopModUploadPanel"); if (go == null) { return; } workshopModUploadPanel = go.GetComponent<WorkshopModUploadPanel>(); if (workshopModUploadPanel == null) { return; } var modsList = GameObject.Find("ModsList"); if (modsList == null) { return; } m_StagingPath = Util.FindField(workshopModUploadPanel, "m_StagingPath"); m_PreviewPath = Util.FindField(workshopModUploadPanel, "m_PreviewPath"); m_ContentPath = Util.FindField(workshopModUploadPanel, "m_ContentPath"); m_CurrentHandle = Util.FindField(workshopModUploadPanel, "m_CurrentHandle"); m_ShareButton = Util.FindField(workshopModUploadPanel, "m_ShareButton"); m_TargetFolder = Util.FindField(workshopModUploadPanel, "m_TargetFolder"); m_ShareButton = Util.FindField(workshopModUploadPanel, "m_ShareButton"); m_Title = Util.FindField(workshopModUploadPanel, "m_Title"); m_Desc = Util.FindField(workshopModUploadPanel, "m_Desc"); m_ChangeNote = Util.FindField(workshopModUploadPanel, "m_ChangeNote"); m_DefaultModPreviewTexture = Util.FindField(workshopModUploadPanel, "m_DefaultModPreviewTexture"); reloadPreviewImage = typeof(WorkshopModUploadPanel).GetMethod("ReloadPreviewImage", BindingFlags.Instance | BindingFlags.NonPublic); startWatchingPath = typeof(WorkshopModUploadPanel).GetMethod("StartWatchingPath", BindingFlags.Instance | BindingFlags.NonPublic); revertState = RedirectionHelper.RedirectCalls ( typeof(WorkshopModUploadPanel).GetMethod("SetAssetInternal", BindingFlags.Instance | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("SetAssetInternal", BindingFlags.Instance | BindingFlags.NonPublic) ); if (!improvedModsPanelExists) { modsPanelBootstrapped = true; revertState2 = RedirectionHelper.RedirectCalls ( typeof(PackageEntry).GetMethod("FormatPackageName", BindingFlags.Static | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("FormatPackageName", BindingFlags.Static | BindingFlags.NonPublic) ); revertState3 = RedirectionHelper.RedirectCalls ( typeof(CustomContentPanel).GetMethod("RefreshPlugins", BindingFlags.Instance | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("RefreshPlugins", BindingFlags.Static | BindingFlags.Public) ); } else { modsPanelBootstrapped = false; } bootstrapped = true; }
public static void Bootstrap() { if (thisGameObject == null) { thisGameObject = new GameObject(); thisGameObject.name = "ImprovedWorkshopIntegration"; thisGameObject.AddComponent <ImprovedWorkshopIntegration>(); thisGameObject.transform.parent = ModTools.Instance.gameObject.transform; } improvedModsPanelExists = CheckForImprovedModsPanel(); if (!improvedModsPanelExists) { InitializeModSortDropDown(); } if (bootstrapped) { return; } var go = GameObject.Find("(Library) WorkshopModUploadPanel"); if (go == null) { return; } workshopModUploadPanel = go.GetComponent <WorkshopModUploadPanel>(); if (workshopModUploadPanel == null) { return; } var modsList = GameObject.Find("ModsList"); if (modsList == null) { return; } m_StagingPath = Util.FindField(workshopModUploadPanel, "m_StagingPath"); m_PreviewPath = Util.FindField(workshopModUploadPanel, "m_PreviewPath"); m_ContentPath = Util.FindField(workshopModUploadPanel, "m_ContentPath"); m_CurrentHandle = Util.FindField(workshopModUploadPanel, "m_CurrentHandle"); m_ShareButton = Util.FindField(workshopModUploadPanel, "m_ShareButton"); m_TargetFolder = Util.FindField(workshopModUploadPanel, "m_TargetFolder"); m_ShareButton = Util.FindField(workshopModUploadPanel, "m_ShareButton"); m_Title = Util.FindField(workshopModUploadPanel, "m_Title"); m_Desc = Util.FindField(workshopModUploadPanel, "m_Desc"); m_ChangeNote = Util.FindField(workshopModUploadPanel, "m_ChangeNote"); m_DefaultModPreviewTexture = Util.FindField(workshopModUploadPanel, "m_DefaultModPreviewTexture"); reloadPreviewImage = typeof(WorkshopModUploadPanel).GetMethod("ReloadPreviewImage", BindingFlags.Instance | BindingFlags.NonPublic); startWatchingPath = typeof(WorkshopModUploadPanel).GetMethod("StartWatchingPath", BindingFlags.Instance | BindingFlags.NonPublic); revertState = RedirectionHelper.RedirectCalls ( typeof(WorkshopModUploadPanel).GetMethod("SetAssetInternal", BindingFlags.Instance | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("SetAssetInternal", BindingFlags.Instance | BindingFlags.NonPublic) ); if (!improvedModsPanelExists) { modsPanelBootstrapped = true; revertState2 = RedirectionHelper.RedirectCalls ( typeof(PackageEntry).GetMethod("FormatPackageName", BindingFlags.Static | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("FormatPackageName", BindingFlags.Static | BindingFlags.NonPublic) ); revertState3 = RedirectionHelper.RedirectCalls ( typeof(CustomContentPanel).GetMethod("RefreshPlugins", BindingFlags.Instance | BindingFlags.NonPublic), typeof(ImprovedWorkshopIntegration).GetMethod("RefreshPlugins", BindingFlags.Static | BindingFlags.Public) ); } else { modsPanelBootstrapped = false; } bootstrapped = true; }
public static void RevertRedirect(MethodInfo from, RedirectCallsState state) { var fptr1 = from.MethodHandle.GetFunctionPointer(); RevertJumpTo(fptr1, state); }
private static void RevertJumpTo(IntPtr site, RedirectCallsState state) { unsafe { byte* sitePtr = (byte*)site.ToPointer(); *sitePtr = state.a; // mov r11, target *(sitePtr + 1) = state.b; *((ulong*)(sitePtr + 2)) = state.f; *(sitePtr + 10) = state.c; // jmp r11 *(sitePtr + 11) = state.d; *(sitePtr + 12) = state.e; } }