玩转Android10源码开发定制(六)修改内核源码绕过反调试检测

一、Android反调试   

  反调试在代码保护中扮演着非常重要的角色,虽然不能完全阻止攻击者,但是能加大攻击者的分析时间成本。目前绝大多数Android app都加固了,为了防止App被调试分析,加固功能中添加了各种反调试功能,比如:自己ptrace自己、检查函数执行时间、读取/proc/$pid/wchan或者/proc/$pid/task/$pid/wchan文件信息判断调试状态、读取/proc/$pid/stat或者/proc/$pid/task/$pid/stat文件信息判断调试状态、读取/proc/$pid/status或者/proc/$pid/task/$pid/status文件检测TracerPid、读取检测调试进程名、检测调试端口等等。网上关于Android 反调试的文章比较多,想了解更多Android反调试检测手段可以看看[https://bbs.pediy.com/thread-223324.htm]中总结的方法。本篇文章我们只讨论读取/proc/$pid/status 文件和/proc/$pid/wchan文件检测app是否处于被调试。

二、读取/proc/$pid检测原理分析

  1.读取/proc/$pid下的status文件检测被调试

   在Android 中调试状态下,linux内核会向/proc/$pid/status或者/proc/$pid/task/$pid/status 中写入进程状态信息。其中TracerPid 字段写入调试该进程的进程的的Pid。其中State字段中写入该进程当前处于的状态,取值如下之一:

R (running)", "S (sleeping)", "D (disk sleep)", "T (stopped)", "t(tracing stop)", "Z (zombie)",  "X (dead)"

当State为t (tracing stop)或者T (stopped)的时候,表示正被调试追踪。所以反调试的方法之一就是通过不断轮询读取/proc/$pid/status或者/proc/$pid/task/$pid/status文件检测检查TracerPid的值或者State的值,如果TracerPid非0说明该进程被调试;如果state值为t (tracing stop)或者T (stopped),说明被调试追踪。如下图所示:

 

玩转Android10源码开发定制(六)修改内核源码绕过反调试检测_第1张图片

      

   2.读取/proc/$pid/stat、/proc/$pid/task/$pid/stat检测被调试

    进程被调试状态下内核会向/proc/$pid/stat、/proc/$pid/task/$pid/stat文件中的第三个字段写入t标识。

        3.读取/proc/$pid/wchan、/proc/$pid/task/$pid/wchan

          wchan文件内容表示显示当进程sleep时,kernel当前运行的函数。若进程被调试,内核会往/proc/$pid/wchan、/proc/$pid/task/$pid/wchan文件中写入ptrace_stop信息。

     三、修改内核

         内核源码中和"二"中相关的信息代码位于内核/fs/proc目录中,如下图所示:

玩转Android10源码开发定制(六)修改内核源码绕过反调试检测_第2张图片

       1.修改State标识值

        该标识写入相关信息位于内核文件/fs/proc/array.c中,如下所示。

原代码内容:

static const char * const task_state_array[] = {
      "R (running)",    /*   0 */  "S (sleeping)",    /*   1 */  "D (disk sleep)",  /*   2 */  "T (stopped)",    /*   4 */  "t (tracing stop)",  /*   8 */  "X (dead)",    /*  16 */  "Z (zombie)",    /*  32 */};

我们需要把以上内容中的"t (tracing stop)"和"T (stopped)"替换为"S (sleeping)",不管App如何被调试,内核写入的都是正常状态来对抗反调试检测。修改之后的代码如下:

static const char * const task_state_array[] = {
      "R (running)",    /*   0 */  "S (sleeping)",    /*   1 */  "D (disk sleep)",  /*   2 */  ///ADD START  //"T (stopped)",    /*   4 */  "S (sleeping)",       /*   4 */  ///ADD END  /*  ///ADD START  //"t (tracing stop)",/*   8 */    */  "S (sleeping)",  /*   8 */  /*  ///ADD END  */  "X (dead)",    /*  16 */  "Z (zombie)",    /*  32 */};

 

2.修改TracerPid相关

          该标识写入相关信息位于内核文件/fs/proc/array.c中的task_state函数中,如下所示。

玩转Android10源码开发定制(六)修改内核源码绕过反调试检测_第3张图片

其中tpid就表示当前正在调试的进程Pid,我们将tpid永远修改为0。就可以绕过检测TracerPid。修改之后如下:

玩转Android10源码开发定制(六)修改内核源码绕过反调试检测_第4张图片

3.修改wchan文件相关的信息

    文件/proc/$pid/wchan、/proc/$pid/task/$pid/wchan内核写入相关代码路径位于:\fs\proc\base.c中,如下所示:

#ifdef CONFIG_KALLSYMS/* * Provides a wchan file via kallsyms in a proper one-value-per-file format. * Returns the resolved symbol.  If that fails, simply return the address. */static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,        struct pid *pid, struct task_struct *task){
      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_FSCREDS))      return 0;    else      return seq_printf(m, "%lu", wchan);  else    return seq_printf(m, "%s", symname);}#endif /* CONFIG_KALLSYMS */

将以上写入符号名称的地方,修改成过滤符号名称包含trace关键字,然后写入sys_epoll_wait。修改后如下所示:

#ifdef CONFIG_KALLSYMS/* * Provides a wchan file via kallsyms in a proper one-value-per-file format. * Returns the resolved symbol.  If that fails, simply return the address. */static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,        struct pid *pid, struct task_struct *task){
      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_FSCREDS))      return 0;    else      return seq_printf(m, "%lu", wchan);  else{
        ///ADD START    if(strstr(symname,"trace")){
              return seq_printf(m, "%s","sys_epoll_wait");    }    ///ADD END    return seq_printf(m, "%s", symname);  }}#endif /* CONFIG_KALLSYMS */

四、编译刷机

      修改保存之后,在Android源码根目录执行如下命令编译刷机包然后刷机:

source build/envsetup.shbrunch oneplus3-userdebug

 

关注公众号,及时获取文章更新:

你可能感兴趣的:(安卓10系统源码开发定制,android)