/// <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 LoadingExtension()
        {
            Debug.Log("LoadingExtension constructor entry.");

            Debug.Log("Setting ToolMode");
            ToolMode = TrafficManagerMode.None;

            Debug.Log("Init RevertMethods");
            RevertMethods = new RedirectCallsState[8];

            Debug.Log("Setting Despawn to False");
            DespawnEnabled = true;
        }
 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;
     }
 }
 public static void RevertRedirect(MethodInfo from, RedirectCallsState state)
 {
     var fptr1 = from.MethodHandle.GetFunctionPointer();
     RevertJumpTo(fptr1, state);
 }
        public override void OnCreated(ILoading loading)
        {
            SelfDestruct.DestructOldInstances(this);

            base.OnCreated(loading);

            Debug.Log("Setting ToolMode");
            ToolMode = TrafficManagerMode.None;

            Debug.Log("Init RevertMethods");
            RevertMethods = new RedirectCallsState[8];

            Debug.Log("Setting Despawn to False");
            DespawnEnabled = true;

            Debug.Log("Init DetourInited");
            DetourInited = false;

            Debug.Log("Init Custom PathManager");
            CustomPathManager = new CustomPathManager();
        }
Exemple #6
0
 public Detour(MethodInfo originalMethod, MethodInfo customMethod)
 {
     OriginalMethod = originalMethod;
     CustomMethod   = customMethod;
     Redirect       = RedirectionHelper.RedirectCalls(originalMethod, customMethod);
 }
Exemple #7
0
        private void InitDetours()
        {
            // TODO realize detouring with annotations
            if (DetourInited)
            {
                return;
            }

            Log.Info("Init detours");
            bool detourFailed = false;

            try {
                Log.Info("Deploying Harmony patches");
#if DEBUG
                HarmonyInstance.DEBUG = true;
#endif
                Assembly assembly = Assembly.GetExecutingAssembly();

                HarmonyMethodStates.Clear();

                // Harmony attribute-driven patching
                Log.Info($"Performing Harmony attribute-driven patching");
                HarmonyInst = HarmonyInstance.Create(HARMONY_ID);
                HarmonyInst.PatchAll(assembly);

                foreach (Type type in assembly.GetTypes())
                {
                    object[] attributes = type.GetCustomAttributes(typeof(HarmonyPatch), true);
                    if (attributes.Length <= 0)
                    {
                        continue;
                    }

                    foreach (object attr in attributes)
                    {
                        HarmonyPatch       harmonyPatchAttr = (HarmonyPatch)attr;
                        MethodBase         info             = HarmonyUtil.GetOriginalMethod(harmonyPatchAttr.info);
                        IntPtr             ptr   = info.MethodHandle.GetFunctionPointer();
                        RedirectCallsState state = RedirectionHelper.GetState(ptr);
                        HarmonyMethodStates[info] = state;
                    }
                }

                // Harmony manual patching
                Log.Info($"Performing Harmony manual patching");

                foreach (ManualHarmonyPatch manualPatch in ManualHarmonyPatches)
                {
                    Log.InfoFormat(
                        "Manually patching method {0}.{1}. Prefix: {2}, Postfix: {3}, Transpiler: {4}",
                        manualPatch.method.DeclaringType.FullName,
                        manualPatch.method.Name, manualPatch.prefix?.method,
                        manualPatch.postfix?.method, manualPatch.transpiler?.method);

                    HarmonyInst.Patch(
                        manualPatch.method,
                        manualPatch.prefix,
                        manualPatch.postfix,
                        manualPatch.transpiler);

                    IntPtr             ptr   = manualPatch.method.MethodHandle.GetFunctionPointer();
                    RedirectCallsState state = RedirectionHelper.GetState(ptr);
                    HarmonyMethodStates[manualPatch.method] = state;
                }
            } catch (Exception e) {
                Log.Error("Could not deploy Harmony patches");
                Log.Info(e.ToString());
                Log.Info(e.StackTrace);
                detourFailed = true;
            }

            try {
                Log.Info("Deploying attribute-driven detours");
                DetouredMethodStates = AssemblyRedirector.Deploy();
            } catch (Exception e) {
                Log.Error("Could not deploy attribute-driven detours");
                Log.Info(e.ToString());
                Log.Info(e.StackTrace);
                detourFailed = true;
            }

            if (detourFailed)
            {
                Log.Info("Detours failed");
                Singleton <SimulationManager> .instance.m_ThreadingWrapper.QueueMainThread(
                    () => {
                    UIView.library
                    .ShowModal <ExceptionPanel>("ExceptionPanel")
                    .SetMessage(
                        "TM:PE failed to load",
                        "Traffic Manager: President Edition failed to load. You can " +
                        "continue playing but it's NOT recommended. Traffic Manager will " +
                        "not work as expected.",
                        true);
                });
            }
            else
            {
                Log.Info("Detours successful");
            }

            DetourInited = true;
        }
Exemple #8
0
        public override void OnBeforeSimulationFrame()
        {
            base.OnBeforeSimulationFrame();

            if (firstFrame)
            {
                firstFrame = false;
                Log.Info("ThreadingExtension.OnBeforeSimulationFrame: First frame detected. Checking detours.");

                List <string> missingDetours = new List <string>();

                foreach (Detour detour in Detours)
                {
                    if (!RedirectionHelper.IsRedirected(
                            detour.OriginalMethod,
                            detour.CustomMethod))
                    {
                        missingDetours.Add(
                            string.Format(
                                "<Manual> {0}.{1} with {2} parameters ({3})",
                                detour.OriginalMethod.DeclaringType.Name,
                                detour.OriginalMethod.Name,
                                detour.OriginalMethod.GetParameters().Length,
                                detour.OriginalMethod.DeclaringType.AssemblyQualifiedName));
                    }
                }

                foreach (KeyValuePair <MethodBase, RedirectCallsState> entry in HarmonyMethodStates)
                {
                    MethodBase         method   = entry.Key;
                    RedirectCallsState oldState = entry.Value;
                    RedirectCallsState newState =
                        RedirectionHelper.GetState(method.MethodHandle.GetFunctionPointer());

                    if (!oldState.Equals(newState))
                    {
                        missingDetours.Add(
                            string.Format(
                                "<Harmony> {0}.{1} with {2} parameters ({3})",
                                method.DeclaringType.Name,
                                method.Name,
                                method.GetParameters().Length,
                                method.DeclaringType.AssemblyQualifiedName));
                    }
                }

                Log.Info($"ThreadingExtension.OnBeforeSimulationFrame: First frame detected. " +
                         $"Detours checked. Result: {missingDetours.Count} missing detours");

                if (missingDetours.Count > 0)
                {
                    string error =
                        "Traffic Manager: President Edition detected an incompatibility with another " +
                        "mod! You can continue playing but it's NOT recommended. Traffic Manager will " +
                        "not work as expected. See TMPE.log for technical details.";
                    Log.Error(error);
                    string log = "The following methods were overriden by another mod:";

                    foreach (string missingDetour in missingDetours)
                    {
                        log += $"\n\t{missingDetour}";
                    }

                    Log.Info(log);

                    if (GlobalConfig.Instance.Main.ShowCompatibilityCheckErrorMessage)
                    {
                        Prompt.Error("TM:PE Incompatibility Issue", error);
                    }
                }
            }

            if (Options.timedLightsEnabled)
            {
                tlsMan.SimulationStep();
            }
        }
Exemple #9
0
        public static void RevertRedirect(MethodInfo from, RedirectCallsState state)
        {
            var fptr1 = from.MethodHandle.GetFunctionPointer();

            RevertJumpTo(fptr1, state);
        }