Android native anti-debugging detection and principle analysis

1. Detect Android-server file

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

Analysis :
This is the simplest kind of anti-debugging detection. The principle is very simple. Use currentDirstructure detection to obtain
/data/local/tmpIs there an android_server file in the directory

Countermeasures:
There are many countermeasures. The most convenient way is to enter the /data/local/tmp directory and change the file name.

2. Detection process name

This method has been analyzed before, here is a more detailed analysis

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: Definition : char *strstr(const char *haystack, const char *needle) Function : haystack -C string to be retrieved. needle -The small string to be searched in the haystack string. This function returns the position where the needle string first appears in haystack, or null if it is not found .

atoi: definition : int atoi(const char *str), function : str-the string to be converted to an integer. This function returns the converted long integer, or zero if no effective conversion has been performed.

Analysis : first check whether the value of Tracepid is 0, if it is 0, check whether there is android_server in the traversal check, if there is a direct kill process

Countermeasures: Let’s simply talk about it. In general, we will try to break under ida and change its return value to 0 when running to the specified function. Of course, other methods such as nop off the jump instruction can also be used. , Let it not be detected, there is a more complicated way to fundamentally solve this anti-debugging problem, that is to refresh the machine to modify the source code, here is a post from a big guy 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/

Three, detect commonly used ports

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

Analysis:
The cat /proc/net/tcp |grep :5D8Acommand is used here to read the data generated after port 23946 is used, and the data is obtained using strCatTcpPort , and then written into pfile , and finally

ps:fget function
If successful, the function returns the same str parameter.
If the end of the file is reached or no characters have been read

**Simulated execution effect: **When we did not start android_server, the cat /proc/net/tcp |grep :5D8Acommand effect was used:

Insert picture description here
No output

And we used
Insert picture description here
countermeasures after starting android_server :
Since it is a detection port, then just change the port android_server directly,
use ./android_server -pthe port followed by you
Insert picture description here

Fourth, round-robin detection

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

Analysis : It also detects the pid to determine whether it is 0. If it is not 0, an endless loop is performed. The disadvantage of this method is obviously that it takes up memory, which is generally not common.

Five, fork the child process to debug the parent process

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

Analysis : Since the parent process is debugged by the child process, you can consider debugging its child process directly.

Six, ptrace yourself

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

This article has been covered in detail before

to sum up

There are many methods for anti-debugging at the so layer. The most important method is the nop method , dynamic debugging and modifying the return value . It should be noted that many anti-debugging methods are not just pure anti-debugging, but also many Encryption algorithms are linked together, which greatly increases the ability of analysis and anti-debugging.

Guess you like

Origin blog.csdn.net/weixin_43632667/article/details/105353383