使用 Docker 编译 AOSP 源码绕过 Android 反调试
· 3 分钟阅读 · @admin

前言
在研究 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.shextract-lge-hammerhead.shextract-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 容器化技术,我们大大简化了编译环境的配置过程。通过修改内核源码,我们成功绕过了常见的反调试检测手段,包括:
- ptrace 检测绕过:通过修改
proc_pid_wchan函数,将 trace 相关函数伪装成普通系统调用 - TracerPid 检测绕过:将 TracerPid 强制设置为 0
- 进程状态检测绕过:将 traced 状态伪装成 sleeping 状态
这种方法适用于安全研究和逆向工程学习,可以帮助研究人员更好地分析 Android 应用的行为。

