有些读者可能知道,Frida 有两个 JavaScript 运行时:一个基于 V8,另一个基于 Duktape。 我们过去还有一个基于 JavaScriptCore 的运行时,但后来事实证明,在所有不适合 V8 的场景中,例如微型嵌入式系统以及禁止 RWX 内存页的系统上,Duktape 运行时都表现得更好,因此 JavaScriptCore 运行时退役了。

值得一提的是,Duktape 提供了编译为字节码的 API。这样就能缓存已编译的代码,在需要 对新进程进行插桩时节省宝贵的启动时间。从本次发布开始,我们提供了全新的 API,可将 JavaScript 编译为字节码,当然也可以从字节码实例化脚本。V8 运行时尚不支持此 API, 不过下次升级 V8 后,我们应该可以利用最近版本中开始出现的 WebAssembly 基础设施来实现它。

闲话少叙,让我们通过 Session.disable_jit() 强制 Frida 优先使用 Duktape,试用一下 Duktape 运行时中的这项新 API。

在 Node.js 中:

const co = require('co');
const frida = require('frida');

co(function* () {
  const systemSession = yield frida.attach(0);
  yield systemSession.disableJit();
  const bytecode = yield systemSession.compileScript(`
    rpc.exports = {
      listThreads() {
        return Process.enumerateThreadsSync();
      }
    };
  `);

  const session = yield frida.attach('Twitter');
  yield session.disableJit();
  const script = yield session.createScriptFromBytes(bytecode);
  yield script.load();

  const api = yield script.getExports();
  console.log('api.listThreads() =>', yield api.listThreads());

  yield script.unload();
})
.catch(err => {
  console.error(err);
});

在 Python 中:

import frida

system_session = frida.attach(0)
system_session.disable_jit()
bytecode = system_session.compile_script("""
rpc.exports = {
  listThreads() {
    return Process.enumerateThreadsSync();
  }
};
""")

session = frida.attach("Twitter")
session.disable_jit()
script = session.create_script_from_bytes(bytecode)
script.load()

api = script.exports
print("api.list_threads() =>", api.list_threads())

请注意,此处同样存在 Duktape 文档中说明 的限制,因此请确保要加载的代码格式正确,并由同一版本的 Duktape 生成。升级到未来版本的 Frida 时,Duktape 可能也会升级;不过字节码至少与架构无关,也就是说,你可以在 64 位 x86 桌面系统上编译为字节码,再顺利加载到 ARM 上的 32 位 iOS 应用中。

以上是通过 API 编译字节码,不过你可能更希望改用 frida-compile CLI 工具:

$ npm install frida-compile
$ ./node_modules/.bin/frida-compile agent.js -o agent.bin -b

开发期间还可以添加 -w 使用监视模式。该模式会监视输入,并在其中任意文件变化时执行 快速增量构建。

无论是否使用字节码(-b),我们都强烈推荐 frida-compile,因为它还有许多其他优点, 可以让你:

  • 使用 require() 将脚本拆分成多个 .js 文件。
  • 利用 npm 上成千上万个现有模块,其中也包括一些 Frida 专用模块。例如: frida-trace、 frida-uikit、 frida-screenshot 等。
  • 使用 ES6 语法,并将代码编译为 ES5,以兼容 Duktape 运行时。

最后,我们来汇总一下变更:

7.2.0:

  • core:支持编译和加载字节码,以及从字节码加载
  • core:在 RPC 错误响应中包含错误名称和堆栈跟踪
  • node:支持新的字节码 API
  • node:在可用时为 RPC 错误补充 name 和 stack
  • node:将示例迁移到 ES6
  • python:支持新的字节码 API
  • python:适配修订后的 RPC 协议

7.2.1:

  • objc:支持解析精简 Objective-C 代理上的方法

7.2.2:

  • objc:修复返回结构体和浮点值的方法处理

7.2.3:

  • objc:公开 Objective-C 方法的原始句柄

