如何获取具有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方法?
答案 0 :(得分:1)
您不能像使用本机方法那样钩住Java方法,即,直接在内存中替换机器代码。
jmethodID
是对Java方法的不透明引用。它可以在不同的JVM中甚至在同一JVM的不同版本中以不同的方式实现。例如,随着Metaspace的到来,jmethodID
的内部表示在JDK 7和JDK 8之间发生了变化。
现在,在HotSpot JVM中,jmethodID
是指向Metaspace中Method
结构的指针。它不是Java方法的代码,而是表示JVM内部方法的内部结构。
请注意,Java方法最初根本没有任何机器代码-而是由JVM解释其字节码。由于JIT编译,重新编译或取消优化,方法的机器代码可能会完全出现,更改或消失。同样,一个方法可能同时具有多个JIT编译版本。这就是为什么传统的挂钩技术不能应用于Java方法的原因。此外,一个方法可能会内联到其他JIT编译的方法中,在这种情况下,jmethodID
根本没有用。
但是,有一种用于处理Java方法的标准技术-bytecode instrumentation。它可以通过 standard 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);