Beispiel #1
0
 internal void DetourILDetourTarget(bool force = false)
 {
     ILProxyDetour?.Dispose();
     ILProxyDetour = null;
     if (!force && ILList.Count == 0)
     {
         return;
     }
     try {
         ILProxyDetour = new NativeDetour(ILCopy, DMD.Generate());
     } catch (Exception e) {
         StringBuilder builder = new StringBuilder();
         if (DMD.Definition?.Body?.Instructions != null)
         {
             builder.AppendLine("IL hook failed for:");
             foreach (Instruction i in DMD.Definition.Body.Instructions)
             {
                 builder.AppendLine(i?.ToString() ?? "NULL!");
             }
         }
         else
         {
             builder.AppendLine("IL hook failed, no instructions found");
         }
         throw new InvalidProgramException(builder.ToString(), e);
     }
 }
Beispiel #2
0
        private void TestNativeDetoursUnix(dt_rand d_not_rand, IntPtr ptr_not_rand)
        {
            DidNothing = true;
            libc_rand();
            Assert.True(DidNothing);

            DidNothing = true;
            Assert.Equal(-1, d_not_rand());
            Assert.False(DidNothing);

            using (new NativeDetour(
                       typeof(NativeDetourTest).GetMethod("libc_rand"),
                       typeof(NativeDetourTest).GetMethod("not_rand")
                       )) {
                DidNothing = true;
                Assert.Equal(-1, libc_rand());
                Assert.False(DidNothing);
            }

            DidNothing = true;
            libc_rand();
            Assert.True(DidNothing);

            /* dl's dlopen doesn't follow ld, meaning that we need to...
             * - use libc.so.6 on Linux and hope that everyone is using glibc.
             * - use /usr/lib/libc.dylib on macOS because macOS is macOS.
             * If libc cannot be dlopened, skip the native -> managed detour test.
             * - ade
             */
            if (!(PlatformHelper.Is(Platform.Linux) && DynDll.TryOpenLibrary("libc.so.6", out IntPtr libc)) &&
                !(PlatformHelper.Is(Platform.MacOS) && DynDll.TryOpenLibrary("/usr/lib/libc.dylib", out libc)) &&
                !DynDll.TryOpenLibrary($"libc.{PlatformHelper.LibrarySuffix}", out libc))
            {
                return;
            }

            NativeDetour d = new NativeDetour(
                libc.GetFunction("rand"),
                ptr_not_rand
                );

            DidNothing = true;
            Assert.Equal(-1, libc_rand());
            Assert.False(DidNothing);

            d.Dispose();

            DidNothing = true;
            libc_rand();
            Assert.True(DidNothing);
        }
Beispiel #3
0
        private void TestNativeDetoursWindows(dt_rand d_not_rand, IntPtr ptr_not_rand)
        {
            if (!DynDll.TryOpenLibrary($"msvcrt.{PlatformHelper.LibrarySuffix}", out IntPtr msvcrt))
            {
                Console.WriteLine("NativeDetourTest skipped - msvcrt not found!");
                return;
            }

            if (!msvcrt.TryGetFunction("rand", out IntPtr ptr_msvcrt_rand))
            {
                Console.WriteLine("NativeDetourTest skipped - rand not found in msvcrt!");
                return;
            }

            DidNothing = true;
            msvcrt_rand();
            Assert.True(DidNothing);

            DidNothing = true;
            Assert.Equal(-1, d_not_rand());
            Assert.False(DidNothing);

            using (new NativeDetour(
                       typeof(NativeDetourTest).GetMethod("msvcrt_rand"),
                       typeof(NativeDetourTest).GetMethod("not_rand")
                       )) {
                DidNothing = true;
                Assert.Equal(-1, msvcrt_rand());
                Assert.False(DidNothing);
            }

            DidNothing = true;
            msvcrt_rand();
            Assert.True(DidNothing);

            NativeDetour d = new NativeDetour(
                ptr_msvcrt_rand,
                ptr_not_rand
                );

            DidNothing = true;
            Assert.Equal(-1, msvcrt_rand());
            Assert.False(DidNothing);

            d.Dispose();

            DidNothing = true;
            msvcrt_rand();
            Assert.True(DidNothing);
        }
