質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

1回答

800閲覧

PTRACE_PEEKTEXTでデータを読み取れない

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

0クリップ

投稿2019/08/21 17:08

編集2019/08/22 18:01

現在、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, &regs); 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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

どうやらPIE(position-independent executable)なる機能のおかげでアドレスが絶対アドレスではなく相対アドレスになっていたようです。

ELF実行ファイルのメモリ配置はどのように決まるのか
バッファオーバーフローを起こしたい。
こちらを参考に、/proc/pid/mapsから基点となるアドレスを読み込んだ後、相対アドレスを計算すると上手くブレークポイントを貼ることができました。

また別の問題が発生したのですが、当初の問題は解決したので、自己解決とさせていただきます。

投稿2019/08/22 19:44

編集2019/08/22 19:47
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問