0

関数ptraceで呼び出しを検出できるプログラムを実行しようとしています。PTRACE_SINGLESTEP を使用すると、命令ごとにプログラム命令を実行できます。次に、レジスタ RIP が指す OP_CODE 0xe8 を取得したら、PTRACE_PEEKTEXT を使用して、RIP が指すアドレスの次の 4 バイトを取得します。次に、インターネットで見つけたドキュメントによると、4バイトはジャンプする場所を参照するオフセットを表しています。PTRACE_PEEKTEXT が奇妙な値を返しているようで、オフセットが大きすぎます。以下の私のコード:

  instr_num = ptrace(PTRACE_PEEKTEXT, this->pid, regs.rip, 0);
  dest = ptrace(PTRACE_PEEKTEXT, this->pid, regs.rip + 1, 0);
  if (instr_num == 0xe8)
    {
      printf("call : %ld\n", regs.rip + dest);
    }

出力は次のとおりです。

call : -2853719444197214464
call : -2853719444197214464
call : -2853719444197214464

これは objdump -D の出力です。ご覧のとおり、main からの呼び出しと関数 func の先頭の間に 15 バイトのオフセットがあります。

00000000004004c4 <func>:
4004c4:       55                      push   %rbp
4004c5:       48 89 e5                mov    %rsp,%rbp
4004c8:       5d                      pop    %rbp
4004c9:       c3                      retq   

00000000004004ca <main>:
4004ca:       55                      push   %rbp
4004cb:       48 89 e5                mov    %rsp,%rbp
4004ce:       b8 00 00 00 00          mov    $0x0,%eax
4004d3:       e8 ec ff ff ff          callq  4004c4 <func>
4004d8:       5d                      pop    %rbp
4004d9:       c3                      retq

呼び出しを検出した直後に ptrace(PTRACE_SINGLESTEP) を 1 回実行すると、ジャンプ先の関数のアドレスが RIP に含まれますか? 私のテストによると、そうではないようですが、そうすべきだと思います。

4

1 に答える 1

0

試す:

printf("call : 0x%lx\n", regs.rip + (long) (int) (dest & (unsigned long) UINT_MAX);

destは 64 ビット値ですが、オフセットはここでは 32 ビットでエンコードされています。この種のコードでは、16 進数で印刷する方がはるかに優れています。

于 2013-06-17T19:02:35.587 に答える