如何获取具有 JNI MethodID 的方法的内存位置?
我想通过使用 JNI 来 Hook 或操作 Java 方法,因为众所周知,JVM 会重新定位此类方法,因此无法使用指向方法的静态指针。
所以我使用 C++ 和 JNI 从 JVM 中获取 MethodID。
MethodID 可以转换为 Integer,它是一个十六进制内存地址。
我已经发现,在MethodID的内存位置,有一个指向HEAP地址的指针。这个堆地址指向一个
“jvm.dll.53A14DE8方法:元数据:MetaspaceObj”
(这就是我的逆向工具“ReClass.NET”所说的)
因此 jvm.dll.xxx Method 获得了一些函数指针,但这些不能是 Method,因为它们由 3 个字节组成(太小)或太大(30 个指令+)。 我想找到的方法只返回 1.0 的 float
这是 ReClass.NET 中的 jvm.dll.xxx 方法:
或者是否有其他方法可以在没有 JVMTI 的情况下 native Hook /操作 Java 方法?
最佳答案
您无法像使用 native 方法那样 Hook Java 方法,即直接替换内存中的机器代码。
jmethodID
是对 Java 方法的不透明引用。它在不同的 JVM 中,甚至在同一 JVM 的不同版本中,可能会有不同的实现。例如,随着 Metaspace 的出现,jmethodID
的内部表示在 JDK 7 和 JDK 8 之间发生了变化。
现在,在 HotSpot JVM 中,jmethodID
是指向 Metaspace 中 Method
结构的指针。它不是Java方法的代码,而是代表JVM内部方法的内部结构。
请注意,Java 方法最初根本没有任何机器代码 - 相反,JVM 解释其字节码。由于 JIT 编译、重新编译或去优化,方法的机器代码可能会出现、更改或完全消失。此外,一个方法可能同时具有多个 JIT 编译版本。这就是为什么传统的 Hook 技术不能应用于 Java 方法。此外,一个方法可能会内联到其他 JIT 编译的方法中,在这种情况下 jmethodID
将毫无用处。
但是,有一种用于操作 Java 方法的标准技术 - bytecode instrumentation 。它可以通过标准 API 获得,即 RetransformClasses和 RedefineClasses JVM TI 的功能。
如果您使用 JNI,则也可以使用 JVM TI 函数。即使没有代理或特殊的 JVM 参数,JVM TI 也可以工作;它可以从任何 JNI 上下文中获得。例如。如何从 JNIEnv*
获取 jvmtiEnv*
:
JavaVM* vm;
(*env)->GetJavaVM(env, &vm);
jvmtiEnv* jvmti;
(*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0);
关于java - (JNI) 使用GetMethodID获取Java方法的内存地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59530468/