frida-trace

本页为社区译文;如有疑义,请以英文原文为准。 英文原文

frida-trace 是一个用于动态跟踪函数调用的工具。

# Trace recv* and send* APIs in Safari, insert library names
# in logging
$ frida-trace --decorate -i "recv*" -i "send*" Safari

# Trace ObjC method calls in Safari
$ frida-trace -m "-[NSView drawRect:]" Safari

# Launch SnapChat on your iPhone and trace crypto API calls
$ frida-trace \
    -U \
    -f com.toyopagroup.picaboo \
    -I "libcommonCrypto*"

# Launch YouTube on your Android device and trace Java methods
# with “certificate” in their signature (s), ignoring case (i)
# and only searching in user-defined classes (u)
$ frida-trace \
    -U \
    -f com.google.android.youtube \
    --runtime=v8 \
    -j '*!*certificate*/isu'

# Trace all JNI functions in Samsung FaceService app on Android
$ frida-trace -U -i "Java_*" com.samsung.faceservice

# Trace a Windows process's calls to "mem*" functions in msvcrt.dll
$ frida-trace -p 1372 -i "msvcrt.dll!*mem*"

# Trace all functions matching "*open*" in the process except
# in msvcrt.dll
$ frida-trace -p 1372 -i "*open*" -x "msvcrt.dll!*open*"

# Trace an unexported function in libjpeg.so
$ frida-trace -p 1372 -a "libjpeg.so!0x4793c"

完整选项列表

$ frida-trace -h
usage: frida-trace [options] target

positional arguments:
  args                  extra arguments and/or target

options:
  -h, --help            show this help message and exit
  -D ID, --device ID    connect to device with the given ID
  -U, --usb             connect to USB device
  -R, --remote          connect to remote frida-server
  -H HOST, --host HOST  connect to remote frida-server on HOST
  --certificate CERTIFICATE
                        speak TLS with HOST, expecting CERTIFICATE
  --origin ORIGIN       connect to remote server with “Origin” header set to ORIGIN
  --token TOKEN         authenticate with HOST using TOKEN
  --keepalive-interval INTERVAL
                        set keepalive interval in seconds, or 0 to disable (defaults to -1 to auto-select based on transport)
  --p2p                 establish a peer-to-peer connection with target
  --stun-server ADDRESS
                        set STUN server ADDRESS to use with --p2p
  --relay address,username,password,turn-{udp,tcp,tls}
                        add relay to use with --p2p
  -f TARGET, --file TARGET
                        spawn FILE
  -F, --attach-frontmost
                        attach to frontmost application
  -n NAME, --attach-name NAME
                        attach to NAME
  -N IDENTIFIER, --attach-identifier IDENTIFIER
                        attach to IDENTIFIER
  -p PID, --attach-pid PID
                        attach to PID
  -W PATTERN, --await PATTERN
                        await spawn matching PATTERN
  --stdio {inherit,pipe}
                        stdio behavior when spawning (defaults to “inherit”)
  --aux option          set aux option when spawning, such as “uid=(int)42” (supported types are: string, bool, int)
  --realm {native,emulated}
                        realm to attach in
  --runtime {qjs,v8}    script runtime to use
  --debug               enable the Node.js compatible script debugger
  --squelch-crash       if enabled, will not dump crash report to console
  -O FILE, --options-file FILE
                        text file containing additional command line options
  --version             show program's version number and exit
  -I MODULE, --include-module MODULE
                        include MODULE
  -X MODULE, --exclude-module MODULE
                        exclude MODULE
  -i FUNCTION, --include FUNCTION
                        include [MODULE!]FUNCTION
  -x FUNCTION, --exclude FUNCTION
                        exclude [MODULE!]FUNCTION
  -a MODULE!OFFSET, --add MODULE!OFFSET
                        add MODULE!OFFSET
  -T INCLUDE_IMPORTS, --include-imports INCLUDE_IMPORTS
                        include program's imports
  -t MODULE, --include-module-imports MODULE
                        include MODULE imports
  -m OBJC_METHOD, --include-objc-method OBJC_METHOD
                        include OBJC_METHOD
  -M OBJC_METHOD, --exclude-objc-method OBJC_METHOD
                        exclude OBJC_METHOD
  -y SWIFT_FUNC, --include-swift-func SWIFT_FUNC
                        include SWIFT_FUNC
  -Y SWIFT_FUNC, --exclude-swift-func SWIFT_FUNC
                        exclude SWIFT_FUNC
  -j JAVA_METHOD, --include-java-method JAVA_METHOD
                        include JAVA_METHOD
  -J JAVA_METHOD, --exclude-java-method JAVA_METHOD
                        exclude JAVA_METHOD
  -s DEBUG_SYMBOL, --include-debug-symbol DEBUG_SYMBOL
                        include DEBUG_SYMBOL
  -q, --quiet           do not format output messages
  -d, --decorate        add module name to generated onEnter log statement
  -S PATH, --init-session PATH
                        path to JavaScript file used to initialize the session
  -P PARAMETERS_JSON, --parameters PARAMETERS_JSON
                        parameters as JSON, exposed as a global named 'parameters'
  -o OUTPUT, --output OUTPUT
                        dump messages to file
  --ui-port UI_PORT     the TCP port to serve the UI on

