FastNativeDetour.cs 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. using System;
  2. using System.Reflection;
  3. using System.Runtime.InteropServices;
  4. using MonoMod.RuntimeDetour;
  5. using MonoMod.Utils;
  6. namespace BepInEx.IL2CPP.Hook
  7. {
  8. public class FastNativeDetour : IDetour
  9. {
  10. protected byte[] BackupBytes { get; set; }
  11. public bool IsValid { get; protected set; } = true;
  12. public bool IsApplied { get; protected set; }
  13. public IntPtr OriginalFuncPtr { get; protected set; }
  14. public IntPtr DetourFuncPtr { get; protected set; }
  15. public IntPtr TrampolinePtr { get; protected set; } = IntPtr.Zero;
  16. public int TrampolineSize { get; protected set; } = 0;
  17. protected MethodInfo TrampolineMethod { get; set; }
  18. public FastNativeDetour(IntPtr originalFuncPtr, IntPtr detourFuncPtr)
  19. {
  20. OriginalFuncPtr = originalFuncPtr;
  21. DetourFuncPtr = detourFuncPtr;
  22. // TODO: This may not be safe during undo if the method is smaller than 20 bytes
  23. BackupBytes = new byte[20];
  24. Marshal.Copy(originalFuncPtr, BackupBytes, 0, 20);
  25. }
  26. public void Apply()
  27. {
  28. TrampolinePtr = TrampolineGenerator.Generate(OriginalFuncPtr, DetourFuncPtr, out int trampolineLength);
  29. TrampolineSize = trampolineLength;
  30. IsApplied = true;
  31. }
  32. public void Undo()
  33. {
  34. Marshal.Copy(BackupBytes, 0, OriginalFuncPtr, BackupBytes.Length);
  35. DetourHelper.Native.MemFree(TrampolinePtr);
  36. TrampolinePtr = IntPtr.Zero;
  37. TrampolineSize = 0;
  38. IsApplied = false;
  39. }
  40. public void Free()
  41. {
  42. IsValid = false;
  43. }
  44. public MethodBase GenerateTrampoline(MethodBase signature = null)
  45. {
  46. if (TrampolineMethod == null)
  47. {
  48. TrampolineMethod = DetourHelper.GenerateNativeProxy(TrampolinePtr, signature);
  49. }
  50. return TrampolineMethod;
  51. }
  52. public T GenerateTrampoline<T>() where T : Delegate
  53. {
  54. if (!typeof(Delegate).IsAssignableFrom(typeof(T)))
  55. throw new InvalidOperationException($"Type {typeof(T)} not a delegate type.");
  56. return GenerateTrampoline(typeof(T).GetMethod("Invoke")).CreateDelegate(typeof(T)) as T;
  57. }
  58. public void Dispose()
  59. {
  60. if (!IsValid)
  61. return;
  62. Undo();
  63. Free();
  64. }
  65. }
  66. }