Question

I need the content of EBP/RBP for retrieving the return address of a function. This address should be at the position 8(%RBP) within the stack frame ( let's consider only x86_64 bit architecture).

I retrieve this value from the ucontex_t structure, which is passed to the signal handler, but the program has a really strange behavior. Sometimes the values contained in the RBP register does not make sense at all (for instance, 0x00, 0x01) and sometimes it contains the correct stack base value. Of course, this behavior causes several application's crashes.

I need to retrieve the return address of the function because, I want to find out the address of the caller function.

This is the code that I am using :

  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);

The macro are defined as follows :

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

An example of the output of the previous code is : Correct value :

[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

Wrong value :

[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

Even worse :

[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

I have noticed that, when RBP contains zero, it keeps with the same value until the end the application.

Was it helpful?

Solution 2

There is no guarantee that all functions will use a standard stack frame with ebp being pushed and then set to esp at the start of the function. It's not that uncommon for functions to use ebp as a general purpose register, and then refer to function parameters and local variables via the esp register.

That's obviously more complicated for the code generator, because the value of esp will change over time (for example as variables are being pushed in a function call), but it's certainly possible to generate code that way.

At best, you could try and guess the return address by scanning up the stack, looking for a potential return address (e.g. by checking if the VMA for that address has the VM_EXEC flag set). Then having found a potential address, you would need to scan backwards from that address, looking for code that appears to be a function call (one example being an E8 five bytes back).

You could go further, by checking where the function call (assuming it's not an indirect call) is pointing to an address somewhere near your current IP, although figuring out what is a safe definition of "near" is not an easy decision either.

The bottom line is that it's going to very complicated, and there's still no guarantee that you're going to find the correct address.

OTHER TIPS

If using a recent GCC compiler, you might be interested by some GCC builtins like __builtin_return_address, __builtin_extract_return_addr, __builtin_frame_address

You might be interested by GCC libbacktrace (which is usable outside of GCC) and by Glibc backtrace functions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top