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

相关推荐
B.-1 小时前
Flutter 应用在真机上调试的流程
android·flutter·ios·xcode·android-studio
有趣的杰克1 小时前
Flutter【04】高性能表单架构设计
android·flutter·dart
大耳猫7 小时前
主动测量View的宽高
android·ui
帅次9 小时前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
枯骨成佛10 小时前
Android中Crash Debug技巧
android
kim565915 小时前
android studio 更改gradle版本方法(备忘)
android·ide·gradle·android studio
咸芝麻鱼15 小时前
Android Studio | 最新版本配置要求高,JDK运行环境不适配,导致无法启动App
android·ide·android studio
无所谓จุ๊บ15 小时前
Android Studio使用c++编写
android·c++
csucoderlee16 小时前
Android Studio的新界面New UI,怎么切换回老界面
android·ui·android studio
kim565916 小时前
各版本android studio下载地址
android·ide·android studio