JNI FindClass 遇到的 NoClassDefFoundError 错误

在上次的隐私合规工具套装文章中,有人留言了 jvmti 也可以实现方法的监控,这几天尝试写了下 demo,从打印的日志上来看,确实是可行,但 MethodEntry 这个 callback,回调频率也太高了吧,总感觉这玩意性能真的太差了,不如免 root 的 frida 方案(狗头)。

然后再说下使用 MethodEntry 遇到的一个问题,我想将执行的类与方法回调给 java 层,然后 java 层去判断隐私合规是否有调用,但使用 FindClass 时报了如下错误:

java.lang.NoClassDefFoundError: Class not found using the boot class loader

从报错日志看,FindClass 的这个类在系统类加载器找不到,由于 jvmti 是系统类加载器加载的类,如果 FindClass 加载的类是应用类的话,确实是无法找到的,这个是类加载双亲委托的规则。

查了下相关资料,这个问题还是比较接近的,但没有给解决办法:

文章引用了个 google 官方链接,常见问题解答:为什么 FindClass 找不到我的类? 官方的解决办法也是在 JNI_OnLoad 中去做 class 缓存,尝试在 JNI_OnLoad 中 FindClass,然后设置全局引用,NewGlobalRef 与 static 都试过:

kotlin 复制代码
jobject myClass;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
	jclass clazz = env->FindClass("com/codelang/jvmticheck/JvmtiHelper");
    myClass = (env)->NewGlobalRef(clazz);
}
kotlin 复制代码
static jclass myClass;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
	jclass clazz = env->FindClass("com/codelang/jvmticheck/JvmtiHelper");
    myClass = clazz;
}

但在 MethodEntry 中去获取这个 myClass 一直是个 null:

kotlin 复制代码
void MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jmethodID method) {
    ALOGI("clazz %s",myClass!= nullptr?"not null":"null");
} 

搜到另一位使用 jvmti 的博主遇到的问题,跟我遇到的一样:

然后我又去找了下几个 jvmti 的 demo,没有人这么玩,所以,只能自己硬着头皮继续查资料了。

在 Java 中,系统类加载器是无法加载应用类的,为了解决这个问题,Java 的设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoader)。它是从 JDK1.2 开始引入的,可以通过 Thread 类的 getContextClassLoader() 与 setContextClassLoader(ClassLoader cl) 来获取和设置当前线程的类加载器。

基于这个思路,我想在 jni 中应该也是一样的,尝试在 MethodEntry 中找下有关 context classLoader 的方法,别说,还真有:

那么,有了 context classLoader 之后该如何加载 Class 呢?巧了,正好 Class.forName 支持传入上下文类加载器来加载类:

我们的 jni 代码就可以写成:

显示效果,红色为 java 方法打印的日志:

总结

虽然解决了 boot classLoader 加载应用类的问题,但还有一个问题需要解决,那就是调用 Java 方法之后可能会造成的循环调用问题,这里需要做一些类、方法的排除。

jvmti demo 示例可查看 jvmticheck.cpp

相关推荐
Jerry3 小时前
Compose 中的绘制功能简介
android
我科绝伦(Huanhuan Zhou)4 小时前
【脚本升级】银河麒麟V10一键安装MySQL9.3.0
android·adb
消失的旧时光-19434 小时前
Android回退按钮处理方法总结
android·开发语言·kotlin
叫我龙翔5 小时前
【MySQL】从零开始了解数据库开发 --- 数据表的约束
android·c++·mysql·数据库开发
2501_916013745 小时前
iOS 上架 App 全流程实战,应用打包、ipa 上传、App Store 审核与工具组合最佳实践
android·ios·小程序·https·uni-app·iphone·webview
2501_915106326 小时前
iOS 26 能耗监测全景,Adaptive Power、新电池视图
android·macos·ios·小程序·uni-app·cocoa·iphone
用户2018792831676 小时前
浅谈Android PID与UID原理
android
TimeFine7 小时前
Android AWS KVS WebRTC 通话声道切换到媒体音乐声道
android
用户2018792831678 小时前
Android文件下载完整性保证:快递员小明的故事
android