Frida 动态 ClassLoader 查找指南
在 Android 逆向中,直接使用 Java.use() 往往会遇到 ClassNotFoundException,尤其是当目标类位于热修复补丁(如 Sophix)、插件框架或 Multidex 的非主 Dex 中时。
1. 核心代码
javascript
/**
* 遍历所有 ClassLoader 查找指定的类
* @param {string} klass 类名(全路径)
*/
function getClassWrapper(klass) {
for (var loader of Java.enumerateClassLoadersSync()) {
try {
// 尝试在当前加载器中查找类
loader.findClass(klass);
// 如果找到,使用对应的工厂创建类引用
return Java.ClassFactory.get(loader).use(klass);
} catch (e) {
// 没找到则继续尝试下一个加载器
continue;
}
}
throw new Error(`${klass} not found`);
}2. 工作原理
为什么需要它?
Android 应用可能存在多个 ClassLoader。标准的 Java.use() 默认只在主加载器中查找。如果应用使用了以下技术,类可能对主加载器不可见:
- Multidex: 类被分到了辅助 dex。
- 动态加载: 插件化框架、热更新(补丁包)。
- 自定义加载器: 一些加壳程序会自定义加载器来加载解密后的类。
运行逻辑
- 枚举:
Java.enumerateClassLoadersSync()同步获取当前进程空间内所有的ClassLoader实例。 - 嗅探: 对每一个加载器执行
loader.findClass(klass)。这是 Java 原生方法,如果类不存在会抛出异常。 - 绑定: 一旦
findClass成功,必须使用Java.ClassFactory.get(loader)获取一个与该加载器绑定的工厂实例,再进行.use(klass)。这样才能保证后续操作是在正确的上下文(Context)中进行的。
3. 使用方法
场景:Hook 某个动态加载的类
javascript
Java.perform(function() {
try {
// 代替传统的 Java.use("com.example.DynamicClass")
var DynamicClass = getClassWrapper("com.example.DynamicClass");
DynamicClass.targetMethod.implementation = function() {
console.log("成功 Hook 动态加载的方法!");
return this.targetMethod();
};
} catch (e) {
console.error("未找到目标类: " + e.message);
}
});提示 ::: tip
虽然这个方法很强大,但如果在应用启动极早期(attach 瞬间)调用可能会失败,因为对应的 ClassLoader 可能还没有被创建。建议在 Java.perform 内部或确保相关功能已触发后再执行。 :::