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); } } }
public static int TestMethod_B(Func <TestObject, int, int, int> orig, TestObject self, int a, int b) { return(orig(self, a, b) + 42); }
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 } }
public static int TestMethod_A(TestObject self, int a, int b) { return(42); }