本版本有不少令人兴奋的内容。让我们直接开始。
FreeBSD
我们的目标是支持用户关心的所有平台。在本版本中,我想迈出将支持扩展到 BSD 的第一步。现在我很高兴地宣布,Frida 终于也支持 FreeBSD 了!🎉
目前只支持 x86_64 和 arm64,但如果有人愿意帮忙,扩展到其余体系结构并不困难。
移植工作带来了多项架构改进,也普遍提升了基于 ELF 的操作系统上的稳健性。它还让我想到了一些改进 Linux 注入器、使其支持向容器注入的方案;这是我今后希望完成的工作。
Stalker 性能
在 15.1.10 中,Stalker 在 x86/64 上获得了巨大的性能提升。本版本将相同思路应用到了 arm64 后端,包括改进局部性、更好的内联缓存等。据说我们当时在 FuzzBench 中已经能超越或追平 QEMU,现在 arm64 上的表现应该也相当不错。与此同时,我们还提升了稳定性。令人兴奋!
GObject 内省
早在 14.1 中,@meme 就为构建系统接入了 GObject Introspection 支持。这意味着所有 API 都有了机器可读的描述,使我们能够复用现有的语言绑定基础设施,甚至免费获得自动生成的参考文档。
本版本为 Gum 添加了大量注解和文档字符串,我们比以往任何时候都更接近自动生成参考文档。在适合发布生成的文档之前仍有一些工作要做,但已经不远了。如果有人愿意参与,请查看 Gum 的 CI,并留意 GObject Introspection 输出的警告。
Meson 子项目支持
我非常喜欢 Meson 构建系统的一点是它支持子项目。Gum 现在可以作为子项目使用。你们有些人可能已经通过 devkit 二进制文件使用 Gum,现在又有了一个更加简便的新选择。
与使用 devkit 相比,主要优势是所有内容都从源代码构建,因此很容易试验代码。
假设有一个 hello.c 文件,内容如下:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <gum.h>
#include <stdio.h>
#include <unistd.h>
static int (* open_impl) (const char * path, int oflag, ...);
static int replacement_open (const char * path, int oflag, ...);
int
main (int argc,
char * argv[])
{
gum_init ();
GumInterceptor * interceptor = gum_interceptor_obtain ();
gum_interceptor_begin_transaction (interceptor);
open_impl = dlsym (RTLD_DEFAULT, "open");
gum_interceptor_replace (interceptor, open_impl, replacement_open,
NULL, NULL);
gum_interceptor_end_transaction (interceptor);
close (open_impl ("/etc/hosts", O_RDONLY));
close (open_impl ("/etc/fstab", O_RDONLY));
return 0;
}
static int
replacement_open (const char * path,
int oflag,
...)
{
printf ("!!! open(\"%s\", 0x%x)\n", path, oflag);
return open_impl (path, oflag);
}为了构建它,可以在旁边创建包含以下内容的 meson.build:
project('hello', 'c')
gum = dependency('frida-gum-1.0')
executable('hello', 'hello.c', dependencies: [gum])再创建 subprojects/frida-gum.wrap,内容如下:
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = main
depth = 1
[provide]
dependency_names = frida-gum-1.0, frida-gum-heap-1.0, frida-gum-prof-1.0, frida-gumjs-1.0如果尚未安装 Meson 和 Ninja,请运行 pip install meson ninja。
然后进行构建并运行:
$ meson setup build
$ meson compile -C build
$ ./build/hello
!!! open("/etc/hosts", 0x0)
!!! open("/etc/fstab", 0x0)体积
我们投入了大量精力,确保 Frida 能从桌面系统一直扩展到嵌入式系统。本版本中,我花了一些时间分析二进制体积,并据此做出大量调整、添加构建选项来减小体积。
我很好奇,只使用 Interceptor 的 Gum Hello World 程序最小能做到多小。最终结果在使用 Thumb 指令的 32 位 ARM 上测得,其中 Gum 及其依赖静态链接,唯一的外部依赖是系统 libc。
结果小到只有 55K(!),让我非常兴奋。我在 Gum、GLib 和 Capstone 中引入了新的构建选项。Gum 现在支持 “diet” 模式,不使用 GObject,只提供普通 C API。这意味着它不支持 GObject Introspection 和高级语言绑定,也不提供完整 Gum API,不过未来可以继续扩展。
类似地,GLib 也新增了 “diet” 模式,主要是禁用 slice 分配器、调试功能,并做一些其他小调整。
对于 Capstone,我引入了一个可设为 “tiny” 的新 “profile” 选项。启用后,Capstone 只理解足以确定每条指令长度的指令集内容,并提供一些与位置相关指令的细节。其思路是仅支持 Relocator 实现所需的能力,因为 Interceptor 和 Stalker 背后的大部分繁重工作都由它们完成。
除非确实需要如此小的体积,否则我不建议使用这些构建选项;但了解能够做到什么仍然很有价值。我们也提供其他不那么极端的选项,详情请阅读体积文档。
多构建系统之苦
自 Frida 诞生以来一直困扰我的一件事是,构建 Frida 需要与多个构建系统打交道。我们当然会尽量把复杂性隐藏在脚本和 makefile 后面,但总会有用户不得不费力弄清 Frida 为何无法构建,并因此感到沮丧。
有些人还希望为略有不同的 libc、工具链或其他环境交叉编译 Frida,甚至可能想支持尚未支持的操作系统。但当他们意识到需要处理四种不同构建系统——Meson、autotools、自定义 Perl 脚本(OpenSSL)和 GN(V8)——时,很可能立刻失去动力。
我们是 Meson 的满意用户,因此我的目标是“让一切 Meson 化!”到本版本为止,我们终于基本实现所有必需依赖都使用 Meson 构建。唯一的例外是 V8,但希望有一天也能用 Meson 构建它。(来自未来的剧透:Frida 16 会实现这一目标!)
结束语
此外还有许多令人兴奋的变化,请务必查看下面的变更日志。
祝使用愉快!
变更日志
- 添加 FreeBSD 支持。
- 添加 ARMv4 支持,用于为旧式嵌入式系统插桩。
- 添加减小二进制体积的构建选项(参见 config.mk)。
- 调整 Capstone 和 GLib,以实现小得多的二进制体积。
- droidy:添加 AXML 解码器。感谢 @meme!
- windows:修复 dbghelp 回溯器对 libffi frame 的支持。
- linux:修复与新版 glibc 的兼容性。
- linux:安装资源后只使用一个 frida-helper。
- qnx:注入器关闭时移除临时文件。
- core:修复取消 agent 清理时的泄漏。
- gumjs:修复返回 null 的 RPC 调用处理。
- interceptor:无法分配 “JMP
” 可达内存时,按需在 x86 上使用 “jumbo” JMP。 - interceptor:生成可变大小的 x86 NOP 填充。
- stalker:将近期用于优化 x86/64 后端的思路应用于 arm64 后端,例如改进局部性和内联缓存,从而提升性能。
- stalker:修复大小为零的 freeze/thaw() 处理。
- stalker:重做 x86 PLT 排除代码,避免跟踪期间的重入问题。
- stalker:不再要求存在 C++ 运行时。
- arm-writer:添加 put_bl_reg()、put_call_reg()。
- arm-writer:修复 put_call_address*() 中的寄存器破坏。
- arm64-reader:公开 disassemble_instruction_at()。
- arm64-writer:修复混合宽度字面量的处理。
- arm64-writer:修复 TBZ/TBNZ 编码。
- arm64-writer:修复 32 位系统上的 put_and_reg_reg_imm()。
- arm64-writer:添加 put_{ldr,str}_reg_reg_offset_mode()。
- elf-module:公开更多细节,添加离线模式支持和 Vala 绑定。
- exceptor:添加 reset() 以恢复异常处理程序。
- gum:添加大量 GObject Introspection 注解和 API 文档。
- gum:支持作为 Meson 子项目使用。
- gum:将 Meson 构建系统移植到 Windows。
- gum:消除 GIO 依赖。
- gum:添加 diet 模式,使使用 Interceptor 的 “Hello World” C 程序在采用 Thumb 指令的 32 位 ARM 上可小至 55K。
- gum:添加 CI。感谢 @meme!
- 对构建系统进行多项可移植性改进。
- 使用 Meson 构建 elfutils、libiconv、libdwarf、libunwind、openssl、xz。
- 升级依赖:capstone、elfutils、libdwarf、libunwind。
- 发布 Fedora 35 而非 34 的软件包。
- python:使用 PEP 503 代替 PyPI xmlrpc。感谢 @GalaxySnail!
- python:修复 Windows 上对 Python >= 3.10 的支持。
oleavr