Example #1
0
        public void TestDetoursRedo()
        {
            lock (TestObject.Lock) {
                // The following use cases are not meant to be usage examples.
                // Please take a look at DetourTest and HookTest instead.

                // Uncomment the following line when you want to run this test isolated and make sure that pins aren't being leaked.
                DetourRuntimeILPlatform runtimeIL = null; // DetourHelper.Runtime as DetourRuntimeILPlatform;

                DetourRuntimeILPlatform.MethodPinInfo[] pinnedPrev = null;
                if (runtimeIL != null)
                {
                    pinnedPrev = runtimeIL.GetPins();
                }

                Step(new NativeDetour(
                         typeof(TestObject).GetMethod("TestStaticMethod"),
                         typeof(DetourRedoTest).GetMethod("TestStaticMethod_A")
                         ));

                Step(new Detour(
                         typeof(TestObject).GetMethod("TestStaticMethod"),
                         typeof(DetourRedoTest).GetMethod("TestStaticMethod_A")
                         ));

                Step(new Hook(
                         typeof(TestObject).GetMethod("TestStaticMethod"),
                         typeof(DetourRedoTest).GetMethod("TestStaticMethod_A")
                         ));

                if (runtimeIL != null)
                {
                    DetourRuntimeILPlatform.MethodPinInfo[] pinned = runtimeIL.GetPins();
                    Assert.Equal(pinnedPrev.Length, pinned.Length);
                    for (int i = 0; i < pinned.Length; i++)
                    {
                        DetourRuntimeILPlatform.MethodPinInfo pinPrev = pinnedPrev[i];
                        DetourRuntimeILPlatform.MethodPinInfo pin     = pinned[i];
                        Assert.Equal(pinPrev.Handle.Value, pin.Handle.Value);
                        Assert.Equal(pinPrev.Count, pin.Count);
                    }
                }

                void Step(IDetour d)
                {
                    using (d) {
                        Assert.True(d.IsValid);
                        Assert.True(d.IsApplied);

                        int staticResult = TestObject.TestStaticMethod(2, 3);
                        Assert.Equal(12, staticResult);

                        d.Undo();
                        Assert.True(d.IsValid);
                        Assert.False(d.IsApplied);

                        staticResult = TestObject.TestStaticMethod(2, 3);
                        Assert.Equal(6, staticResult);

                        d.Apply();
                        Assert.True(d.IsValid);
                        Assert.True(d.IsApplied);

                        staticResult = TestObject.TestStaticMethod(2, 3);
                        Assert.Equal(12, staticResult);
                    }

                    Assert.False(d.IsValid);
                    Assert.False(d.IsApplied);
                }
            }
        }
Example #2
0
 public static int TestMethod_B(Func <TestObject, int, int, int> orig, TestObject self, int a, int b)
 {
     return(orig(self, a, b) + 42);
 }
Example #3
0
        public void TestDetoursExt()
        {
            lock (TestObject.Lock) {
                // The following use cases are not meant to be usage examples.
                // Please take a look at DetourTest and HookTest instead.

#if true
                using (NativeDetour d = new NativeDetour(
                           // .GetNativeStart() to enforce a native detour.
                           typeof(TestObject).GetMethod("TestStaticMethod").Pin().GetNativeStart(),
                           typeof(DetourExtTest).GetMethod("TestStaticMethod_A")
                           )) {
                    int staticResult = d.GenerateTrampoline <Func <int, int, int> >()(2, 3);
                    Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}");
                    Assert.Equal(6, staticResult);

                    staticResult = TestObject.TestStaticMethod(2, 3);
                    Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}");
                    Assert.Equal(12, staticResult);
                }

                // We can't create a backup for this.
                MethodBase dm;
                using (DynamicMethodDefinition dmd = new DynamicMethodDefinition(typeof(TestObject).GetMethod("TestStaticMethod"))) {
                    dm = dmd.Generate();
                }
                using (NativeDetour d = new NativeDetour(
                           dm,
                           typeof(DetourExtTest).GetMethod("TestStaticMethod_A")
                           )) {
                    int staticResult = d.GenerateTrampoline <Func <int, int, int> >()(2, 3);
                    Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}");
                    Assert.Equal(6, staticResult);

                    // FIXME: dm.Invoke can fail with a release build in mono 5.X!
                    // staticResult = (int) dm.Invoke(null, new object[] { 2, 3 });
                    staticResult = ((Func <int, int, int>)dm.CreateDelegate <Func <int, int, int> >())(2, 3);
                    Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}");
                    Assert.Equal(12, staticResult);
                }
