MASTG-TOOL-0031:Frida
Frida 是一个免费和开源的动态代码插桩工具包,由 Ole André Vadla Ravnås 编写,通过将 QuickJS JavaScript 引擎(以前是 Duktape 和 V8)注入到检测过程中来工作。 Frida 允许你在 Android 和 iOS 上的原生应用中执行 JavaScript 代码片段(以及在 其他平台上)。
安装¶
要在本地安装 Frida,只需运行
pip install frida-tools
或者参考安装页面了解更多详情。
操作模式¶
代码可以通过多种方式注入。 例如,Xposed 永久性地修改 Android 应用加载器,每次启动新进程时都提供运行你自己的代码的钩子。 相比之下,Frida 通过将代码直接写入进程内存来实现代码注入。 当附加到运行中的应用时
- Frida 使用 ptrace 来劫持正在运行的进程的线程。 此线程用于分配内存块并用微型引导程序填充它。
- 引导程序启动一个新线程,连接到设备上运行的 Frida 调试服务器,并加载包含 Frida 代理(
frida-agent.so
)的共享库。 - 代理建立一个双向通信通道返回到工具(例如 Frida REPL 或你自定义的 Python 脚本)。
- 被劫持的线程在恢复到其原始状态后继续运行,并且进程执行照常继续。
- Frida 架构,来源:https://www.frida.re/docs/hacking/
Frida 提供三种操作模式
- 注入:这是最常见的场景,frida-server 作为守护进程在 iOS 或 Android 设备中运行。 frida-core 通过 TCP 公开,默认监听 localhost:27042。 在未 root 或越狱的设备上,无法在此模式下运行。
- 嵌入式:这是你的设备未 root 或越狱(你不能以非特权用户身份使用 ptrace)的情况,你负责通过将其嵌入到你的应用中手动或通过第三方工具(例如 objection.将frida-gadget 库注入到你的应用中,手动或通过第三方工具来完成。
- 预加载:类似于
LD_PRELOAD
或DYLD_INSERT_LIBRARIES
。 你可以将 frida-gadget 配置为自主运行并从文件系统加载脚本(例如,相对于 Gadget 二进制文件所在位置的路径)。
APIs¶
与所选模式无关,你可以使用 Frida JavaScript APIs 与运行中的进程及其内存进行交互。 一些基本的 API 是
- Interceptor:当使用 Interceptor API 时,Frida 在函数序言中注入一个 trampoline(又名内联钩子),这会导致重定向到我们的自定义代码,执行我们的代码,并返回到原始函数。 请注意,虽然对于我们的目的来说非常有效,但这会引入相当大的开销(由于 trampoline 相关的跳转和上下文切换),并且不能被认为是透明的,因为它会覆盖原始代码并且行为类似于调试器(放置断点),因此可以以类似的方式检测到,例如通过定期校验其自身代码的应用。
- Stalker:如果你的跟踪要求包括透明度、性能和高粒度,那么 Stalker 应该是你的 API 选择。 当使用 Stalker API 跟踪代码时,Frida 利用即时动态重新编译(通过使用 Capstone):当一个线程即将执行其下一个指令时,Stalker 会分配一些内存,将原始代码复制过去,并将复制的代码与你的自定义代码交织在一起进行插桩。 最后,它执行复制的代码(保持原始代码不变,因此避免任何反调试检查)。 这种方法大大提高了插桩性能,并且允许在跟踪时具有非常高的粒度(例如,通过专门跟踪 CALL 或 RET 指令)。 你可以在 Frida 的创建者 Ole 的博客文章“代码跟踪器的解剖” [#vadla] 中了解更深入的详细信息。 Stalker 的一些用例示例是,例如 who-does-it-call 或 diff-calls。
- Java:在 Android 上工作时,你可以使用此 API 来枚举加载的类、枚举类加载器、创建和使用特定的类实例、通过扫描堆来枚举类的实时实例等等。
- ObjC:在 iOS 上工作时,你可以使用此 API 来获取所有已注册类的映射、注册或使用特定的类或协议实例、通过扫描堆来枚举类的实时实例等等。
Frida 17¶
Frida 17 引入了重大更改,例如删除了 Frida 的 GumJS 运行时中的捆绑运行时桥(frida-{objc,swift,java}-bridge
)。 这意味着你现在必须通过使用 frida-pm install
显式安装你需要的桥
frida-pm install frida-java-bridge
但是,命令 frida
和 frida-trace
预捆绑了 Java、Objective-C 和 Swift 桥,因此你仍然可以在这些上下文中使用它们,而无需手动安装。 你可以在 Frida 文档中了解有关桥的更多信息。
Frida 对其原生 API 进行了更改。 虽然这些更改可能会破坏你的一些现有脚本,但它们鼓励你编写更具可读性和性能的代码。 例如,现在,Process.enumerateModules()
返回一个 Module
对象数组,允许你直接使用它们。
for (const module of Process.enumerateModules()) {
console.log(module.name);
}
另一个已删除的 API 是 Module.getSymbolByName
,它在许多脚本中使用。 根据你是否知道符号所在的模块,你可以使用以下两种替代方法之一
// If you know the module
Process.getModuleByName('libc.so').getExportByName('open')
// If you don't (i.e., the old Module.getSymbolByName(null, 'open'); )
Module.getGlobalExportByName('open');
有关更多详细信息,请参阅 Frida 17.0.0 发行说明。
工具¶
Frida 还提供了一些构建在 Frida API 之上的简单工具,并且在通过 pip 安装 frida-tools 后可以直接从你的终端使用。 例如
- 你可以使用 Frida CLI(
frida
)进行快速脚本原型设计和试错场景。 frida-ps
以获取设备上运行的所有应用(或进程)的列表,包括它们的名称、标识符和 PID。frida-ls-devices
以列出你连接的运行 Frida 服务器或代理的设备。frida-trace
以快速跟踪属于 iOS 应用或在 Android 本地库中实现的方法。
此外,你还会发现几个基于 Frida 的开源工具,例如
- Grapefruit:一个用于 iOS 的运行时应用程序检测工具包。
- Fridump:一个用于 Android 和 iOS 的内存转储工具。
- objection:一个运行时移动安全评估框架。
- r2frida:一个项目,它将 radare2 的强大逆向工程功能与 Frida 的动态检测工具包相结合。
- JNITrace:一种用于跟踪本机库对 Android JNI 运行时方法的使用情况的工具。
我们将在整个指南中使用所有这些工具。
你可以按原样使用这些工具,根据你的需要进行调整,或者将它们作为如何使用 API 的出色示例。 将它们作为示例在你编写你自己的钩子脚本或在你构建内省工具以支持你的逆向工程工作流程时非常有用。