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环境搭建

  1. 下载JDK

    • 执行javac命令获取最新JDK安装指令
    • Java 6和7需要Oracle账号,从官网下载:
      • jdk-6u45-linux-x64.bin
      • jdk-7u80-linux-x64.tar.gz
  2. 安装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
    
  3. 创建切换脚本
    创建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
    

获取内核源码

  1. 确定设备内核版本

    • 获取手机的git short commit id(如cf10b7e)
  2. 下载源码

    git clone https://android.googlesource.com/kernel/msm.git
    # 或使用清华镜像
    git clone https://aosp.tuna.tsinghua.edu.cn/kernel/msm.git
    
  3. 检出特定分支

    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
    

安装交叉编译器

  1. 下载交叉编译器

    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
    
  2. 设置环境变量

    • 临时设置:
      export PATH=~/AndroidKernel/arm-eabi-4.6/bin:$PATH
      
    • 永久设置(添加到~/.bashrc):
      export PATH=<交叉编译API存放的文件根目录>/arm-linux-androideabi-4.9/bin:$PATH
      source ~/.bashrc
      

修改内核源码

修改目标

  1. /proc/[pid]/status中的关键字段

    • TracerPid:调试器进程ID
    • State:进程状态(T/t表示被跟踪)
  2. /proc/[pid]/wchan

    • 调试状态下显示"ptrace_stop"
    • 非调试状态下显示"ep_poll"

修改文件

  1. 修改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);
        }
      }
      
  2. 修改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);
      

编译内核

  1. 配置编译环境

    export ARCH=arm
    export SUBARCH=arm
    cd msm
    make hammerhead_defconfig
    
  2. 编译内核

    make ARCH=arm CROSS_COMPILE=arm-eabi- -j4
    
    • 如遇kernel/timeconst.pl错误,修改:
      if (!defined(@val)) 改为 if (!@val)
      
  3. 获取编译结果
    编译完成后,内核镜像位于arch/arm/boot/zImage

制作和刷入boot.img

  1. 准备工具

    git clone https://github.com/pbatard/bootimg-tools.git
    make
    cd mkbootimg
    
  2. 解包原始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
    
  3. 重新打包

    • 用编译的zImage替换原kernel文件
    • 使用上述命令重新打包(修改--kernel参数)
  4. 刷入设备

    adb reboot bootloader
    fastboot flash boot bootnew.img
    fastboot reboot
    

验证修改

  1. 检查/proc/[pid]/status

    • TracerPid应始终显示0
    • 被调试进程的State不应显示T或t
  2. 检查/proc/[pid]/wchan

    • 即使被调试也应显示"sys_epoll_wait"而非"ptrace_stop"

参考资源

  1. Ubuntu安装JDK
  2. Android内核编译指南
  3. Android镜像使用帮助
  4. bootimg-tools工具

通过以上步骤,我们成功修改了Android内核,使其隐藏了调试痕迹,实现了反反调试的功能。这种方法适用于安全研究和逆向工程场景,但请注意遵守相关法律法规。

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 : 创建切换脚本 : 创建 alternativeJava.sh 文件: 执行: 获取内核源码 确定设备内核版本 : 获取手机的 git short commit id (如cf10b7e) 下载源码 : 检出特定分支 : 安装交叉编译器 下载交叉编译器 : 设置环境变量 : 临时设置: 永久设置(添加到~/.bashrc): 修改内核源码 修改目标 /proc/[ pid]/status中的关键字段 : TracerPid :调试器进程ID State :进程状态(T/t表示被跟踪) /proc/[ pid]/wchan : 调试状态下显示"ptrace_ stop" 非调试状态下显示"ep_ poll" 修改文件 修改msm/fs/proc/base.c : 定位 proc_pid_wchan 函数(约268行) 修改为: 修改msm/fs/proc/array.c : 修改 task_state_array (约134行): 修改 seq_printf 输出(约180行): 编译内核 配置编译环境 : 编译内核 : 如遇 kernel/timeconst.pl 错误,修改: 获取编译结果 : 编译完成后,内核镜像位于 arch/arm/boot/zImage 制作和刷入boot.img 准备工具 : 解包原始boot.img : 输出示例: 重新打包 : 用编译的zImage替换原kernel文件 使用上述命令重新打包(修改--kernel参数) 刷入设备 : 验证修改 检查/proc/[ pid]/status : TracerPid 应始终显示0 被调试进程的 State 不应显示T或t 检查/proc/[ pid]/wchan : 即使被调试也应显示"sys_ epoll_ wait"而非"ptrace_ stop" 参考资源 Ubuntu安装JDK Android内核编译指南 Android镜像使用帮助 bootimg-tools工具 通过以上步骤,我们成功修改了Android内核,使其隐藏了调试痕迹,实现了反反调试的功能。这种方法适用于安全研究和逆向工程场景,但请注意遵守相关法律法规。