问题描述
我想获取方法地址以便稍后在我的自定义作弊保护中使用它(我想检查方法是否被挂钩)。我目前正在尝试使用
typeof(MyClass).getmethod("MyMethod").MethodHandle.GetFunctionPointer();
但这并没有给我正确的偏移量。对不起,如果我的问题看起来很愚蠢,但我认为这是做我需要的唯一方法。谢谢。
UPD:我正在将我的偏移量与 Cheat Engine 的偏移量进行比较。我知道地址总是不同的
UPD 2:我想读取我自己的应用程序的内存,所以我可以检查它是否被更改(我只对非常重要的方法这样做)
解决方法
您有一个 X/Y problem,由于您对 CLR 和托管代码在 Windows 台式计算机中的执行方式缺乏了解而恶化。我会详细说明。
我要获取方法地址
未通过 AOT 编译为本机代码的计算机程序,例如用 C#/.NET、Java 和 JavaScript 编写的程序,不会将其函数/方法位于内存中的单个位置.
这是因为:
- 函数可以通过解释器执行,通常称为字节码解释器或类似的。发生这种情况时,根本没有函数的本机代码表示。
- 当一个函数最终被 JIT 编译时,它可以存在于内存中的多个位置,因为 JIT 编译器可能会根据运行时行为多次重新编译一个函数(例如,JIT 可以重新编译一个函数并删除所有的
if( x == null )
检查是否在遵循热门路径时意识到它们是不必要的。 - 当使用 monomorphic 或 reified 泛型系统(在 .NET 中使用,而不是在 Java 中使用)时,如果存在任何泛型函数(包括泛型类型的非泛型成员) ) 对于泛型类型参数参数的每个不同组合,这些函数将在内存中实例化。
- 这是因为编译后的
List<String>.Add(String s)
方法不能用于List<FileInfo>
更不用说List<Int32>
(请记住,.NET 不使用类型擦除)。
- 这是因为编译后的
简而言之:C# 方法没有单一地址。
稍后在我的自定义作弊保护中使用它
如果这对你来说是一个学习练习,那么继续 - 忽略仇恨者和他们的口号:“不要推出你自己的加密货币”、“构建完美的 DRM 系统在数学上是不可能的”和“构建您自己的作弊保护只是在欺骗自己”:执行傻瓜差事可能是了解为什么这是傻瓜差事的最佳方式 - 不要在生产中使用它 所以您不会让其他用户处于危险之中。
我想检查方法是否被钩住
我想你误解了钩子的工作原理。 “钩子”是 Win32 特有的(因为它是 Win32 的一个设计特性),但你不能“钩子”软件中的任意方法/函数。
我目前正在尝试使用 typeof(MyClass).GetMethod("MyMethod").MethodHandle.GetFunctionPointer();
获取指针,但这并没有给我正确的偏移量。
您应该阅读文档。
The documentation for MethodHandle
says(强调我的):
获取方法的内部元数据表示的句柄。
The documentation for GetFunctionPointer
says(强调我的):
返回的 IntPtr
用于内部运行时使用,不应用于从本机代码调用函数。使用 Marshal.GetFunctionPointerForDelegate
以获得可以传递给本机代码的函数指针。
一般来说,如果有“内部”字样,您可能不应该使用它。
我知道 MethodHandle
和 GetFunctionPointerForDelegate
的文档确实表明它返回 C 风格的函数指针,但就您而言,文档是不正确的。
(实际上,如果您在 GetFunctionPointerForDelegate
上调用 MethodInfo
以获得开放式泛型方法,您将得到一个 InvalidProgramException
!- 这根本没有记录,呃)。
UPD:我正在将我的偏移量与 Cheat Engine 的偏移量进行比较。我知道地址总是不同的
由于我已经讨论过的原因,Cheat Engine 不适用于非本地程序。
如果您在 Cheat Engine 的论坛上搜索“.NET”或“Java”,您会发现数百篇来自与您遇到相同问题的人的帖子。
UPD 2:我想读取我自己的应用程序的内存,所以我可以检查它是否被更改(我只对非常重要的方法这样做)
由于上述原因,您不能对任何非确定性 JIT 编译的软件执行此操作。