Análisis de principios y detección anti-depuración nativa de Android

1. Detecta el archivo del servidor Android

void check(){
    
    
const char* Path="/data/local/tmp";
dir =opendir(Path);
int pid =getpid();
if(dir!=NULL){
    
    
    dirent *currentDir;
    while((currentDir=readdir(dir)!=NULL)){
    
    
        //使用readdir函数读取当前目录下的每一个文件
        if(strncmp(currentDir->d_name,"android_server",14)==0)//currentDir->de_name结构体能够获取当前的文件名
        {
    
    
            kill(pid,SIGKILL);
        }
    }
    closedir(dir);//关闭文件
    }else{
    
    
        
    }
}

Análisis :
este es el tipo más simple de detección anti-depuración. El principio es muy simple. Utilice currentDirla detección de estructura para obtener
/ data / local / tmp¿Hay un archivo android_server en el directorio?

Contramedidas:
Existen muchas contramedidas, la forma más conveniente es ingresar al directorio / data / local / tmp y cambiar el nombre del archivo.

2. Nombre del proceso de detección

Este método ha sido analizado antes, aquí hay un análisis más detallado

void check()
{
    
    
    const int bufsize=1024;
    char filename[bufsize];
    char line[bufsize];
    char name[bufsize];
    char nameline[bufsize];
    //获取Tracepid的值
    int pid=getpid();
    sprint(filename,"/proc/%d/status",pid);
    FILE *fd=fopen(filename,"r");
    if(fd!=NULL)
    {
    
    
        while(fgets(line,bufsize,fd))
        {
    
    
           //遍历读取到“TracePid”
           if(strstr(line,"TracePid")!=NULL)
            {
    
    
            //判断TracePid的第10个数是否为0
                int statue=atoi(&line[10]);
                if(statue!=0)
                {
    
    
                //不等于0时,将当前的statue写入到name中
                    sprint(name,"/proc/%d/cmdline",statue);
                    //读取文件fdname
                    FILE *fdname=fopen(name,"r");
                    if(fdname!=NULL)
                    {
    
    
                    //遍历找到“android_server”
                        while(fgets(nameline,bufsize,fdname))
                        {
    
    
                            if(strstr(nameline,"android_server"!=NULL))
                            {
    
    
                                int ret =kill(pid,SIGKILL);
                                //kill进程
                            }
                        }
                    }
                    fclose(fdname);
                }
            }
        }
    }
    fclose(fd);
}

strstr: Definición : char * strstr (const char * haystack, const char * needle) Función : haystack -C cadena a recuperar. aguja -La cuerda pequeña que se buscará en la cuerda del pajar. Esta función devuelve la posición donde la cadena de agujas aparece por primera vez en el pajar, o nula si no se encuentra .

atoi: definición : int atoi (const char * str), función : str-la cadena que se convertirá en un entero. Esta función devuelve el entero largo convertido, o cero si no se ha realizado una conversión efectiva.

Análisis : primero verifique si el valor de Tracepid es 0, si es 0, verifique si hay android_server en la verificación transversal, si hay un proceso de eliminación directa

Contramedidas: simplemente hablemos de ello. En general, intentaremos romper con ida y cambiar su valor de retorno a 0 cuando se ejecuta la función especificada. Por supuesto, también se pueden usar otros métodos como nop fuera de la instrucción de salto. , Que no se detecte, hay una forma más complicada de resolver fundamentalmente este problema de anti-depuración, que es actualizar la máquina para modificar el código fuente, aquí hay una publicación de un gran tipo https://se8s0n.github.io/2019/04/ 19 /% E5% B0% 9D% E8% AF% 95% E7% BB% 95% E8% BF% 87TracePID% E5% 8F% 8D% E8% B0% 83% E8% AF% 95% E4% BA% 8C % E2% 80% 94% E2% 80% 94% E4% BB% 8E% E6% BA% 90% E7% A0% 81% E5% 85% A5% E6% 89% 8B /

Tres, detecta puertos de uso común