-U, –usb:连接 USB 设备

此选项指示 frida-trace 在通过主机 USB 接口连接的远程设备上执行跟踪。

例如:你想从 Windows 主机跟踪 Android 设备上运行的应用程序。指定 -U / --usb 后,frida-trace 会完成在主机与远程设备之间传输全部数据所需的工作, 并相应地执行跟踪。

将 frida-server 二进制文件复制到远程设备

跟踪远程设备时,请记得将 适用于目标平台的 frida-server 二进制文件 复制到远程设备。复制完成后,请确保先运行 frida-server 二进制文件,再开始跟踪会话。

例如,要跟踪远程 Android 应用,可以将 “frida-server-12.8.0-android-arm”二进制文件复制到 Android 的 /data/local/tmp 目录。然后通过 adb shell 在后台运行该服务 (例如“frida-server-12.8.0-android-arm &”)。

-O:通过文本文件传递命令行选项

使用此选项,可以通过一个或多个文本文件传入任意数量的命令行选项。文本文件中的选项 可以分布在一行或多行中,每行可包含任意数量的选项,也可以包含其他 -O 命令选项。

此功能适合处理大量命令行选项,也能解决命令行长度超过操作系统最大限制的问题。

例如:

$ frida-trace -p 9753 --decorate -O additional-options.txt

其中 additional-options.txt 的内容为:

-i "gdi32full.dll!ExtTextOutW"
-S core.js -S ms-windows.js
-O module-offset-options.txt

而 module-offset-options.txt 的内容为:

-a "gdi32full.dll!0x3918DC" -a "gdi32full.dll!0xBE7458"
-a "gdi32full.dll!0xBF9904"

-I, -X:包含/排除模块

借助这些选项,只需一个选项就能包含或排除某个特定模块(例如 .so、.dll)中的 所有函数。选项接受用于匹配一个或多个模块的文件名 glob 模式。任何匹配该 glob 模式的模块都会被整体包含或排除。

frida-trace 会为 -I 选项匹配到的每个函数生成一个 JavaScript 处理程序文件。

要在包含整个模块后排除特定函数,请参阅 -x 选项。

-i, -x:包含/排除函数(基于 glob)

借助这些选项,你可以按需包含或排除匹配的函数。它们十分灵活,粒度范围从所有模块中的 所有函数,一直到特定模块中的单个函数。

frida-trace 会为 -i 选项匹配到的每个函数生成一个 JavaScript 处理程序文件。

-i / -x 选项在语法上与对应的大写选项不同:它们接受以下任意形式 (MODULE 和 FUNCTION 均为 glob 模式):

- MODULE!FUNCTION
- FUNCTION
- !FUNCTION
- MODULE!

以下是一些示例及其说明:

选项值 说明
-i “msvcrt.dll!cpy” 仅匹配 msvcrt.dll 中名称包含“cpy”的所有函数
-i “free” 匹配所有模块中名称包含“free”的所有函数
-i “!free” 与 -i “free” 完全相同
-i “gdi32.dll!” 跟踪 gdi32.dll 中的所有函数(与 -I “gdi32.dll” 完全相同)
frida-trace 的工作集以及包含和排除操作的顺序

frida-trace 内部有一个“工作集”概念,即一组会在运行时跟踪其处理程序的 “module:function”对。工作集的内容可以通过包含/排除命令行选项 (-I / -X / -i / -x)更改。

必须理解,包含/排除选项的顺序非常重要。每个此类选项都会作用于工作集的当前状态, 不同的选项排列顺序可能产生不同的结果。换句话说,包含/排除选项是过程式的 (即顺序会影响结果),而非单纯的声明式选项。

例如,假设我们希望跟踪某个运行中进程里所有模块中的全部“str*”和“mem*”函数。 在本例中,这些函数存在于三个模块中:ucrtbase.dll、ntdll.dll 和 msvcrt.dll。 不过,为了减少干扰,我们不希望跟踪 msvcrt.dll 模块中的任何函数。

