GDB アンチデバッギング
GDB アンチデバッギングについて調べたのでメモ。
ptraceを使う検知法とファイルディスクリプタの増加による検知法の2通りの方法を発見したけど、後者は古いバージョンでしか動かないっぽい。
ptraceを使って検知
ptraceとはプロセス追跡をするシステムコールである。1回目の呼び出しでは正常にプロセスを追跡できるが、2回目以降、同一プロセスを追跡しようとすると失敗し、-1を返す。ptraceで自分自身を追跡すると、gdbから実行された場合(既にptraceされている場合)は、-1を返すので検知できる。
#include <stdio.h> #include <sys/ptrace.h> int main() { if (ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) { printf("inside gdb !!\n"); return 1; } printf("outside gdb.\n"); return 0; }
攻略法
ptrace()をnopで潰したり、ptraceを呼んだ後に set $eax = 0 したりすることで攻略できる。
ファイルディスクリプタの増加による検知
ファイルディスクリプタとは、プロセスがアクセスするファイルや標準入出力などをOSが識別するために用いる識別子である。
最初からプロセスは、0(stdin)、1(stdout)、2(stderr)の3つのファイルディスクリプタを持っていて、これらはプロセス終了時に自動で閉じられるが、ファイルを開いたり、socketを使うときに生成されるものは自分で閉じる必要がある。
以下のコードでファイルディスクリプタの割り当てが確認できる。
#include <stdio.h> #include <unistd.h> int main(void) { printf("stdin: %d\n", fileno(stdin)); //出力は 0 printf("stdout: %d\n", fileno(stdout)); //出力は 1 printf("stderr: %d\n", fileno(stderr)); //出力は 2 FILE *new_fd = fopen("/tmp", "r"); printf("new fd: %d\n", fileno(new_fd)); //出力は 3 fclose(new_fd); return 0; }
gdbでプログラムを実行する際、gdbが3、4、5のファイルディスクリプタを開くので、ファイルディスクリプタの増加によってgdbを検知できるらしいが、私の環境(gdb (Ubuntu 7.7-0ubuntu3.1) 7.7, gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2)では再現できなかった。gdbがファイルディスクリプタを新たに開かないようになったっぽい。
#include <stdio.h> #include <unistd.h> int main(){ FILE* fd = fopen("/tmp", "r"); if(fileno(fd) > 3){ printf("fuck you gdb !!\n"); _exit(1); } printf("outside gdb.\n"); return 0; }
攻略法
break __libc_start_mainして、close()を使ってファイルディスクリプタを閉じればいい。