xorl %eax, %eax

More GDB Anti-Debugging

with 2 comments

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$

Written by xorl

January 5, 2009 at 15:19

2 Responses

Subscribe to comments with RSS.

  1. “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

  2. 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


Leave a comment