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

相关推荐
tongyiixiaohuang2 小时前
WMS已发货状态反写金蝶云星空:单策略实战教程
android
好的佩奇3 小时前
Dart 之类修饰符
android·flutter·dart
alexhilton4 小时前
用Konsist与Lint强制执行设计系统契约
android·kotlin·android jetpack
北京自在科技8 小时前
谷歌安卓 Gemini 迎来界面改版,Find Hub 接入 Gemini 支持物品记忆查找
android·安卓
YB137510 小时前
Jetpack Compose 动画Modifier.animateItem()
android
2401_8858850411 小时前
巴林语音通知接口如何对接?系统告警语音API接入教程
android·前端·网络·python·语音识别
收纳过往12 小时前
数据库加索引的时机:慢查询日志说话
android·开发语言·数据库·python·低代码·rxjava
狂热开发者13 小时前
车载中控要给鸿蒙用户,能不能和 Android 共用一个二维码?
android·华为·harmonyos
.Bryce.13 小时前
T2-LLM评测不等于Agent评测
android·java·人工智能·后端·gpt·agent·1024程序员节
美狐美颜SDK开放平台14 小时前
视频美颜SDK如何应对快速转头与大幅度面部动作?
android·人工智能·ios·音视频·直播美颜sdk·视频美颜sdk