ptraceを使ってみよう!
「たのしいバイナリの歩き方」では4章で簡易的なデバッガの作成を解説しています。ただWindows環境での話でした。ptraceを使うことで、同じようなことをLinux環境(Ubuntu 12.04.2)でも実現できます。基本的な仕組みはWindowsのときと同じです。
試しにやってみましょう。
// dbg.c // $ gcc -Wall dbg.c -o dbg #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/syscall.h> #include <sys/user.h> #include <errno.h> void err(char *str) { fprintf(stderr, "ERROR: %s\n", str); } void target(char *argv[], char *argp[]) { if(ptrace(PTRACE_TRACEME, 0, NULL, NULL) != -1) execve(argv[0], argv, argp); else err("PTRACE_TRACEME"); exit(0); } void controler(int pid) { int status; struct user_regs_struct regs; while(1){ waitpid(pid, &status, 0); if(WIFEXITED(status)) break; ptrace(PTRACE_GETREGS, pid, 0, ®s); printf("%08x: \n", (unsigned int)regs.eip); ptrace(PTRACE_SINGLESTEP, pid, 0, NULL); } } int exec_prog(char *argv[], char *argp[]) { int pid; switch(pid = fork()) { case 0: target(argv, argp); break; case -1: err("FORK"); break; default: controler(pid); break; } return 0; } int main(int argc, char *argv[], char *argp[]) { if(argc < 2){ fprintf(stderr, "%s <args>\n", argv[0]); return 1; } argv++; exec_prog(argv, argp); return 0; }
// target.c // $ gcc target.c -o target #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { if(argc != 2){ printf("%s <PASSWORD>\n", argv[0]); return 1; } if(strcmp("BINARY", argv[1]) == 0) printf("OK!\n"); else printf("ERR\n"); return 0; }
$ gcc target.c -o target $ gcc -Wall dbg.c -o dbg $ ./dbg target > eiplog $ cat eiplog | more b77551d0: b77551d2: b7758c80: b7758c81: b7758c83: b7758c84: (省略)
4章まで読まれた方なら動作概要は容易に理解できるかと思います。基本的に、ptrace関数に渡す第1引数によって動作が異なります。
PTRACE_ATTACH | 任意のプロセスにアタッチ |
PTRACE_DETACH | デバッギからデタッチ |
PTRACE_KILL | デバッギを強制終了 |
PTRACE_TRACEME | 自身がデバッギになる |
PTRACE_PEEKDATA | (デバッギの)メモリ空間を読む |
PTRACE_POKEDATA | (デバッギの)メモリ空間へ書く |
PTRACE_GETREGS | (デバッギの)レジスタを取得する |
PTRACE_SYSCALL | 実行し、システムコールの前後で停止する |
PTRACE_SINGLESTEP | 実行し、1命令処理後に停止する |
ここに挙げた以外にもめちゃくちゃたくさんあるのですが、説明しきれないので詳細はman ptraceを見てください。これをベースに作り込むと、いろいろと便利なものが作れます。2年ほど前に私が書いたものもぜひ参考にしてみてください。