我需要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"的安全定义也不是一个容易的决定。
最重要的是,这将非常复杂,而且仍然不能保证你能找到正确的地址。