下面将说明三种不同的命令行选项顺序,并展示它们如何产生不同结果。

  • -i "str*" -i "mem*" -X "msvcrt.dll"
    • '-i "str*"'
      在 3 个模块中匹配 80 个函数, 工作集包含 80 个条目
    • '-i "mem*"'
      在 3 个模块中匹配 18 个函数, 工作集包含 98 个条目
    • '-X "msvcrt.dll"'
      移除来自 msvcrt.dll 的 28 个“str”函数和 6 个“mem”函数,最终工作集包含 64 个条目。
  • -i "str*" -X "msvcrt.dll" -i "mem*"
    • '-i "str*"'
      在 3 个模块中匹配 80 个函数, 工作集包含 80 个条目
    • '-X "msvcrt.dll"'
      移除来自 msvcrt.dll 的 28 个“str”函数,工作集包含 52 个条目。
    • '-i "mem*"'
      在 3 个模块(包括 msvcrt.dll)中 匹配 18 个函数,最终工作集包含 70 个条目
  • -X "msvcrt.dll" -i "str*" -i "mem*"
    • '-X "msvcrt.dll"'
      尝试移除来自 msvcrt.dll 的 28 个“str”函数和 6 个“mem”函数。由于工作集为空,没有任何内容可移除, 工作集仍为 0 个条目。
    • '-i "str*"'
      在 3 个模块中匹配 80 个函数, 工作集包含 80 个条目
    • '-i "mem*"'
      在 3 个模块中匹配 18 个函数, 最终工作集包含 98 个条目

-a:包含函数(基于偏移量)

此选项可以跟踪名称未由所属模块导出的函数(例如静态 C/C++ 函数)。只要你知道函数入口点的 绝对偏移量,名称未导出就不应妨碍你跟踪此类函数。

示例:-a "libjpeg.so!0x4793c"

在此示例中,选项值同时给出了模块的完整名称(即 libjpeg.so)以及函数入口点在模块内的 十六进制偏移量(0x4793c)。

frida-trace 会为 -a 选项匹配到的每个函数生成一个 JavaScript 处理程序文件。

-P:使用可全局访问的 JSON 对象初始化 frida-trace 会话

此选项可以将一个 JSON 对象赋值给全局变量 parameters。处理程序可以访问这个全局变量, 因此,你可以通过修改命令行中传给 -P 的值来动态改变处理程序的行为。

传入的 JSON 对象可以任意复杂或庞大,只要它是有效的 JSON 即可。

示例

在一个会话中,你正在跟踪许多函数。有时你希望所有处理程序都输出进程 ID。 使用 `-P` 选项,可以让处理程序自行决定是否输出进程 ID。

首先,确定一个 JSON 对象格式,用来告知处理程序是否应显示进程 ID。这里采用以下格式:

-P '{"displayPid": true}'

请注意,这种写法适用于 Linux(即命令行中可以同时使用单引号和双引号)。在 Windows 下 只能使用双引号,因此需要通过输入两个双引号来转义内部的双引号,如下所示:

-P "{""displayPid"": true}"

Frida-trace 会把 JSON 对象赋给全局 JavaScript 变量“parameters”。此时, 处理程序可以检查 parameters.displayPid 变量,以决定是否输出进程 ID:

{ onEnter(log, args, state) { log('memcpy() [msvcrt.dll]'); if (parameters.displayPid) { log(`Process ID: ${Process.id}`); } }, onLeave(log, retval, state) { } }

-S:使用 JavaScript 代码初始化 frida-trace 会话

此选项会执行你选择的一个或多个 JavaScript 代码文件,以初始化 frida-trace 会话。这些文件 可以声明全局可见的函数,并向全局“state”对象添加任意数据。当“state”对象传递给任一 处理程序时,你可以立即访问会话初始化期间保存到其中的所有内容。

这项强大功能可用于在会话开始前初始化 frida-trace 运行环境,也可用于共享经过精心调试的 JavaScript 函数和数据,供不同处理程序和开发项目调用。

有关如何使用这项强大功能的详细说明,请参阅 会话初始化入门指南。

-d, –decorate:在跟踪日志中添加模块名称

--decorate 选项适用于 frida-trace 自动生成 JavaScript 处理程序脚本的场景。 默认情况下,处理程序的 onEnter 函数如下所示:

onEnter(log, args, state) { log('memcpy()'); },

它的缺点是:如果多个模块中存在同名函数,就很难区分不同函数的跟踪记录。 --decorate 功能会指示 frida-trace 在默认的 onEnter 跟踪语句中插入模块名称:

onEnter(log, args, state) { log('memcpy() [msvcrt.dll]'); },