現在、ptraceを使ったデバッグの勉強をしています。以下のサイトのデバッガを試してみたのですが上手くいきません。元のコードに手は加えていません。
[Debug] Ptrace によるデバッグ
調べてみると、アタッチはできているので、どうやら関数p_break()内のPTRACE_PEEKTEXTでデータを読み取る際に失敗しているようです。
恐らくaddrの値が問題だと考えているのですが、一向に解決しません。どうしたら正しく動作するでしょうか?
以下は実際に試した様子です。vmware上のubuntu-64bitを使用しています。
$ nm sample | grep func 000000000000068a T func $ ps aux | grep sample user 20601 0.0 0.0 4504 764 pts/1 S+ 01:46 0:00 ./sample $ sudo ./ptrace_demo 20616 0x000000000000068a Breakpoint at 0x68a. Continuing. //これ以降何も表示されない。sampleの方は動き続けている
###追記
やはりaddrの値が違ったようで、自分で書いたコードでPTRACE_GETREGSでEIPを取得し、その位置にint3を書き込むことでブレークポイントを仕掛けることには成功しました。ただ、上記のサイトのように、目的の関数にブレークポイントを仕掛けることは未だできていません。目的の関数にブレークポイントを仕掛けるにはどうしたらいいでしょうか。
また、addrの値が違うなら、そもそもnmコマンドで表示されているアドレスは一体何なのでしょうか。
あなたが知らないプログラムの真の始まり――main()関数の前にあるスタートアップとは (2/3)
こちらの記事によると、nmやreadelfで表示できるアドレスは実際に実行される際のアドレスのようですが、私の環境ではどうにも一致していません。
以下自分で書いたコードです。都合上32bitでコンパイルしています。
gcc -m32 -o TestHook TestHook.c
TestHook
1#include <stdio.h> 2#include <stdlib.h> 3#include <sys/ptrace.h> 4#include <unistd.h> 5#include <sys/types.h> 6#include <sys/wait.h> 7#include <sys/user.h> 8#include <elf.h> 9 10 11//forkしたプロセスをexecvp()で別のプロセスに置き換える 12int child(int argc, char* argv[]) 13{ 14 if(argc < 2){ 15 puts("error : argument"); 16 return -1; 17 } 18 19 long ret; 20 ret = ptrace(PTRACE_TRACEME, 0, 0, 0); 21 if(ret < 0){ 22 perror("failed PTRACE_TRACEME"); 23 exit(1); 24 } 25 26 ret = execvp(argv[1], argv); 27 if(ret < 0){ 28 perror("failed to execvp"); 29 exit(1); 30 } 31 puts("error"); //通常ならば実行されない 32 return 0; 33} 34 35//子の状態変化を待ち、SIGTRAPを受け取ると再開.int3を入れたりいろいろやる 36void parent(pid_t pid) 37{ 38 int status; 39 int ret; 40 struct user_regs_struct regs; 41 unsigned addr; 42 unsigned original_data; 43 unsigned trap_data; 44 unsigned readback_data; 45 addr = strtol("0x0000051d", NULL, 0); 46 47 waitpid(pid, &status, 0); 48 if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){ 49 50 //レジスタの値を取得 51 ret = ptrace(PTRACE_GETREGS, pid, 0, ®s); 52 if(ret < 0){ 53 puts("Failed PTRACE_GETREGS"); 54 } 55 printf("Child started. EIP = 0x%08x\n", regs.eip); 56 57 //元データの読み出し 58 original_data = ptrace(PTRACE_PEEKTEXT, pid, (void *)regs.eip, 0); 59 if(original_data == -1){ 60 puts("PEEK_TEXT error"); 61 } 62 printf("Original data at 0x%08x : 0x%08x\n",regs.eip, original_data); 63 64 //int3の書き込み 65 trap_data = (original_data & 0xFFFFFF00) | 0xCC; 66 ret = ptrace(PTRACE_POKETEXT, pid, (void *)regs.eip, (void *)trap_data); 67 if(ret < 0){ 68 puts("Failed to PTRACE_POKETEXT"); 69 } 70 71 //書き込み後のデータの所得 72 readback_data = ptrace(PTRACE_PEEKTEXT, pid, (void *)regs.eip, 0); 73 printf("After trap, data at 0x%08x : 0x%08x\n",regs.eip, readback_data); 74 75 sleep(3); 76 77 puts("\nRestart child process."); 78 puts("----------------------------"); 79 ptrace(PTRACE_CONT, pid, 0, 0); //停止している子プロセスの再開 80 waitpid(pid, &status, 0); 81 if(WIFSTOPPED(status)){ 82 puts("Breakpoint int3"); 83 } 84 } 85 } 86 87 88int main(int argc, char *argv[]) 89{ 90 pid_t child_pid = fork(); 91 92 switch(child_pid){ 93 case 0: 94 { 95 child(argc, argv); 96 } 97 default : 98 { 99 parent(child_pid); 100 } 101 } 102} 103
回答1件
あなたの回答
tips
プレビュー