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

相关推荐
荣月灵的小梅花5 小时前
在Android 9上修改build.fingerprint
android
帅次5 小时前
Compose 入门:@Composable、组合与重组
android·kotlin·gradle·android jetpack·compose·composable
洞见前行5 小时前
APK Signing Block V2 多渠道分包技术原理
android
DandelionR5 小时前
Android SDK安装
android
雪铃儿6 小时前
Flutter Android 热更新:我为什么没用 Shorebird 而是自己造了一个🚀
android·开源
angerdream6 小时前
Android手把手编写儿童手机远程监控App之通知栏消息
android
OCN_Yang8 小时前
能告诉我:你为什么用 MVI 吗?反正我不理解!
android·架构·前端框架
荣月灵的小梅花9 小时前
Android 给广播接收器增加权限(permission)或signature签名权限
android
沐言人生9 小时前
ReactNative 源码分析4——ReactActivity之加载JSBundle
android·react native
砖厂小工11 小时前
Now In Android 精讲 10 - AGENTS.md:写给 AI Agent 的项目说明书
android