8-BitQuest
菜单
[逆向工程]

使用 Docker 编译 AOSP 源码绕过 Android 反调试

· 3 分钟阅读 · @admin

使用 Docker 编译 AOSP 源码绕过 Android 反调试 像素封面

前言

在研究 Android 逆向工程时,常常会遇到应用的反调试机制。通过编译定制化的 Android 系统,我们可以从源码层面绕过这些检测。然而,传统的 AOSP 编译过程存在诸多痛点:不同 Android 版本需要不同的 JDK 版本和 Ubuntu 版本,环境配置极其繁琐,光是搭建编译环境就可能耗费大量时间。

幸运的是,Docker 技术为我们提供了优雅的解决方案。使用 AOSP Docker 镜像,我们可以跳过复杂的环境配置,直接使用预先配置好的编译环境。本文将介绍如何使用 Docker 编译 AOSP 源码,并通过修改内核源码来绕过常见的反调试检测。

推荐使用 Linux 系统(Debian 或 Ubuntu 均可)安装 Docker。虽然 Windows 也支持 Docker,但在实际使用中可能会遇到一些兼容性问题。

环境准备

1. 磁盘空间要求

编译 AOSP 需要充足的磁盘空间,建议至少分配 100GB 以上。如果您的 Linux 虚拟机磁盘空间不足,可以通过添加虚拟硬盘来扩容。对于 VMware 虚拟机用户,可以参考这篇文章为虚拟机添加额外的硬盘。

2. 安装 Docker

Debian 默认软件源中不包含 Docker,需要添加 backports 源。编辑 /etc/apt/sources.list 文件,添加以下内容:

deb http://http.debian.net/debian jessie-backports main

然后更新软件包列表并安装 Docker:

apt-get update
apt-get install docker.io

编译 AOSP 源码

1. 启动 Docker 服务

在开始编译之前,必须先启动 Docker 服务,否则后续步骤会报错:

/etc/init.d/docker start

2. 设置环境变量

设置 AOSP_VOL 环境变量,指定存放源码的路径。如果您使用的是新添加的硬盘,请将路径设置为挂载点。本文示例使用 /Android 目录:

export AOSP_VOL=/Android

3. 下载编译脚本

下载 AOSP Docker 的 Wrapper 脚本。本文以编译 KitKat(Android 4.4)为例,如需编译其他版本,请参考 docker-aosp 项目。该脚本针对国内网络环境进行了优化,使用清华大学的镜像源,下载速度更快。

curl -O https://raw.githubusercontent.com/tiann/docker-aosp/master/tests/build-kitkat.sh

4. 执行编译

运行下载的脚本开始编译。该脚本会自动完成以下操作:

  • 下载 Docker 镜像
  • 下载 Android 源码到 AOSP_VOL 指定的路径
  • 启动编译过程
sh ./build-kitkat.sh

编译完成后,系统将使用默认的内核。为了绕过反调试检测,我们需要修改并重新编译内核。

修改并编译内核

1. 克隆内核源码

本文以 Nexus 5 为例,该设备对应的内核源码仓库为 kernel/msm,设备代号为 hammerhead。

首先在源码目录下创建 kernel 文件夹并克隆内核源码:

cd /Android/aosp
mkdir kernel
cd kernel
git clone https://aosp.tuna.tsinghua.edu.cn/kernel/msm.git

2. 切换到对应的分支

进入克隆的源码目录,查看所有可用分支:

cd msm
git branch -a

找到包含 hammerhead 的分支名称,切换到对应的 KitKat 分支:

git checkout remotes/origin/android-msm-hammerhead-3.4-kitkat-mr1

3. 修改内核源码

为了绕过常见的反调试检测,需要修改以下两个文件:

3.1 修改 kernel/msm/fs/proc/base.c

找到 proc_pid_wchan 函数,修改如下部分:

// 省略其他代码
else {
    if (strstr(symname, "trace")) {
        return sprintf(buffer, "%s", "sys_epoll_wait");
    }
    return sprintf(buffer, "%s", symname);
}

修改说明:该修改会将包含 “trace” 的函数名伪装成 sys_epoll_wait,从而绕过对 ptrace 等跟踪函数的检测。

3.2 修改 kernel/msm/fs/proc/array.c

修改一:在 task_state 函数中,将 TracerPid 设置为 0:

"Gid:\t%d\t%d\t%d\t%d\n",
    get_task_state(p),
    task_tgid_nr_ns(p, ns),
    pid_nr_ns(pid, ns),
    ppid, /*tpid*/0,  // 将 TracerPid 设置为 0
    cred->uid, cred->euid, cred->suid, cred->fsuid,
    cred->gid, cred->egid, cred->sgid, cred->fsgid);

修改二:修改 task_state_array 数组,将 traced 状态伪装成 sleeping:

static const char * const task_state_array[] = {
    "R (running)",        /*   0 */
    "S (sleeping)",       /*   1 */
    "D (disk sleep)",     /*   2 */
    "S (sleeping)",       /*   4 - 原本是 T (stopped) */
    "S (sleeping)",       /*   8 - 原本是 t (tracing stop) */
    "Z (zombie)",         /*  16 */
    "X (dead)",           /*  32 */
    "x (dead)",           /*  64 */
    "K (wakekill)",       /* 128 */
    "W (waking)",         /* 256 */
};

