Reputation: 1465
return_address
is obtain by writing a small piece of assembly code getting the ebp and hence we can get the return address by increment the ebp by 4.
Here return_address
is of type int
but we can cast it to int*
int extract_function_address(int return_address) {
int *offset_address_ptr = (int*)(return_address - 5 + 1);
int offset = *offset_address_ptr;
int func_address = return_address + offset;
return func_address;
}
I use gdb
to step through it
(gdb) disas bar
Dump of assembler code for function bar:
0x08048304 <+0>: push %ebp
0x08048305 <+1>: mov %esp,%ebp
0x08048307 <+3>: sub $0x8,%esp
0x0804830a <+6>: mov 0xc(%ebp),%eax
0x0804830d <+9>: mov 0x8(%ebp),%edx
0x08048310 <+12>: add %edx,%eax
0x08048312 <+14>: mov %eax,-0x4(%ebp)
0x08048315 <+17>: mov -0x4(%ebp),%eax
0x08048318 <+20>: mov %eax,0x8(%ebp)
0x0804831b <+23>: mov 0x81e2460,%eax
0x08048320 <+28>: mov %eax,(%esp)
0x08048323 <+31>: call 0x8048358 <traceback>
0x08048328 <+36>: leave
0x08048329 <+37>: ret
End of assembler dump.
(gdb) disas foo
Dump of assembler code for function foo:
0x0804832a <+0>: push %ebp
0x0804832b <+1>: mov %esp,%ebp
0x0804832d <+3>: sub $0x8,%esp
0x08048330 <+6>: movl $0x11,0x4(%esp)
0x08048338 <+14>: movl $0x5,(%esp)
0x0804833f <+21>: call 0x8048304 <bar>
0x08048344 <+26>: leave
0x08048345 <+27>: ret
End of assembler dump.
I passed return address as 0x08048344
to the function. The offset will be -64
and the return value will be 0x8048304
which is the starting address of bar.
Why is this work?
This is the C file where bar
and foo
locate
#include "traceback.h"
#include <stdio.h>
void bar(int x, int y)
{
int z;
z = x + y;
traceback(stdout);
}
void foo() {
bar (5,17);
}
int main (int argc, char **argv)
{
foo();
return 0;
}
I put that piece of code in traceback(FILE *fp)
.
Upvotes: 1
Views: 227
Reputation: 451
A call instruction assembles to E8 AA BB CC DD
where AA BB CC DD
is the offset of the target function from the instruction following the call, i.e. from the return address. Try x/5bx 0x0804833f
in gdb to see the encoded instruction. Note that the offset would be in little endian byte order.
Therefore, (return_address - 5 + 1)
points to the offset of the call instruction. offset = *offset_address_ptr
reads this offset from the call instruction and return_address + offset
points to the target function.
Upvotes: 2
Reputation: 676
I'm not sure, but it looks like the code fethes call-address from the instruction just before the return location.
Upvotes: 0