linux ELF程序常用反调试套路 2018-11-30 09:20:00 Steven Xeldax 1.int3指令 int3是一个特殊的指令,专门用来给调试器使用。这时,我们应该容易想到,要反调试,只要插入int3来迷惑调试器即可。 ``` #include <signal.h> void handler(int signo){} int main(){ signal(handler, SIGTRAP); asm("int3"); printf("Hello\n"); } ``` 2.文件描述符 gdb要调试这个程序时会打开一个额外的文件描述符来读这个可执行文件,而这个程序正是利用这个弱点。 ``` #include <stdio.h> int main( int argc, char *argv[] ) { if(close(3) == -1) { printf("OK\n"); } else { printf("traced!\n"); exit(-1); } return 0; } ``` 3.检查父进程名称 再Linux上要跟踪一个程序,必须是它的父进程才能做到,因此如果一个程序的父进程不是意料之中的bash或者init这类的,说明他被追踪了。 ``` pid_t ppid = getppid() ``` ``` #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { char buf0[32], buf1[128]; FILE* fin; snprintf(buf0, 24, "/proc/%d/cmdline", getppid()); fin = fopen(buf0, "r"); fgets(buf1, 128, fin); fclose(fin); if(!strcmp(buf1, "gdb")) { printf("Debugger detected"); return 1; } printf("All good"); return 0; ``` 4.利用环境变量 bash有一个环境变量位$_,它保存的是上一个执行的命令的最后一个参数。 ``` getenv("_") ``` 5.利用ptrace 如果被追踪了还再调用ptrace(PTRACE_TRACEME)自然会不成功。 ``` #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; } ``` 6.设置程序运行最大时间 由于程序在调试时的断点、检查修改内存等操作,运行时间往往要远大于正常运行时间。所以,一旦程序运行时间过长,便可能是由于正在被调试。 ``` #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; ``` 7.检查进程运行状态TracerPID 调试器也可以通过attach到某个已有进程的方法进行调试。这种情况下,被调试进程的父进程便不是调试器了。 在这种情况下,我们可以通过直接检查进程的运行状态来判断是否被调试。而这里使用到的依然是/proc文件系统。具体地,我们检查/proc/self/status文件。当进程正常运行而未被调试时,该文件的内容如下: ``` root@kali:~# cat /proc/self/status Name: cat Umask: 0022 State: R (running) Tgid: 27398 Ngid: 0 Pid: 27398 PPid: 27385 TracerPid: 0 ``` 可见,进程状态由sleeping变为tracing stop,TracerPid也由0变为非0的数,即调试器的PID。由此,我们便可通过检查status文件中TracerPid的值来判断是否有正在被调试。示例代码如下: ``` #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; } ```