java - (JNI) 使用 GetMethodID 获取 Java 方法的内存地址
问题描述
如何获取我拥有 JNI MethodID 的方法的内存位置?
我想通过使用 JNI 来挂钩或操作 Java 方法,因为众所周知,JVM 会重新定位此类方法,因此无法使用指向方法的静态指针。
所以我使用 C++ 和 JNI 从 JVM 中获取 MethodID。
MethodID 可以转换为整数,即十六进制内存地址。
我已经发现,在 MethodID 的内存位置,有一个指向 HEAP 地址的指针。这个堆地址指向一个
“jvm.dll.53A14DE8 方法:元数据:MetaspaceObj”
(这就是我的反向工具“ReClass.NET”所说的)
所以 jvm.dll.xxx 方法得到了一些函数指针,但这些不能是方法,因为它们由 3 个字节(太小)或太大(30 条指令+)组成。我想找到的方法只返回 1.0 的浮点数
这就是 ReClass.NET 中的 jvm.dll.xxx 方法:
或者有没有其他方法可以在没有 JVMTI 的情况下本地挂钩/操作 Java 方法?
解决方案
您不能像使用本地方法那样挂钩 Java 方法,即直接在内存中替换机器代码。
jmethodID
是对 Java 方法的不透明引用。它可能在不同的 JVM 中实现不同,甚至在同一个 JVM 的不同版本中实现。例如,jmethodID
随着 Metaspace 的出现,JDK 7 和 JDK 8 之间的内部表示发生了变化。
现在,在 HotSpot JVM 中,jmethodID
是指向Method
Metaspace 中的结构的指针。它不是Java方法的代码,而是代表JVM内部方法的内部结构。
请注意,Java 方法最初根本没有任何机器代码 - 相反,JVM 解释其字节码。由于 JIT 编译、重新编译或反优化,方法的机器代码可能会出现、更改或完全消失。此外,一个方法可能同时具有多个 JIT 编译版本。这就是为什么传统的挂钩技术不能应用于 Java 方法的原因。此外,一个方法可能被内联到其他 JIT 编译的方法中,在这种情况下jmethodID
将毫无用处。
但是,有一种操作 Java 方法的标准技术——字节码检测。它可通过标准API 获得,即JVM TI 的RetransformClasses和RedefineClasses函数。
如果您使用 JNI,您也可以使用 JVM TI 函数。即使没有代理或特殊的 JVM 参数,JVM TI 也能正常工作;它可以从任何 JNI 上下文中获得。例如如何jvmtiEnv*
从JNIEnv*
:
JavaVM* vm;
(*env)->GetJavaVM(env, &vm);
jvmtiEnv* jvmti;
(*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0);
推荐阅读
- testing - 在 Cypress 中运行测试的所有断言
- magnolia - 渲染不属于 JCR 的节点
- ravendb - 在 Ravendb 中创建使对象数组可搜索的索引
- azure - 如何使用 Azure pod 身份与 Keda 合作
- python - pygame/sprites:暴民碰撞
- c# - 复选框中的 UWP 10 XAML 删除线内容
- angular - 当有效负载数据与当前状态值相同时,如何在 ngxs 状态选择上触发订阅
- javascript - 无法使用 dropzone.js 调整图像大小
- javascript - 如何在 React 中调用类组件?
- android - 无法使用来自 sql Flutter 的数据更新仪表板