【发布时间】:2021-12-03 15:31:00
【问题描述】:
在 C++ 中,我会获取函数的地址并将前几个字节覆盖到我的函数的 jmp 中,做一些事情,恢复原始字节,然后调用原始函数。
我可以在 C# 中做这样的事情吗?
【问题讨论】:
-
这个问题很有趣。但我不认为有办法..
在 C++ 中,我会获取函数的地址并将前几个字节覆盖到我的函数的 jmp 中,做一些事情,恢复原始字节,然后调用原始函数。
我可以在 C# 中做这样的事情吗?
【问题讨论】:
.NET Profiler API 是最接近“Microsoft 认可”的在运行时拦截方法的方式。如前所述,这有点难以实现,我不知道有一个库可以使用纯托管代码轻松实现。
几个月前我自己研究这个选项时,我偶然发现了CLR Method Injection,这是一篇包含源代码的文章,解释了如何在运行时拦截方法。我自己考虑过使用它,甚至让示例项目工作,但最终得出的结论是,我需要的不仅仅是方法拦截,还需要一个不同的解决方案。但是,这种方法直接回答了您的问题。
最后,我最终做的是开发Afterthought 作为PostSharp 的开源替代品,它作为后编译步骤运行,允许您修改现有方法以调用其他代码,或替换方法实现共。我现在正在研究一种新的流畅语法,我将在其中包含一个示例,以提供一个示例来帮助您了解这种 AOP 方法如何满足您的需求:
Methods
.Named("Sum")
.WithParams<int[]>()
.Before((T instance, ref int[] values)
=> { var s = new Stopwatch(); s.Start(); return s; })
.After((instance, stopwatch, values)
=> instance.Result = (int)stopwatch.ElapsedMilliseconds);
在这种情况下,在使用Sum 方法修改现有类型时,我将在方法之前和之后引入代码来测量执行时间。在对原始编译类运行 Afterthought 后,生成的 Sum 方法将在方法体之前和之后调用这些 lambda 表达式(C# 编译器只是将它们转换为静态方法)。我可以很容易地调用Implement 并替换整个方法实现。
我希望其中一种方法能够满足您的需求。就我而言,我选择了 AOP 路线,因为我想做的不仅仅是拦截,例如实现接口、添加新方法/属性等。我还想要一些不会在运行时引入依赖或担心稳定性或性能的东西。运行时环境——编译时处理更安全,更容易测试。
【讨论】:
你想在运行时挂钩还是要修补二进制文件?
要在运行时挂钩,您可以使用分析 api(相对困难): http://msdn.microsoft.com/en-us/magazine/cc188743.aspx
要在编译时挂钩,您可以使用 IL 重写器,例如 PostSharp。
【讨论】:
您正在寻找的技术称为 AOP - 面向方面的编程。如果你仔细观察,你可以找到几个 C# 框架。
更新:您可以在这个问题中找到大量链接和信息:Built-in AOP in C# - is it on the way?
【讨论】: