Android反调试——从源码入手
字数 1276 2025-08-22 22:47:30
Android反调试技术:从源码入手修改内核实现反反调试
前言
本教程将详细介绍如何通过修改Android内核源码来实现反反调试功能,主要针对常见的调试检测手段(如TracePid、进程状态等)进行修改。教程基于Android 6.0.1 (Marshmallow)和Nexus 5设备,但原理适用于其他Android版本和设备。
环境准备
硬件要求
- 建议使用Ubuntu 16.04系统(18.10也可用)
- 至少2GB内存
- Nexus 5设备(或其他可获取内核源码的设备)
Java环境搭建
-
下载JDK:
- 执行
javac命令获取最新JDK安装指令 - Java 6和7需要Oracle账号,从官网下载:
- jdk-6u45-linux-x64.bin
- jdk-7u80-linux-x64.tar.gz
- 执行
-
安装JDK:
mv jdk-6u45-linux-x64.bin /usr/lib/jvm/ mv jdk-7u80-linux-x64.tar.gz /usr/lib/jvm/ cd /usr/lib/jvm chmod +x jdk-6u45-linux-x64.bin ./jdk-6u45-linux-x64.bin tar -zxvf jdk-7u80-linux-x64.tar.gz -
创建切换脚本:
创建alternativeJava.sh文件:#!/bin/sh JAVAHOME=$1 if [ -d $JAVAHOME ];then sudo update-alternatives --install /usr/bin/java java $JAVAHOME/bin/java 300 sudo update-alternatives --install /usr/bin/javac javac $JAVAHOME/bin/javac 300 sudo update-alternatives --install /usr/bin/jar jar $JAVAHOME/bin/jar 300 sudo update-alternatives --install /usr/bin/javah javah $JAVAHOME/bin/javah 300 sudo update-alternatives --install /usr/bin/javap javap $JAVAHOME/bin/javap 300 else echo "Wrong input" exit 0 fi执行:
chmod +x alternativeJava.sh ./alternativeJava.sh /usr/lib/jvm/jdk1.7.0_80
获取内核源码
-
确定设备内核版本:
- 获取手机的
git short commit id(如cf10b7e)
- 获取手机的
-
下载源码:
git clone https://android.googlesource.com/kernel/msm.git # 或使用清华镜像 git clone https://aosp.tuna.tsinghua.edu.cn/kernel/msm.git -
检出特定分支:
cd msm git branch -r --contains <your short commit id> git checkout -b android-msm-hammerhead-3.4-marshmallow-mr3 origin/android-msm-hammerhead-3.4-marshmallow-mr3
安装交叉编译器
-
下载交叉编译器:
git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6 # 或清华镜像 git clone https://aosp.tuna.tsinghua.edu.cn/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6 -
设置环境变量:
- 临时设置:
export PATH=~/AndroidKernel/arm-eabi-4.6/bin:$PATH - 永久设置(添加到~/.bashrc):
export PATH=<交叉编译API存放的文件根目录>/arm-linux-androideabi-4.9/bin:$PATH source ~/.bashrc
- 临时设置:
修改内核源码
修改目标
-
/proc/[pid]/status中的关键字段:
TracerPid:调试器进程IDState:进程状态(T/t表示被跟踪)
-
/proc/[pid]/wchan:
- 调试状态下显示"ptrace_stop"
- 非调试状态下显示"ep_poll"
修改文件
-
修改msm/fs/proc/base.c:
- 定位
proc_pid_wchan函数(约268行) - 修改为:
static int proc_pid_wchan(struct task_struct *task, char *buffer) { unsigned long wchan; char symname[KSYM_NAME_LEN]; wchan = get_wchan(task); if (lookup_symbol_name(wchan, symname) < 0) if (!ptrace_may_access(task, PTRACE_MODE_READ)) return 0; else return sprintf(buffer, "%lu", wchan); else { // 关键修改:隐藏trace相关字符串 if(strstr(symname,"trace")) return sprintf(buffer, "%s", "sys_epoll_wait"); return sprintf(buffer, "%s", symname); } }
- 定位
-
修改msm/fs/proc/array.c:
- 修改
task_state_array(约134行):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 */ }; - 修改
seq_printf输出(约180行):seq_printf(m, "State:\t%s\n" "Tgid:\t%d\n" "Pid:\t%d\n" "PPid:\t%d\n" "TracerPid:\t%d\n" "Uid:\t%d\t%d\t%d\t%d\n" "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, 0, // 关键修改:强制TracerPid为0 cred->uid, cred->euid, cred->suid, cred->fsuid, cred->gid, cred->egid, cred->sgid, cred->fsgid);
- 修改
编译内核
-
配置编译环境:
export ARCH=arm export SUBARCH=arm cd msm make hammerhead_defconfig -
编译内核:
make ARCH=arm CROSS_COMPILE=arm-eabi- -j4- 如遇
kernel/timeconst.pl错误,修改:if (!defined(@val)) 改为 if (!@val)
- 如遇
-
获取编译结果:
编译完成后,内核镜像位于arch/arm/boot/zImage
制作和刷入boot.img
-
准备工具:
git clone https://github.com/pbatard/bootimg-tools.git make cd mkbootimg -
解包原始boot.img:
./unmkbootimg -i boot.img输出示例:
To rebuild this boot image, you can use the command: mkbootimg --base 0 --pagesize 2048 --kernel_offset 0x00008000 --ramdisk_offset 0x02900000 --second_offset 0x00f00000 --tags_offset 0x02700000 --cmdline 'console=ttyHSL0,115200,n8 androidboot.hardware=hammerhead user_debug=31 maxcpus=2 msm_watchdog_v2.enable=1' --kernel kernel --ramdisk ramdisk.cpio.gz -o boot.img -
重新打包:
- 用编译的zImage替换原kernel文件
- 使用上述命令重新打包(修改--kernel参数)
-
刷入设备:
adb reboot bootloader fastboot flash boot bootnew.img fastboot reboot
验证修改
-
检查/proc/[pid]/status:
TracerPid应始终显示0- 被调试进程的
State不应显示T或t
-
检查/proc/[pid]/wchan:
- 即使被调试也应显示"sys_epoll_wait"而非"ptrace_stop"
参考资源
通过以上步骤,我们成功修改了Android内核,使其隐藏了调试痕迹,实现了反反调试的功能。这种方法适用于安全研究和逆向工程场景,但请注意遵守相关法律法规。