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); } }
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); }
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); }
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); }