void check()
{
    
    
    FILE* pfile=NULL;
    char buf[0x10000]={
    
    0};
    //使用代码执行cmd命令
    char* strCatTcpPort="cat /proc/net/tcp |grep :5D8A";
    pfile = popen(strCatTcpPort,"r");
    int pid=getpid();//获取进程的pid
    if(NULL==pfile)
    {
    
    
        //命令运行失败
        return;
    }
    //读取pfile文件内容,如果android_server没有启动的话,常文件内不会有内容
    while(fgets(buf,sizeof(buf),pfile))
    {
    
    
        //检测到23946端口被占用,直接kill进程
        int ret=kill(pid,SIGKILL);
    }
    pclose(pfile);
}

Análisis:
el cat /proc/net/tcp |grep :5D8Acomando se usa aquí para leer los datos generados después de que se usa el puerto 23946, y los datos se obtienen usando strCatTcpPort , y luego se escriben en pfile , y finalmente

Función ps: fget
Si tiene éxito, la función devuelve el mismo parámetro str.
Si se llega al final del archivo o no se han leído caracteres

** Efecto de ejecución simulado: ** Cuando no iniciamos android_server, cat /proc/net/tcp |grep :5D8Ase utilizó el efecto de comando:

Inserte la descripción de la imagen aquí
Ninguna salida

Y usamos
Inserte la descripción de la imagen aquí
contramedidas después de iniciar android_server :
dado que es un puerto de detección, simplemente cambie el puerto android_server directamente,
use ./android_server -pel puerto seguido por usted
Inserte la descripción de la imagen aquí

Cuarto, detección por turnos

void anti_debugger()
{
    
    
    pthread_t tid;
    pthread_create(&tid,NULL,&anti_debug_thread,NULL);
}
void *anti_debugger_thread(void*data)
{
    
    
    pid_t pid=getpid();
    while(true)
    {
    
    
        check_debugger(pid)
    }
}
bool check_debugger(pid_t pid)
{
    
    
    const int pathSize=256;
    const int bufSize=1024;
    char path[pathSize];
    char line[bufSize];
    snprintf(path,sizeof(path)-1,"/proc/%d/status",pid);
    bool result =true;
    FILE *fp=fopen(path,"rt");
    if(fp!=NULL)
    {
    
    
        while(fgets(line,sizeof(line),fp))
        {
    
    
            if(strncmp(line,TRACERPID,TRACERPID_LEN)==0)
            {
    
    
                pid_t tracerPid=0;
                sscanf(line,"%*s%d",&tracerPid);
                if(!tracerPid)
                result =false
                break;
            }
        }
        fclose(fp);
    }
    return result;
}

Análisis : también detecta el pid para determinar si es 0. Si no es 0, se realiza un bucle sin fin. La desventaja de este método es obviamente que ocupa memoria, lo que generalmente no es común.

Cinco, bifurque el proceso hijo para depurar el proceso padre

void protect_father()
{
    
    
    pid_t ppid=getppid();
    //获取父进程pid
    attach(ppid);
}
void attach(pid_t pid)
{
    
    
        long err =ptrace(PTRACE_ATTACH,pid,NULL,NULL);
    if(err<0)
    {
    
    
        perror("PTRACE_ATTACH");
        exit(EXIT_FAILURE);
        
    }
}

Análisis : dado que el proceso hijo depura el proceso principal, puede considerar la posibilidad de depurar su proceso hijo directamente.

Seis, sigue tu pista

void anti_debug01()
{
    
    
    ptrace(PTRACE_TRACEME,0,0,0);
}

Este artículo se ha tratado en detalle antes

para resumir

Hay muchos métodos de anti-depuración en la capa so. El método más importante es el método nop , depuración dinámica y modificación del valor de retorno . Cabe señalar que muchos métodos anti-depuración no son solo anti-depuración, sino también muchos Los algoritmos de cifrado están vinculados entre sí, lo que aumenta en gran medida la capacidad de análisis y anti-depuración.

Supongo que te gusta

Origin blog.csdn.net/weixin_43632667/article/details/105353383
Recomendado
Clasificación