DEX 操作接口——在运行时读写和操作 DEX 字节码
什么时候用 dex 模块
Frida 原生的 API 已经能覆盖绝大多数 Hook 场景(Java.use 找类、Interceptor 拦截函数、Module 找 SO 基址)。dex 模块补充的是直接操作 DEX 字节码的能力——在更底层做事情。
典型场景:
- 目标应用用了加壳或混淆,Frida 的
Java.use找不到原始类,但 DEX 字节码里还留着原始信息 - 需要在运行时动态加载新类(而不是提前注入 Frida 脚本)
- 直接修改类的字段值、方法体等字节码结构
基本用法
dex 模块的 API 列表和 Frida 运行时版本关联较大,具体以 JsHook 内置的 API 文档为准。以下是通用概念。
列出 DEX 文件
// 列出目标应用加载的所有 DEX
var dexList = dex.list();
dexList.forEach(function (d) {
console.log('[+] DEX: ' + d.path + ', classes: ' + d.classCount);
});
搜索类名
// 在指定 DEX 里按关键词搜索类
var results = dex.search('com.example', 'Shop');
results.forEach(function (r) {
console.log('[+] 找到类: ' + r.className);
});
读取类信息
var ShopClass = dex.getClass('com.example.Shop');
console.log('[+] 类名: ' + ShopClass.name);
console.log('[+] 父类: ' + ShopClass.superClass);
ShopClass.methods.forEach(function (m) {
console.log(' 方法: ' + m.name + m.signature);
});
和 Frida API 的关系
dex 模块补充 Frida API 的深度:
| 需求 | 用哪个 |
|---|---|
| Hook 已知类的已知方法 | Java.use() + implementation |
| 搜索所有已加载类 | Java.enumerateLoadedClasses() |
| 在混淆/加壳情况下搜索原始类名 | dex.search() |
| 运行时动态加载新 DEX | dex.load() |
| 直接修改字节码 | dex.modify() |
大多数场景下 Frida API 就够了。只有当 Frida 层被混淆/加壳挡住时,才需要下探到 DEX 字节码层。
和内核模式的关系
dex 模块操作的是目标进程里 DEX 类加载器的内容。内核模式下观察者进程没有目标进程的类加载器,dex 模块在内核模式下不可用。
如果脚本可能在内核模式下运行,用 runtime.isKernel 判断并跳过 dex 相关操作。
运行时动态加载 DEX
Java.perform(function () {
// 加载一个外部 DEX 文件到目标应用的 ClassLoader
dex.load('/sdcard/Download/my-custom-classes.dex');
// 加载后就可以用 Java.use 拿到新类了
var CustomClass = Java.use('com.myapp.CustomClass');
console.log('[+] 新类加载成功');
});
这比把所有逻辑写进一个脚本里更灵活——可以把不同功能拆成多个 DEX,按需加载。