跳过内容

MASTG-TOOL-0039: iOS 版 Frida

Frida 支持通过 ObjC API 与 Objective-C 运行时进行交互。你能够 hook 和调用进程及其原生库中的 Objective-C 和原生函数。你的 JavaScript 代码片段可以完全访问内存,例如,读取和/或写入任何结构化数据。

以下是 Frida API 提供的一些任务,这些任务在 iOS 上是相关或独有的

  • 实例化 Objective-C 对象并调用静态和非静态类方法(ObjC API)。
  • 跟踪 Objective-C 方法调用和/或替换其实现(Interceptor API)。
  • 通过扫描堆来枚举特定类的实时实例(ObjC API)。
  • 扫描进程内存中出现的字符串(Memory API)。
  • 拦截原生函数调用,以便在函数入口和出口运行你自己的代码(Interceptor API)。

请记住,在 iOS 上,你还可以受益于安装 Frida 时提供的内置工具,包括 Frida CLI (frida)、frida-psfrida-ls-devicesfrida-trace 等。

有一个 frida-trace 功能在 iOS 上是独有的,值得强调:使用 -m 标志和通配符跟踪 Objective-C API。例如,跟踪所有方法名称中包含 "HTTP",并且属于任何名称以 "NSURL" 开头的类的方法,就像运行一样简单

frida-trace -U YourApp -m "*[NSURL* *HTTP*]"

为了快速入门,你可以浏览 iOS 示例

在 iOS 上安装 Frida

要将 Frida 连接到 iOS 应用程序,你需要一种将 Frida 运行时注入到该应用程序的方法。这在越狱设备上很容易做到,因为你可以通过第三方应用商店(如 Sileo 来安装 frida-server。 打开 Sileo,通过导航到 Manage -> Sources -> Edit -> Add 并输入 https://build.frida.re 来添加 Frida 的仓库。 然后你应该能够找到并安装 Frida 软件包。

默认情况下,frida-server 只监听本地接口,需要你通过 USB 连接设备。 如果你想在公共接口上暴露 frida-server,请修改 /var/jb/Library/LaunchDaemons/re.frida.server.plist 并向 ProgramArguments 添加两个条目,如下所示

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <d>
        <key>Label</key>
        <string>re.frida.server</string>
        <key>Program</key>
        <string>/var/jb/usr/sbin/frida-server</string>
        <key>ProgramArguments</key>
        <array>
                <string>/var/jb/usr/sbin/frida-server</string>
                <string>-l</string>
                <string>0.0.0.0</string>
        </array>
        <key>UserName</key>
        <string>root</string>
        <key>POSIXSpawnType</key>
        <string>Interactive</string>
        <key>RunAtLoad</key>
        <true/>
        <key>KeepAlive</key>
        <true/>
        <key>ThrottleInterval</key>
        <integer>5</integer>
        <key>ExecuteAllowed</key>
        <true/>
</dict>
</plist>

安装完成后,Frida 服务器将自动以 root 权限运行,允许你轻松地将代码注入到任何进程中。

危险

在公共接口上暴露 frida-server 将允许连接到同一网络上的任何人将代码注入到设备上运行的任何进程中。 你应该只在受控的实验室环境中执行此操作。

在 iOS 上使用 Frida

通过 USB 连接你的设备,并通过运行 frida-ps 命令和 -U 标志来确保 Frida 正常工作。 这应该返回设备上运行的进程列表

$ frida-ps -U
PID  Name
---  ----------------
963  Mail
952  Safari
416  BTServer
422  BlueTool
791  CalendarWidget
451  CloudKeychainPro
239  CommCenter
764  ContactsCoreSpot
(...)

Frida 绑定

为了扩展脚本编写体验,Frida 提供了与 Python、C、NodeJS 和 Swift 等编程语言的绑定。

以 Python 为例,首先要注意的是,无需进一步的安装步骤。 在你的 Python 脚本中以 import frida 开始,你就可以开始了。 请看以下脚本,它只是运行了之前的 JavaScript 代码段

# frida_python.py
import frida

session = frida.get_usb_device().attach('com.android.chrome')

source = """
Java.perform(function () {
    var view = Java.use("android.view.View");
    var methods = view.class.getMethods();
    for(var i = 0; i < methods.length; i++) {
        console.log(methods[i].toString());
    }
});
"""

script = session.create_script(source)
script.load()

session.detach()

在这种情况下,运行 Python 脚本(python3 frida_python.py)与之前的示例具有相同的结果:它会将 android.view.View 类的所有方法打印到终端。 但是,你可能想使用 Python 中的数据。 使用 send 而不是 console.log 会将数据以 JSON 格式从 JavaScript 发送到 Python。 请阅读以下示例中的注释

# python3 frida_python_send.py
import frida

session = frida.get_usb_device().attach('com.android.chrome')

# 1. we want to store method names inside a list
android_view_methods = []

source = """
Java.perform(function () {
    var view = Java.use("android.view.View");
    var methods = view.class.getMethods();
    for(var i = 0; i < methods.length; i++) {
        send(methods[i].toString());
    }
});
"""

script = session.create_script(source)

# 2. this is a callback function, only method names containing "Text" will be appended to the list
def on_message(message, data):
    if "Text" in message['payload']:
        android_view_methods.append(message['payload'])

# 3. we tell the script to run our callback each time a message is received
script.on('message', on_message)

script.load()

# 4. we do something with the collected data, in this case we just print it
for method in android_view_methods:
    print(method)

session.detach()

这有效地过滤了方法,并仅打印包含字符串 "Text" 的方法

$ python3 frida_python_send.py
public boolean android.view.View.canResolveTextAlignment()
public boolean android.view.View.canResolveTextDirection()
public void android.view.View.setTextAlignment(int)
public void android.view.View.setTextDirection(int)
public void android.view.View.setTooltipText(java.lang.CharSequence)
...

最后,由你决定希望在哪里处理数据。 有时从 JavaScript 中进行操作会更方便,而在其他情况下,Python 将是最佳选择。 当然,你也可以使用 script.post 从 Python 向 JavaScript 发送消息。 有关 发送接收 消息的更多信息,请参阅 Frida 文档。