c-在linux中检索EBP寄存器的内容



我需要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 %lun", syscall); 
  DPRINT(DEBUG_ALL, "Syscall instruction address %pn", info->si_call_addr);
  DPRINT(DEBUG_ALL, "PC  0x%lx, BASE_STACK  0x%lx, Stack 0x%lxn", pc, stack_base, stack);
  DPRINT(DEBUG_ALL, "Syscall number %dn", info->si_syscall);
  DPRINT(DEBUG_ALL, "Syscall arch   %un", 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包含零时,它将保持相同的值,直到应用程序结束。

如果使用最新的GCC编译器,您可能会对__builtin_return_address__builtin_extract_return_addr__builtin_frame_address 等GCC内置程序感兴趣

您可能对GCC libbacktrace(可在GCC之外使用)和Glibc回溯函数感兴趣。

不能保证所有函数都会使用标准堆栈框架,其中ebp被推送,然后在函数开始时设置为esp。函数使用ebp作为通用寄存器,然后通过esp寄存器引用函数参数和局部变量,这并不罕见。

对于代码生成器来说,这显然更复杂,因为esp的值会随着时间的推移而变化(例如,在函数调用中推送变量时),但以这种方式生成代码当然是可能的。

最多,您可以通过向上扫描堆栈,查找潜在的返回地址(例如,通过检查该地址的VMA是否设置了VM_EXEC标志)来尝试猜测返回地址。然后,在找到一个潜在的地址后,您需要从该地址向后扫描,寻找似乎是函数调用的代码(一个例子是返回5字节的E8)。

你可以更进一步,通过检查函数调用(假设它不是间接调用)指向的地址靠近你当前IP的某个地方,尽管弄清楚什么是"near"的安全定义也不是一个容易的决定。

最重要的是,这将非常复杂,而且仍然不能保证你能找到正确的地址。

相关内容

  • 没有找到相关文章

最新更新