修改说明:将 traced 状态伪装成 sleeping 状态,使反调试检测无法通过进程状态判断是否被调试。

4. 创建编译脚本

在内核源码目录 /Android/aosp/kernel/msm 下创建编译脚本 run.sh:

export PATH='/Android/aosp/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin':$PATH
export ARCH=arm
export SUBARCH=arm
export CROSS_COMPILE=arm-eabi-
make hammerhead_defconfig
make -j4

说明:

  • PATH 变量指定了交叉编译工具链的路径
  • -j4 表示使用 4 个线程并行编译,可根据 CPU 核心数调整

5. 执行内核编译

运行编译脚本:

sh run.sh

编译成功后,会看到如下输出:

CALL    scripts/checksyscalls.sh
CHK     include/generated/compile.h
Kernel: arch/arm/boot/Image is ready
LD      arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
CAT     arch/arm/boot/zImage-dtb
Kernel: arch/arm/boot/zImage-dtb is ready

6. 替换内核文件

编译成功后,在 /Android/aosp/kernel/msm/arch/arm/boot 目录下会生成 zImage-dtb 文件,这是 Nexus 5 的内核镜像文件。

将其复制到设备内核目录,覆盖原有文件:

cp /Android/aosp/kernel/msm/arch/arm/boot/zImage-dtb \
   /Android/aosp/device/lge/hammerhead-kernel/zImage-dtb

下载硬件驱动

1. 下载驱动文件

要将系统刷入真机,还需要下载三个硬件驱动包。访问 Google Drivers 页面,搜索 Nexus 5 并找到对应的系统版本。

以 Android 4.4.4 (KTU84P) 为例:

Nexus 5 (GSM/LTE) binaries for Android 4.4.4 (KTU84P)

Hardware Component Company Download SHA-256 Checksum
NFC, Bluetooth, Wi-Fi Broadcom Link f258605e24c9c3d4e78c9af934f3516a4f8d3410da697005fad42cad36c5ed5c
Camera, Sensors, Audio LG Link fc72704e0fba9c51c6505ae009e474570de27ee8565d51483368d8dae6c0f44e
Graphics, GSM, Camera, GPS, Sensors, Media, DSP, USB Qualcomm Link 8603d85ad511346d65c27c3747919da280523b86d55a39dfce657a4ca1b0685b

2. 解压并安装驱动

下载完成后,将三个驱动文件解压到 /Android/aosp 目录,会得到以下脚本文件:

  • extract-broadcom-hammerhead.sh
  • extract-lge-hammerhead.sh
  • extract-qcom-hammerhead.sh

分别执行这些脚本:

sh extract-broadcom-hammerhead.sh
sh extract-lge-hammerhead.sh
sh extract-qcom-hammerhead.sh

执行过程中会不断显示许可协议,按回车键继续,最后会出现如下提示:

Type "I ACCEPT" if you agree to the terms of the license:

输入 I ACCEPT 并回车,即可完成驱动安装。

3. 重新编译系统

安装驱动后,需要重新编译 AOSP,将驱动整合到系统中。这次编译会很快,因为大部分文件已经编译完成:

sh ./build-kitkat.sh

刷入设备

1. 解锁 Bootloader

在刷机之前,必须先解锁 Bootloader,否则无法刷入自定义系统。

对于 Nexus 5,进入 Bootloader 模式的方法是:同时按住音量下键 + 音量上键 + 电源键,直到出现 Bootloader 界面。

使用 USB 连接手机和电脑,执行以下命令解锁:

fastboot oem unlock

注意:解锁会清除手机所有数据,请提前备份重要信息。

2. 刷入系统

编译成功后,系统镜像文件保存在 /Android/aosp/out/target/product/hammerhead 目录。

执行以下命令刷入系统:

cd /Android/aosp/out/target/product/hammerhead
adb reboot bootloader
fastboot -w flashall

命令说明:

  • adb reboot bootloader:重启设备进入 Bootloader 模式
  • fastboot -w flashall:刷入所有镜像文件,-w 参数会清除用户数据

刷机完成后,设备会自动重启,首次启动可能需要较长时间,请耐心等待。

总结

本文介绍了使用 Docker 编译 AOSP 源码并绕过 Android 反调试检测的完整流程。通过 Docker 容器化技术,我们大大简化了编译环境的配置过程。通过修改内核源码,我们成功绕过了常见的反调试检测手段,包括:

  1. ptrace 检测绕过:通过修改 proc_pid_wchan 函数,将 trace 相关函数伪装成普通系统调用
  2. TracerPid 检测绕过:将 TracerPid 强制设置为 0
  3. 进程状态检测绕过:将 traced 状态伪装成 sleeping 状态

这种方法适用于安全研究和逆向工程学习,可以帮助研究人员更好地分析 Android 应用的行为。

参考资料

更多文章