这是一次疯狂的发布,带来了大量改进。
先说一项面向用户的变化。名为 frida-repl 的 CLI 工具已更名为 frida,而且现在支持 Tab 补全!这项功能以及其他一些出色的 REPL 改进由 @fitblip 贡献。
现在还集成支持直接从 shell 启动脚本:
$ frida Calculator -l calc.js
_____
(_____)
| | Frida 4.0.0 - A world-class dynamic
| | instrumentation framework
|`-'|
| | Commands:
| | help -> Displays the help system
| | object? -> Display information about 'object'
| | exit/quit -> Exit
| |
| | More info at https://frida.re/docs/home/
`._.'
# The code in calc.js has now been loaded and executed
[Local::ProcName::Calculator]->
# Reload it from file at any time
[Local::ProcName::Calculator]-> %reload
[Local::ProcName::Calculator]->或者,你可能已经厌倦了 console.log(),想在脚本中设置断点,以帮助理解正在发生什么? 现在可以了,因为 Frida 刚刚集成了兼容 Node.js 的调试器。
(此处应出现“Yo Dawg”梗图。)
没错,而且它确实非常实用。所有 CLI 工具都提供 --debug 开关来启用它:
# Connect Frida to a locally-running Calculator.app
# and load calc.js with the debugger enabled
$ frida Calculator -l calc.js --debug
_____
(_____)
| | Frida 4.0.0 - A world-class dynamic
| | instrumentation framework
|`-'|
| | Commands:
| | help -> Displays the help system
| | object? -> Display information about 'object'
| | exit/quit -> Exit
| |
| | More info at https://frida.re/docs/home/
`._.'
Debugger listening on port 5858
# We can now run node-inspector and start debugging calc.js
[Local::ProcName::Calculator]->效果如下:

你是否曾想直接从 shell 使用 frida-trace 跟踪 Objective-C API?感谢 @Tyilo,现在可以了:
# Trace ObjC method calls in Safari
$ frida-trace -m '-[NSView drawRect:]' Safari还有其他好东西,例如全新的回溯生成功能,以及使用调试符号对地址进行符号化:
const f = Module.getExportByName('libcommonCrypto.dylib',
'CCCryptorCreate');
Interceptor.attach(f, {
onEnter(args) {
console.log('CCCryptorCreate called from:\n' +
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n') + '\n');
}
});又或者,你正在 Windows 上尝试找出谁访问了某些内存区域?那就看看全新的 MemoryAccessMonitor。严格来说,这段代码 并不是新的,只是直到现在才向 JavaScript API 公开。
另一项不错的功能是,从本次发布开始,在其他设备(例如 Android)上运行
frida-server 时,不再需要转发多个 TCP 端口。
错误反馈也得到了显著改善,现在会从远程进程一路传播到例如 Python 中不同的异常类型。 在上一个版本中,如果在 Mac 上附加到不存在的 pid,会得到:
SystemError: GDBus.Error:org.gtk.GDBus.UnmappedGError.Quark._g_2↩
dio_2derror_2dquark.Code0: task_for_pid() for remote pid failed w↩
hile trying to make pipe endpoints: (os/kern) failure (5)太疯狂了。现在则简化为:
frida.ProcessNotFoundError: unable to find process with pid 1234好多了。接下来谈谈性能。你可能使用过 frida-trace,并疑惑它为什么在“Resolving functions…”上花费这么长时间。在典型 iOS 应用中,只解析一个函数通常就要约 8 秒, 现在降到了约 1 秒。虽然还有一些优化空间,但我很快意识到,无论函数导出枚举得多快, 数据仍需要传输,而仅传输时间本身就可能令人难以接受。解决办法是什么?把逻辑移到目标 进程中,传输逻辑而不是数据。很简单。 Dalvik 和 ObjC 接口也经过优化,耗时从数秒降至数毫秒。简而言之,我们进一步推迟了查询 语言运行时的时机。ObjC 接口在这方面走得很远,现在使用 ES6 代理来提供更符合习惯、效率 更高的 API。
这就引出了下一个话题。ObjC 接口有一些变化。主要是:
const NSString = ObjC.use("NSString");现在改为:
const NSString = ObjC.classes.NSString;你仍可使用 ObjC.classes 枚举当前已加载的类,但它现在的行为类似一个对象,将类名映射到
JavaScript ObjC 绑定。
此外,不再需要类型转换,因此不再这样写:
const NSSound = ObjC.use('NSSound');
const sound = ObjC.cast(ptr("0x1234"), NSSound);只需这样写:
const sound = new ObjC.Object(ptr("0x1234"));没错,不再需要试图模拟 ObjC 类层次结构。现在使用完全动态的包装器,首次访问时才构建 方法包装器;只有尝试枚举对象属性时,才会获取方法列表。
这篇文章已经很长了,下面汇总其他主要变化:
- Dalvik 接口现在可以处理可变参数方法。感谢 @dmchell 报告并协助追踪此问题。
- 感谢 @Tyilo,NativePointer 现在还提供
.and()、.or()和.xor()。 - Interceptor 的 onEnter/onLeave 回调过去通过
this.registers公开 CPU 寄存器, 现已更名为this.context,而且现在也允许写入寄存器。 - 为保持一致,Process.enumerateThreads() 返回的线程对象已将 CPU 上下文字段从
registers更名为context。 - enumerateFoo() API 现在提供同步版本 enumerateFooSync(),直接返回包含所有项目的数组。
- 现在可使用
Memory.readCString()读取 ASCII C 字符串。 - 可以查询
Frida.version来检查正在运行的版本;frida-core 端也提供该信息,例如 frida-python 通过frida.__version__将其公开。 - Stalker 现在支持 jecxz 和 jrcxz 指令。这对 CryptoShark 是个好消息,它应该很快就会提供 捆绑最新版 Frida 的更新二进制文件。
- V8 已更新到 4.3.62,并启用了许多 ES6 功能。
- 现在使用即将发布的 Capstone 4.0 的开发版本。
- 所有第三方依赖都已更新到最新版本。
- 现在支持 Windows XP。这不是玩笑。我意识到我们其实没有使用任何 XP 之后才提供的 API; 既然必须在 Windows 上重新构建依赖,不妨降低操作系统要求,帮助仍在 XP 上对软件进行 插桩的用户。
尽情使用吧!
oleavr