玩转Android10源码开发定制(七)修改ptrace绕过反调试

一、安卓10中ptrace介绍

 
   1.源码位置追踪

      在Android10中,ptrace函数定义文件路径为:

 bionic/libc/include/sys/ptrace.h

    函数原型定义如下:

long ptrace(int __request, ...);

        ptrace函数实现文件路径为:

 bionic/libc/bionic/ptrace.cpp

          

    函数实现代码如下:

long ptrace(int req, ...) {
   
     bool is_peek = (req == PTRACE_PEEKUSR || req == PTRACE_PEEKTEXT || req == PTRACE_PEEKDATA);  long peek_result;
  va_list args;  va_start(args, req);  pid_t pid = va_arg(args, pid_t);  void* addr = va_arg(args, void*);  void* data;  if (is_peek) {
   
       data = &peek_result;  } else {
   
       data = va_arg(args, void*);  }  va_end(args);  //最终是调用__ptrace函数  long result = __ptrace(req, pid, addr, data);  if (is_peek && result == 0) {
   
       return peek_result;  }  return result;}

    从ptrace实现代码可以看到最终调用的是__ptrace函数。经过代码追踪__ptrace函数是通过不同平台的汇编实现,最终调用__NR_ptrace系统调用。

   Android中arm平台__ptrace实现代码文件路径:

bionic/libc/arch-arm/syscalls/__ptrace.S

实现代码如下:​​​​​​​

#include <private/bionic_asm.h>
ENTRY(__ptrace)    mov     ip, r7    .cfi_register r7, ip    ldr     r7, =__NR_ptrace    swi     #0    mov     r7, ip    .cfi_restore r7    cmn     r0, #(MAX_ERRNO + 1)    bxls    lr    neg     r0, r0    b       __set_errno_internalEND(__ptrace)

      

      Android中arm64平台__ptrace实现代码文件路径:

 bionic/libc/arch-arm64/syscalls/__ptrace.S

      实现代码如下:


#include <private/bionic_asm.h>

ENTRY(__ptrace)
    mov     x8, __NR_ptrace
    svc     #0

    cmn     x0, #(MAX_ERRNO + 1)
    cneg    x0, x0, hi
    b.hi    __set_errno_internal

    ret
END(__ptrace)
.hidden __ptrace

2.功能作用  

     ptrace可以让一个进程监视和控制另一个进程的执行,并且修改被监视进程的内存、寄存器等,主要应用于调试器的断点调试、系统调用跟踪等。比如安卓系统提供的strace工具,可以跟踪app所有执行的系统调用,如下所示:

图片

   在Android app保护中,ptrace被广泛用于反调试。一个进程只能被ptrace一次,如果先调用了ptrace方法,那就可以防止别人调试我们的程序。这就是传说中的先占坑。比如在JNI_onLoad中调用以下代码来先占坑:

    if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
   
           LOGD("I am ptraced");        exit(0);    }else{
   
           LOGD("ptrace success");    }

   也可以使用多进程,ptrace父进程来检测是否被调试,网上参考的代码,如下:

static void anti_ptrace(){
   
       pid_t child;    child = fork();    if (child)    {
   
           //等待子进程退出        wait(NULL);    }    else    {
   
           // 获取父进程的pid        pid_t parent = getppid();        LOGD("ptrace attach start");        // ptrace附加父进程        if (ptrace(PTRACE_ATTACH, parent, 0, 0) < 0)        {
   
               LOGD("ptrace attach failure");            //attach父进程失败,说明被调试了,进入死循环,也可以考虑用杀进程的方式杀掉父进程            //kill(parent,SIGKILL);            while(1);        }        LOGD("ptrace attach success");        //说明没有被调试,附加成功        // 释放附加的进程        ptrace(PTRACE_DETACH, parent, 0, 0);        // 结束当前子进程        exit(0);    }}

二、源码修改

     针对以上的反调试手段,我们可以将源码中的ptrace逻辑改为如下:

long ptrace(int req, ...) {
   
     bool is_peek = (req == PTRACE_PEEKUSR || req == PTRACE_PEEKTEXT || req == PTRACE_PEEKDATA);  long peek_result;
  va_list args;  va_start(args, req);  pid_t pid = va_arg(args, pid_t);  void* addr = va_arg(args, void*);  void* data;  if (is_peek) {
   
       data = &peek_result;  } else {
   
       data = va_arg(args, void*);  }  va_end(args);

  ///ADD START  int caller_uid=getuid();    //int caller_pid=getpid();  //caller_uid>10000说明是普通App调用  if(caller_uid>10000)  {
   
             if(req ==PTRACE_TRACEME)     {
   
           //自己ptrace自己,直接返回成功        return 0;     }   if(req==PTRACE_ATTACH)   {
   
          int caller_ppid=getppid();     if(caller_ppid==pid)     {
   
           //如果是子进程ptrace父进程,直接返回成功        return 0;     }         //TODO 也可以通过读取/proc/$pid/status获取进程的uid,如果uid和当前调用ptrace的uid一致,也直接返回成功            }  }  ///ADD END  long result = __ptrace(req, pid, addr, data);  if (is_peek && result == 0) {
   
       return peek_result;  }  return result;}

   完成修改之后,执行如下命令编译刷机测试:​​​​​​​

source build/envsetup.shbreakfast oneplus3brunch  oneplus3

三、扩展

    由于ptrace函数容易被劫持,很多app内部使用ptrace功能都不会直接调用ptrace。而是内部使用syscall调用或者使用内联汇编实现调用ptrace的功能。因此,可以通过开发内核hook ptrace模块,兼顾各种ptrace的调用情况。关于内核系统调用拦截的,可以参考该文章:https://www.anquanke.com/post/id/85375。

关注公众号,获取更多相关文章:

   

图片

猜你喜欢

转载自blog.csdn.net/xiaomaNo01/article/details/112056120
今日推荐