7.2.4:

  • core:修复在 iOS 9 上很容易复现的死锁
  • java:提高 Java.perform() 的稳健性,并改进对非应用进程的处理

7.2.5:

  • objc:修复 x86-64 上通过寄存器返回结构体的方法处理

7.2.6:

  • core:将 Gum 移植到 MIPS
  • core:避免在 Proxy 对象行为异常时吞掉异常
  • objc:支持访问 Objective-C 实例变量

7.2.7:

  • core:将 .so 注入器移植到 MIPS
  • core:为 MIPS 模糊回溯器增加更多分支并链接指令
  • core:修复 UnixInputStream 和 UnixOutputStream 在 TTY 上的可轮询行为, 解决脚本卸载时挂起的问题
  • core:移除 hexdump() 偏移量中的“0x”前缀

7.2.8:

  • objc:修复类型提示解析
  • objc:支持包含类型提示
  • objc:公开 ObjC.Block 的 types 字段
  • objc:支持正确声明 void *
  • core:(MIPS)修复获取/设置栈参数时的栈偏移

7.2.9:

  • core:修复 V8 运行时中无法写入寄存器的错误

7.2.10:

  • core:支持附加到 iOS 模拟器进程
  • core:修复 7.2.4 引入的 Android 类解析回归

7.2.11:

  • core:始终通过 SpringBoard 终止 iOS 应用

7.2.12:

  • objc:在卸载和 GC 时注销 Objective-C 类

7.2.13:

  • core:修复 iOS 9 上的应用终止逻辑

7.2.14:

  • core:让 Duktape 运行时像 V8 运行时一样可被抢占
  • core:修复 V8 运行时中的几个锁错误

7.2.15:

  • core:也在 Duktape 运行时中实现 Kernel API
  • core:移除危险的 Kernel.enumerateThreads() API

7.2.16:

  • core:提高快速重新附加到同一进程时的稳健性
  • core:修复分离时存在待处理调用所导致的死锁
  • core:修复 32 位 ARM 上的挂钩回归
  • core:修复 Linux 上 frida-gadget 中的 dlsym() 死锁
  • core:修复 Windows 构建回归
  • core:修复 iOS 7 回归

7.2.17:

  • core:修复会话拆卸回归

7.2.18:

  • core:修复 iOS 9 上长期存在的稳定性问题:注入的引导代码未进行伪签名,导致进程 最终失去 CS_VALID 状态
  • core:消除不必要的磁盘 I/O,加快 iOS 应用启动速度
  • core:修复 iOS 上的临时目录清理

7.2.19:

  • core:修复 Duktape 运行时中与抢占相关的生命周期问题

7.2.20:

  • core:重构 V8 运行时,以支持完全异步卸载
  • core:重构 Duktape 运行时,以支持完全异步卸载
  • core:让 Duktape 运行时完全可重入
  • core:新增 Script.pin() 和 Script.unpin(),用于在关键时刻延长脚本生命周期, 例如等待来自无法控制的外部 API 的回调时
  • core:修复 V8 和 Duktape 运行时中与定时器相关的泄漏
  • objc:让脚本保持存活,直到 ObjC.schedule() 调度的回调执行完毕
  • objc:向 ObjC 代理 API 添加 dealloc 事件

7.2.21:

  • core:修复 detach() 时挂起的问题

7.2.22:

  • core:修复脚本卸载时挂起的问题
  • core:修复 detach() 期间连接突然中断时挂起的问题

7.2.23:

  • core:修复脚本卸载期间两个低概率崩溃问题

7.2.24:

  • core:修复 Duktape 运行时中的释放后使用问题
  • core:修复 ModuleApiResolver 中的释放后使用错误
  • core:改进设置异常处理程序时的卸载行为

7.2.25:

  • core:修复 iOS 9.3.3 上的应用启动
  • frida-server:修复另一个客户端附加到同一进程时,分离操作“挂起”的问题

尽情使用吧!