More GDB Anti-Debugging
A couple of months ago, the almighty Silvio had found an interesting behavior on GDB. As he said at his post, this could be used to detect GDB. When a process uses fork(2) to spawn a child process, the parent’s file descriptors are inherited to the new child process. In normal cases, the new process should have only FDs 0 (stdin), 1 (stdout) and 2 (stderr). However, GDB opens up some more FDs (3, 4 and 5) and never closes them, so they are inherited. You can use this bug to detect the debugger simply by having a function similar to this in your code:
#include <stdio.h> #include <unistd.h> void detect_gdb(void) __attribute__((constructor)); void detect_gdb(void) { FILE *fd = fopen("/tmp", "r"); if (fileno(fd) > 5) { printf("fuck you gdb!\n"); _exit(1); } fclose(fd); } int main(void) { printf("do stuff outside gdb\n"); return 0; }
Similarly to the previous method for anti-debugging, the detection code is inserted in .CTORS section of the ELF in order to make it more stealth. Of course this limits the target operating systems to just the ones that support ELF, but since this issue only affects GDB I think it is fine. At last, here is at runtime:
sh-3.2$ gcc de.c -o de sh-3.2$ ./de do stuff outside gdb sh-3.2$ gdb -q ./de Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1". (gdb) run Starting program: /home/xorl/de Failed to read a valid object file image from memory. fuck you gdb! Program exited with code 01. (gdb)
Another funny thing that I came across during the above test is that FD 5 of GDB is a symbolic link to the executable that is ptrace(2)‘ing. You can use this to retrieve a copy of the original binary. Assume you have this simple application:
#include <unistd.h> #include <stdio.h> int main(void) { return printf("pid: %d\n",getpid()); }
If you know that is running in GDB, for example:
sh-3.2$ gdb -q ./g Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1". (gdb) b *main+38 Breakpoint 1 at 0x80483ba (gdb) run Starting program: /home/xorl/g Failed to read a valid object file image from memory. pid: 32165 Breakpoint 1, 0x080483ba in main () (gdb)
Then you can do something like this and retrieve a copy of the original binary:
sh-3.2$ ls -l /proc/32165/fd/5 lr-x------ 1 xorl xorl 64 2009-01-05 17:08 /proc/32165/fd/5 -> /home/xorl/g sh-3.2$ cat /proc/32165/fd/5 > newfile sh-3.2$ diff newfile g sh-3.2$ echo $? 0 sh-3.2$
And of course it works exactly the same:
sh-3.2$ chmod +x newfile sh-3.2$ ./newfile pid: 32286 sh-3.2$
“A couple of months ago, the almighty Silvio had found an interesting behavior on GDB. As he said at his post, this could be used to detect GDB. When a process uses fork(2) to spawn a child process, the parent’s file descriptors are inherited to the new child process.”
mm.. as I posted in silvio’s blog, this is not true.. this was first published in 2005 (http://www.reversing.org/node/view/5) and used as antidebug technics in several crackmes, including one in the NoConName sec conf.
In any case it’s funny to have same conclusion within a year gap for several people :)
ilo
April 15, 2009 at 22:40
Your anti debugging code don’t detect gdb on my enviroment.
I run it under gdb, but it print “do stuff outside gdb”.
Doesn’t it run on recently gdb?
my gdb: GNU gdb (Ubuntu 7.7-0ubuntu3.1) 7.7
my gcc: gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
たけまる (@tkmru)
April 20, 2015 at 09:42