Modifique ptrace para omitir la anti-depuración (Android10)

1. Introducción a ptrace en Android 10

 
   1. Seguimiento de la ubicación del código fuente

      En Android10, la ruta del archivo de definición de la función ptrace es:

 bionic/libc/include/sys/ptrace.h

    El prototipo de función se define de la siguiente manera:

long ptrace(int __request, ...);

        La ruta del archivo de la función ptrace es:

 bionic/libc/bionic/ptrace.cpp

          

    El código de implementación de la función es el siguiente:

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;}

    Desde el código de implementación de ptrace, podemos ver que finalmente se llama a la función __ptrace. Después del seguimiento del código, la función __ptrace se implementa a través del ensamblaje de diferentes plataformas y finalmente llama a la llamada al sistema __NR_ptrace.

   Ruta del archivo del código de implementación __ptrace de la plataforma Android arm:

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

 

El código de implementación es el siguiente:

#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)

      

      Ruta del archivo del código de implementación __ptrace de la plataforma Android arm64:

               

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

               

      El código de implementación es el siguiente:

#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
    retEND(__ptrace).hidden __ptrace

2. Función  

     ptrace puede permitir que un proceso monitoree y controle la ejecución de otro proceso, y modifique la memoria y los registros del proceso monitoreado. Se utiliza principalmente para la depuración de puntos de interrupción del depurador, seguimiento de llamadas del sistema, etc. Por ejemplo, la herramienta strace proporcionada por el sistema Android puede rastrear todas las llamadas al sistema ejecutadas por la aplicación, como se muestra a continuación:

imagen

   En la protección de aplicaciones de Android, ptrace se usa ampliamente para anti-depuración. Un proceso sólo puede ser ptrace una vez. Si se llama primero al método ptrace, puede evitar que otros depuren nuestro programa. Este es el legendario pozo preventivo. Por ejemplo, llame al siguiente código en JNI_onLoad para ocupar el hoyo primero:

 

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

   También puede utilizar el proceso principal ptrace multiproceso para detectar si está depurado, el código al que se hace referencia en línea es el siguiente:

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);    }}

Dos, modificación del código fuente

      

     Para los métodos anti-depuración anteriores, podemos cambiar la lógica ptrace en el código fuente a lo siguiente:

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;}

   Después de completar la modificación, ejecute el siguiente comando para compilar la prueba flash:

source build/envsetup.shbreakfast oneplus3brunch  oneplus3

Tres, expansión

    Dado que la función ptrace es fácil de secuestrar, muchas aplicaciones usan la función ptrace internamente y no llamarán directamente a ptrace. En su lugar, use syscall internamente o use ensamblado en línea para implementar la función de llamar a ptrace. Por lo tanto, el módulo ptrace hook del kernel se puede desarrollar para tener en cuenta varias llamadas ptrace. Acerca de la interceptación de llamadas del sistema kernel, puede consultar este artículo: https://www.anquanke.com/post/id/85375.

 

Siga la cuenta pública de WeChat para obtener más artículos relacionados:

imagen

Supongo que te gusta

Origin blog.csdn.net/u011426115/article/details/113194084
Recomendado
Clasificación