anti-debug

anti-debug

Posted by fa1con on January 1, 2019

[toc]

linux反调试

ptrace

原理:同一时间内进程最多只能被一个调试器进行调试。通过调试进程自身,判断是否已经有调试器的存在。

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <sys/ptrace.h>
int main(int argc, char *argv[]) {
    if(ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
       printf("Debugger detected");
       return 1;
   }  
   printf("All good");
   return 0;
}

PTRACE_TRACEME来指明进程将被调试,忽略其他参数,如果正在被调试返回-1

检查父进程名称

原理:程序由gdb启动,所以父进程是gdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
   char buf0[32], buf1[128];
   FILE* p;
 
   snprintf(buf0, 24, "/proc/%d/cmdline", getppid());
   p = fopen(buf0, "r");
   fgets(buf1, 128, p);
   fclose(p);
 
   if(!strcmp(buf1, "gdb")) {
       printf("Debugger detected");
       return 1;
   }  
   printf("All good");
   return 0;
}

检查进程运行状态

若程序是attach到调试器上的,程序的父进程就不是调试器,应该检查/proc/self/status文件,TracerPid由0变为非0的数,即调试器的PID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
   int i;
   scanf("%d", &i);
   char buf1[512];
   FILE* fin;
   fin = fopen("/proc/self/status", "r");
   int tpid;
   const char *needle = "TracerPid:";
   size_t nl = strlen(needle);
   while(fgets(buf1, 512, fin)) {
       if(!strncmp(buf1, needle, nl)) {
           sscanf(buf1, "TracerPid: %d", &tpid);
           if(tpid != 0) {
                printf("Debuggerdetected");
                return 1;
           }
       }
    }
   fclose(fin);
   printf("All good");
   return 0;
}

检测运行时间

alarm设置定时,到达时中止程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void alarmHandler(int sig) {
   printf("Debugger detected");
   exit(1);
}
void__attribute__((constructor))setupSig(void) {
   signal(SIGALRM, alarmHandler);
   alarm(2);
}
int main(int argc, char *argv[]) {
   printf("All good");
   return 0;
}

attribute((constructor))指定该函数运行于main函数之前

检查进程打开的filedescriptor(有问题,未解决)

如果被调试的进程是通过gdb 的方式启动,那么它便是由gdb进程fork得到的。而fork在调用时,父进程所拥有的fd(file descriptor)会被子进程继承。由于gdb在往往会打开多个fd,因此如果进程拥有的fd较多,则可能是继承自gdb的,即进程在被调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
   struct dirent *dir;
   DIR *d = opendir("/proc/self/fd");
   while(dir=readdir(d)) {
       if(!strcmp(dir->d_name, "5")) {
           printf("Debugger detected");
           return 1;
       }
    }
   closedir(d);
   printf("All good");
   return 0;
}

参考文章:https://blog.csdn.net/earbao/article/details/53933238