Beispiel #4
0
        public override void Apply()
        {
            // The process to patch native methods is as follows:
            // 1. Create a managed proxy method that calls NativeDetour's trampoline (we need to cache it
            //    because we don't know the trampoline method when generating the DMD).
            // 2. Pass the proxy to the normal Harmony manipulator to apply prefixes, postfixes, transpilers, etc.
            // 3. NativeDetour the method to the managed proxy
            // 4. Cache the NativeDetour's trampoline (technically we wouldn't need to, this is just a workaround
            //    for MonoMod's API.

            if (IsRunningOnDotNetCore)
            {
                Logger.Log(Logger.LogChannel.Warn, () => $"Patch target {Original.GetID()} is marked as extern. " +
                           "Extern methods may not be patched because of inlining behaviour of coreclr (refer to https://github.com/dotnet/coreclr/pull/8263)." +
                           "If you need to patch externs, consider using pure NativeDetour instead.");
            }


            var prevDmd = _dmd;

            _nativeDetour?.Dispose();

            _dmd = GenerateManagedOriginal();
            var ctx = new ILContext(_dmd.Definition);

            HarmonyManipulator.Manipulate(Original, Original.GetPatchInfo(), ctx);

            var target = _dmd.Generate();

            _nativeDetour = new NativeDetour(Original, target, new NativeDetourConfig
            {
                ManualApply = true
            });

            lock (TrampolineCache)
            {
                if (prevDmd != null)
                {
                    TrampolineCache.Remove(prevDmd.GetHashCode());
                }

                TrampolineCache[_dmd.GetHashCode()] = CreateDelegate(_trampolineDelegateType, _nativeDetour.GenerateTrampoline(_invokeTrampolineMethod));
            }

            _nativeDetour.Apply();
        }
        /// <inheritdoc />
        public override MethodBase DetourTo(MethodBase replacement)
        {
            nativeDetour?.Dispose();

            nativeDetour = new NativeDetour(Original, replacement, new NativeDetourConfig {
                ManualApply = true
            });

            lock (TrampolineCache)
            {
                if (currentOriginal >= 0)
                {
                    TrampolineCache.Remove(currentOriginal);
                }
                currentOriginal = newOriginal;
                TrampolineCache[currentOriginal] = CreateDelegate(trampolineDelegateType,
                                                                  nativeDetour.GenerateTrampoline(invokeTrampolineMethod));
            }

            nativeDetour.Apply();
            return(replacement);
        }
        private void TestNativeDetoursWindows(dt_rand d_not_rand, IntPtr ptr_not_rand)
        {
            DidNothing = true;
            msvcrt_rand();
            Assert.True(DidNothing);

            DidNothing = true;
            Assert.Equal(-1, d_not_rand());
            Assert.False(DidNothing);

            using (new NativeDetour(
                       typeof(NativeDetourTest).GetMethod("msvcrt_rand"),
                       typeof(NativeDetourTest).GetMethod("not_rand")
                       )) {
                DidNothing = true;
                Assert.Equal(-1, msvcrt_rand());
                Assert.False(DidNothing);
            }

            DidNothing = true;
            msvcrt_rand();
            Assert.True(DidNothing);

            NativeDetour d = new NativeDetour(
                DynDll.OpenLibrary($"msvcrt.{PlatformHelper.LibrarySuffix}").GetFunction("rand"),
                ptr_not_rand
                );

            DidNothing = true;
            Assert.Equal(-1, msvcrt_rand());
            Assert.False(DidNothing);

            d.Dispose();

            DidNothing = true;
            msvcrt_rand();
            Assert.True(DidNothing);
        }