有些人可能已经注意到,一本关于 Frida 的书正在筹备中。我在 NowSecure 的日常工作中花了大量时间使用 Frida API,因此常常会想起过去那些后来令我后悔的设计决定。多年来我已解决其中大部分,但有些问题处理起来实在痛苦,一直被搁置。到了今天,想到要在这些问题仍然存在的情况下出版一本书,我意识到是时候迎难而上了。

因此,我非常激动地宣布 Frida 12。Frida 的演进终于到达一个阶段:其基础已经足够稳定,可以据此写一本书了。

下面看看具体变化。

CLI 工具

过去一个容易引起困惑的问题是:Python 绑定还附带了一些 CLI 工具。Frida 是用于构建工具的工具包;虽然我们提供几个示例工具,但是否安装它们应由你决定。

此前,任何使用 Python 绑定构建工具的人最终都会依赖 colorama、prompt-toolkit 和 pygments,原因只是我们的 CLI 工具依赖它们。

现在情况改变了。如果执行:

$ pip install frida

现在只会安装 Python 绑定,不包含其他内容,而且该包零依赖。

不过 CLI 工具可能仍对你有用,可用下面的命令安装:

$ pip install frida-tools

绑定中的便利 API

当初看起来很棒的一个想法,是让语言绑定在 Session 对象上提供一些便利 API。设想是:仅需枚举已加载模块和少量内存范围,再读写内存的简单用例,无需自行加载 Agent。因此 Python 和 Node.js 绑定会在幕后代劳。

当时 rpc API 尚不存在,与 Agent 通信比较繁琐,但这仍是一个糟糕的设计决定。JS API 数量众多,若不引入新的复杂层次,就无法全部公开。另一方面,每种语言绑定都必须重复实现这些便利 API,或者我们必须新增可由绑定公开的核心 API。两种方案都很差,会模糊边界并让 Frida 新用户困惑。诚然,它确实简化了内存转储工具等少数简单用例,但对其他人而言只增加了臃肿和困惑。

现在,这些 API 终于从 Python 和 Node.js 绑定中移除。其他绑定从未实现这些便利 API,因此不受影响。

Node.js 绑定

Node.js 绑定编写至今已有数年,Node.js 在此期间发展了很多,现在支持 ES6 类、async / await、箭头函数、Proxy 对象等特性。

仅凭 Proxy 支持,就能把下面这样的 rpc 用法:

const api = await script.getExports();
const result = await api.add(2, 5);

简化为:

const result = await script.exports.add(2, 5);

有些人可能更喜欢用 TypeScript 编写应用;与传统 JavaScript 相比,它能显著提升生产力。除了类型检查,使用 VS Code 等编辑器时还能获得类型感知重构和出色的代码补全。

不过,要充分发挥类型检查和编辑器功能,项目依赖必须具备类型定义。如今这很少成为问题,使用 Frida Node.js 绑定的用户却是例外,因为此前我们没有提供任何类型定义。现在终于解决了:我没有在现有绑定上补充类型定义,而是决定用 TypeScript 重写它们。这也让我们能利用 ES6 类和 async / await 等现代语言特性。

本可以到此为止,但在 TypeScript 中使用 Node.js 绑定时,下面的代码仍会令人困扰:

script.events.listen('message', (message, data) => {
});

编译器并不知道 Script 对象存在哪些事件,也不知道特定事件的回调应采用什么签名。现在终于修复了,API 改为:

script.message.connect((message, data) => {
});

这样,编辑器甚至能告诉你支持哪些事件,并对回调代码进行正确的类型检查。太棒了!

Interceptor

过去一个令人困惑的现象是:从 onEnter 或 onLeave 访问 this.context.pc 得到的是返回地址,而不是设置 Hook 的指令地址。现在终于修复了。此外,在 x86 上,this.context.sp 现在指向返回地址,而不是第一个参数。使用调用探针时,Stalker 也同样如此。

此次重构会影响回溯器实现,因此我也改进了 Windows 上的默认回溯器。

Tether?

你可能疑惑过,为何 frida.get_usb_device() 返回的 Device 其 type 是 ‘tether’。现在它终于如预期改为 ‘usb’,语言绑定也终于与核心 API 一致。

12.0.1 的变更

  • core:修复 32 位 x86 上的参数访问
  • core:更新 Stalker 以采用新的 CpuContext 语义
  • python:向 PyPI 发布正确的 README
  • python:修复 Windows 构建系统

12.0.2 的变更

  • core:升级到 Capstone 的 next 分支
  • core:修复 Windows 上的 DbgHelp 回溯器并升级到最新版 DbgHelp
  • python:修复长描述
  • java:修复对 java.lang.Class.getMethod() 的 Hook——感谢 0x3430D!

12.0.3 的变更

  • core:修复被 Capstone 升级破坏的 iOS 构建系统

12.0.4 的变更

  • core:修复 i/macOS 早期插桩期间的 libc++ 初始化——感谢 mrmacete!
  • core:支持带掩码的内存搜索——感谢 mrmacete!
  • core:修复 InvocationContext.get_return_address()
  • node:修复异步函数返回 RPC 对象时的崩溃

12.0.5 的变更

  • core:修复 Capstone 升级导致的 arm64 崩溃;测试并分支解码逻辑此前无法解码负偏移。感谢 mrmacete 发现并修复!
  • core:修复 MIPS 回归和一个崩溃问题——感谢 r0ck3tAKATrashPanda!

12.0.6 的变更

  • python:改进 spawn(),在 Python 2.x 上支持 Unicode aux 选项
  • java:修复缓存目录缺失时的 Java.registerClass()
  • java:允许配置临时文件命名

12.0.7 的变更

  • core:修复 iOS 11.3.1 至 11.4.1 上的早期插桩——感谢 mrmacete!

12.0.8 的变更

  • core:修复启动带自定义进程名的 Android 应用——感谢 giantpune!
  • java:修复 Android 8.0 上的 ClassLinker 字段偏移检测

尽情体验吧!