在 C# 中在运行时挂钩托管方法

Posted

技术标签:

【中文标题】在 C# 中在运行时挂钩托管方法【英文标题】:Hook a managed method at runtime in c# 【发布时间】:2016-02-04 16:47:05 【问题描述】:

我在程序集中有一个带有公共方法的密封类,我想添加一个日志系统,但不幸的是我没有源代码。所以我试图在一个特定的日志记录方法上绕道这个方法,并在退出时调用原来的方法。挂钩工作正常,但我无法获得任何类型的参数,或者至少我得到了一些完全错误的东西。

我也不能使用任何类型的注入或像 PostSharp 这样的库,所以我想知道这种东西是否可以在运行时以某种方式实现,或者我可以放弃吗?

为了给你更多细节,我将在下面粘贴一些代码部分:

public Hook(Delegate target, Delegate hook)

  this.target = Marshal.GetFunctionPointerForDelegate(target);
  targetDelegate = target;
  this.hook = Marshal.GetFunctionPointerForDelegate(hook);

  originalBytes = new byte[6];
  Marshal.Copy(this.target, originalBytes, 0, 6);

  byte[] hookPointerBytes = BitConverter.GetBytes(this.hook.ToInt32());
  // Jump
  newBytes = new byte[]
  
    0x68, hookPointerBytes[0], hookPointerBytes[1], hookPointerBytes[2], hookPointerBytes[3], 0xC3
  ;


public object CallOriginal(params object[] args)

  // Remove the patch
  Uninstall();
  // Invoke the original method
  object ret = targetDelegate.DynamicInvoke(args);
  // Re-apply the patch
  Install();
  return ret;



public sealed class Foo

    public void DoSomething(Int32 value1)
    
      // and here I am getting value1 = -1919988997
      Console.WriteLine(value1);
    


class Program

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void DoSomethingDelegate(Int32 value1);

    private static DoSomethingDelegate Original  get; set; 
    private static DoSomethingDelegate Hooked  get; set; 

    private static HookManager _hookManager;

    public static void DoSomething(Int32 value1)
    
      // This is called as well after foo.DoSomething but value1 is 251934152
      Console.WriteLine("Hooked DoSomething: " + value1) ;
      var hook = _hook["DoSomethingHook"];

      // Call the original Foo.DoSomething
      hook.CallOriginal(value1);
    

    static void Main(string[] args)
    
      RuntimeHelpers.PrepareMethod(typeof(Foo).GetMethod("DoSomething").MethodHandle);
      _hookManager = new HookManager();
      var originalPointer = typeof(Foo).GetMethod("DoSomething").MethodHandle.GetFunctionPointer();
      Original = (DoSomethingDelegate)Marshal.GetDelegateForFunctionPointer(originalPointer, typeof(DoSomethingDelegate));
      Hooked = DoSomething;
      _hookManager.Add(Original, Hooked, "DoSomethingHook");

      // Call Hook method, HookManager it is just an extended dictionary...
      _hookManager.InstallAll();

      var foo = new Foo();

      // Calling the original method here with 1
      foo.DoSomething(1);

      Console.ReadLine();
    

【问题讨论】:

GetMethod 会给你一个 MethodInfo ,其中包含有关该方法的所有信息,包括参数类型 这篇文章可能对您有所帮助:codeproject.com/Articles/37549/… 谢谢@Gusman,我已经看过了。但它正在用另一种方法替换原来的方法,这不是我所需要的 已解决,Marshal.GetFunctionPointerForDelegate:您不能使用此方法从一个函数指针创建一个委托到另一个托管委托。 您是否在某处发布了完整代码?我对此非常感兴趣。 【参考方案1】:

已解决,Marshal.GetFunctionPointerForDelegate:我无法使用此方法创建从函数指针指向另一个托管委托的委托。

  this.target = target.Method.MethodHandle.GetFunctionPointer(); //Marshal.GetFunctionPointerForDelegate(target);
  targetDelegate = target;
  this.hook = hook.Method.MethodHandle.GetFunctionPointer(); //Marshal.GetFunctionPointerForDelegate(hook);

【讨论】:

以上是关于在 C# 中在运行时挂钩托管方法的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中在运行时创建 pdf 文件 [关闭]

如何在 C# MVC 应用程序中在运行时创建 SQL Server Express 数据库?

有没有办法像在 C++ 中挂钩非托管函数一样在 C# 中挂钩托管函数?

有没有办法像在 C++ 中挂钩非托管函数一样在 C# 中挂钩托管函数?

OpsWorks 在部署时运行挂钩

在 Java 中在运行时扩展或添加新类