0

関数の戻りアドレスを取得するために EBP/RBP の内容が必要です。このアドレスは、スタック フレーム内の 8(%RBP) の位置にある必要があります (x86_64 ビット アーキテクチャのみを考えてみましょう)。

シグナル ハンドラに渡される ucontex_t 構造体からこの値を取得しますが、プログラムは非常に奇妙な動作をします。RBP レジスタに含まれる値がまったく意味をなさない場合 (たとえば、0x00、0x01) や、正しいスタック ベース値が含まれている場合があります。もちろん、この動作はいくつかのアプリケーションのクラッシュを引き起こします。

呼び出し元関数のアドレスを知りたいので、関数の戻りアドレスを取得する必要があります。

これは私が使用しているコードです:

  syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
  pc=ctx->uc_mcontext.gregs[REG_PC];
  stack=ctx->uc_mcontext.gregs[REG_STACK];
  stack_base=ctx->uc_mcontext.gregs[REG_BASE];

  function_address=get_function_address((char *)stack_base); 

  DPRINT(DEBUG_INFO, "Received SYS_SECCOMP signal : syscall %lu\n", syscall); 
  DPRINT(DEBUG_ALL, "Syscall instruction address %p\n", info->si_call_addr);
  DPRINT(DEBUG_ALL, "PC  0x%lx, BASE_STACK  0x%lx, Stack 0x%lx\n", pc, stack_base, stack);
  DPRINT(DEBUG_ALL, "Syscall number %d\n", info->si_syscall);
  DPRINT(DEBUG_ALL, "Syscall arch   %u\n", info->si_arch);

マクロは次のように定義されます。

#define REG_SYSCALL REG_RAX
#define REG_PC    REG_RIP
#define REG_BASE  REG_RBP
#define REG_STACK REG_RSP

前のコードの出力の例: 正しい値:

[DEBUG_INFO] Received SYS_SECCOMP signal : syscall 3
Syscall instruction address 0x7fa058d67452
PC  0x7fa058d67452, BASE_STACK  0x7fff145c1d00, Stack 0x7fff145c1bc0
Syscall number 3
Syscall arch   3221225534

間違った値:

[DEBUG_INFO] Received SYS_SECCOMP signal : syscall 78
Syscall instruction address 0x7fa058df2495
PC  0x7fa058df2495, BASE_STACK  0xffffffffffffffa8, Stack 0x7fff145c1ed0
Syscall number 78
Syscall arch   3221225534

さらに悪いことに:

[DEBUG_INFO] Received SYS_SECCOMP signal : syscall 3
Syscall instruction address 0x7fa058e18360
PC  0x7fa058e18360, BASE_STACK  0x0, Stack 0x7fff145c1e68
Syscall number 3
Syscall arch   3221225534

RBP にゼロが含まれている場合、アプリケーションが終了するまで同じ値が保持されることに気付きました。

4

2 に答える 2

4

最近の GCC コンパイラを使用している場合__builtin_return_address__builtin_extract_return_addr__builtin_frame_address

libbacktraceGCC (GCC の外部で使用可能) と Glibcバックトレース関数に興味があるかもしれません。

于 2013-06-27T11:13:03.410 に答える