Skip to content

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。
  • 动态加载: 插件化框架、热更新(补丁包)。
  • 自定义加载器: 一些加壳程序会自定义加载器来加载解密后的类。

运行逻辑

  1. 枚举: Java.enumerateClassLoadersSync() 同步获取当前进程空间内所有的 ClassLoader 实例。
  2. 嗅探: 对每一个加载器执行 loader.findClass(klass)。这是 Java 原生方法,如果类不存在会抛出异常。
  3. 绑定: 一旦 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 内部或确保相关功能已触发后再执行。 :::