#endif

                // This was provided by Chicken Bones (tModLoader).
                // GetEncoding behaves differently on .NET Core and even between .NET Framework versions,
                // which is why this test only applies to Mono, preferably on Linux to verify if flagging
                // regions of code as read-writable and then read-executable works for AOT'd code.
#if false
                using (Hook h = new Hook(
                           typeof(Encoding).GetMethod("GetEncoding", new Type[] { typeof(string) }),
                           new Func <Func <string, Encoding>, string, Encoding>((orig, name) => {
                    if (name == "IBM437")
                    {
                        return(null);
                    }
                    return(orig(name));
                })
                           )) {
                    Assert.Null(Encoding.GetEncoding("IBM437"));
                }
#endif

                // This was provided by a Harmony user.
                // TextWriter's methods (including all overrides) were unable to be hooked on some runtimes.
                // FIXME: .NET 5 introduces similar behavior for macOS and Linux, but RD isn't ready for that. See DetourRuntimeNETPlatform for more info.
#if true
                using (MemoryStream ms = new MemoryStream()) {
                    using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8, 1024, true)) {
                        // In case anyone needs to debug this mess anytime in the future ever again:

                        /*/
                         * MethodBase m = typeof(StreamWriter).GetMethod("Write", new Type[] { typeof(string) });
                         * Console.WriteLine($"meth: 0x{(long) m?.MethodHandle.Value:X16}");
                         * Console.WriteLine($"getf: 0x{(long) m?.MethodHandle.GetFunctionPointer():X16}");
                         * Console.WriteLine($"fptr: 0x{(long) m?.GetLdftnPointer():X16}");
                         * Console.WriteLine($"nats: 0x{(long) m?.GetNativeStart():X16}");
                         * /**/

                        // Debugger.Break();
                        writer.Write("A");

                        using (Hook h = new Hook(
                                   typeof(StreamWriter).GetMethod("Write", new Type[] { typeof(string) }),
                                   new Action <Action <StreamWriter, string>, StreamWriter, string>((orig, self, value) => {
                            orig(self, "-");
                        })
                                   )) {
                            // Debugger.Break();
                            writer.Write("B");
                        }

                        writer.Write("C");
                    }

                    ms.Seek(0, SeekOrigin.Begin);

                    using (StreamReader reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true)) {
                        Assert.Equal("A-C", reader.ReadToEnd());
                    }
                }
#endif

#if NETFRAMEWORK && true
                Assert.Equal("A", new SqlCommand("A").CommandText);

                using (Hook h = new Hook(
                           typeof(SqlCommand).GetConstructor(new Type[] { typeof(string) }),
                           new Action <Action <SqlCommand, string>, SqlCommand, string>((orig, self, value) => {
                    orig(self, "-");
                })
                           )) {
                    Assert.Equal("-", new SqlCommand("B").CommandText);
                }

                Assert.Equal("C", new SqlCommand("C").CommandText);
#endif


                // This was provided by tModLoader.
                // The .NET Framework codepath failed on making the method writable the for a single user.
#if NETFRAMEWORK && true
                try {
                    throw new Exception();
                } catch (Exception e) {
                    Assert.NotEqual("", e.StackTrace.Trim());
                }

                using (Hook h = Type.GetType("Mono.Runtime") != null ?
                                // Mono
                                new Hook(
                           typeof(Exception).GetMethod("GetStackTrace", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance),
                           new Func <Func <Exception, bool, string>, Exception, bool, string>((orig, self, fNeedFileInfo) => {
                    return("");
                })
                           ) :
                                // .NET
                                new Hook(
                           typeof(StackTrace).GetConstructor(new[] { typeof(Exception), typeof(bool) }),
                           new Action <Action <StackTrace, Exception, bool>, StackTrace, Exception, bool>((orig, self, e, fNeedFileInfo) => {
                    orig(self, e, fNeedFileInfo);
                    DynamicData.Set(self, new {
                        frames = new StackFrame[0],
                        m_iNumOfFrames = 0,
                        m_iMethodsToSkip = 0
                    });
                })
                           )) {
                    try {
                        throw new Exception();
                    } catch (Exception e) {
                        Assert.Equal("", e.StackTrace.Trim());
                    }
                }

                try {
                    throw new Exception();
                } catch (Exception e) {
                    Assert.NotEqual("", e.StackTrace.Trim());
                }
#endif
            }
        }
Example #4
0
 public static int TestMethod_A(TestObject self, int a, int b)
 {
     return(42);
 }