跳过内容

MASTG-TECH-0032: 执行追踪

除了用于调试之外,jdb 命令行工具还提供基本的执行跟踪功能。要从一开始就跟踪应用程序,您可以使用 Android 的“等待调试器”功能或 kill -STOP 命令暂停应用程序,并附加 jdb 以在任何初始化方法上设置延迟方法断点。一旦到达断点,使用 trace go methods 命令激活方法跟踪并恢复执行。 jdb 将从那时起转储所有方法入口和出口。

$ adb forward tcp:7777 jdwp:7288
$ { echo "suspend"; cat; } | jdb -attach localhost:7777
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
> All threads suspended.
> stop in com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>()
Deferring breakpoint com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>().
It will be set after the class is loaded.
> resume
All threads resumed.M
Set deferred breakpoint com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>()

Breakpoint hit: "thread=main", com.acme.bob.mobile.android.core.BobMobileApplication.<clinit>(), line=44 bci=0
main[1] trace go methods
main[1] resume
Method entered: All threads resumed.

Dalvik Debug Monitor Server (DDMS) 是 Android Studio 附带的 GUI 工具。它看起来可能不太起眼,但它的 Java 方法跟踪器是您可以拥有的最棒的工具之一,并且对于分析混淆的字节码来说是必不可少的。

然而,DDMS 有点令人困惑;它可以以多种方式启动,并且将根据方法的跟踪方式启动不同的跟踪查看器。有一个名为“Traceview”的独立工具,以及 Android Studio 中的内置查看器,它们都提供了不同的方式来浏览跟踪。您通常会使用 Android studio 的内置查看器,它为您提供所有方法调用的可缩放分层时间线。但是,独立工具也很有用,它有一个配置文件面板,显示每种方法所花费的时间以及每种方法的父项和子项。

要在 Android Studio 中记录执行跟踪,请打开 GUI 底部的 Android 选项卡。在列表中选择目标进程,然后单击左侧的小 秒表 按钮。这将开始录制。完成后,单击同一按钮停止录制。集成的跟踪视图将打开并显示记录的跟踪。您可以使用鼠标或触控板滚动和缩放时间线视图。

执行跟踪也可以在独立的 Android Device Monitor 中记录。设备监视器可以在 Android Studio 中启动(工具 -> Android -> Android Device Monitor),也可以通过 shell 使用 ddms 命令启动。

要开始记录跟踪信息,请在 Devices 选项卡中选择目标进程,然后单击 Start Method Profiling。单击 停止 按钮停止录制,之后 Traceview 工具将打开并显示记录的跟踪。单击配置文件面板中的任何方法都会在时间线面板中突出显示所选方法。

DDMS 还提供了一个方便的堆转储按钮,可以将进程的 Java 堆转储到 .hprof 文件。 Android Studio 用户指南包含有关 Traceview 的更多信息。

跟踪系统调用

在 OS 层次结构中向下移动一级,您会到达需要 Linux 内核权限的特权函数。这些函数通过系统调用接口提供给普通进程。检测和拦截对内核的调用是粗略了解用户进程正在做什么的有效方法,通常也是停用底层篡改防御的最有效方法。

Strace 是一个标准的 Linux 实用程序,默认情况下未包含在 Android 中,但可以通过 Android NDK 轻松地从源代码构建。它监视进程和内核之间的交互,是监视系统调用的一种非常方便的方式。但是,有一个缺点:由于 strace 依赖于 ptrace 系统调用来附加到目标进程,因此一旦反调试措施生效,它将停止工作。

如果 设置 > 开发者选项 中的“等待调试器”功能不可用,您可以使用 shell 脚本启动进程并立即附加 strace(不是一个优雅的解决方案,但它可以工作)

while true; do pid=$(pgrep 'target_process' | head -1); if [[ -n "$pid" ]]; then strace -s 2000 - e "!read" -ff -p "$pid"; break; fi; done

Ftrace

Ftrace 是一个直接构建到 Linux 内核中的跟踪实用程序。在 root 设备上,ftrace 可以比 strace 更透明地跟踪内核系统调用(strace 依赖于 ptrace 系统调用来附加到目标进程)。

方便的是,Lollipop 和 Marshmallow 上的股票 Android 内核都包含 ftrace 功能。可以使用以下命令启用该功能

echo 1 > /proc/sys/kernel/ftrace_enabled

/sys/kernel/debug/tracing 目录包含与 ftrace 相关的所有控制和输出文件。在此目录中找到以下文件

  • available_tracers:此文件列出了编译到内核中的可用跟踪器。
  • current_tracer:此文件设置或显示当前跟踪器。
  • tracing_on:将“1”回显到此文件中以允许/启动环形缓冲区更新。回显“0”将阻止进一步写入环形缓冲区。

KProbes

KProbes 接口提供了一种更强大的工具来检测内核:它允许您将探针插入内核内存中(几乎)任意代码地址。 KProbes 在指定的地址插入一个断点指令。一旦达到断点,控制权将传递给 KProbes 系统,然后该系统执行用户定义的处理函数和原始指令。除了非常适合函数跟踪之外,KProbes 还可以实现类似于 rootkit 的功能,例如文件隐藏。

Jprobes 和 Kretprobes 是其他基于 KProbes 的探针类型,允许钩住函数入口和出口。

股票 Android 内核没有可加载模块支持,这是一个问题,因为 Kprobes 通常部署为内核模块。编译 Android 内核时采用的严格内存保护是另一个问题,因为它阻止了修补内核内存的某些部分。 Elfmaster 的系统调用钩子方法会导致股票 Lollipop 和 Marshmallow 上的 Kernel panic,因为 sys_call_table 是不可写的。但是,您可以通过编译自己的更宽松的 Kernel(稍后会详细介绍)在沙箱中使用 KProbes。