return_address
是通过编写一小段汇编代码获得ebp获得的,因此我们可以通过将ebp增加4来获得返回地址。
此处return_address
的类型为int
,但我们可以将其转换为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;
}
我使用gdb
逐步完成
(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.
我将返回地址作为0x08048344
传递给函数。偏移量为-64
,返回值为0x8048304
,即条形码的起始地址。
为什么这样做?
这是bar
和foo
找到
#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;
}
我把这段代码放在traceback(FILE *fp)
。
答案 0 :(得分:2)
调用指令汇编到E8 AA BB CC DD
,其中AA BB CC DD
是目标函数与调用后的指令(即返回地址)的偏移量。在gdb中尝试x/5bx 0x0804833f
以查看编码指令。请注意,偏移量将以小端字节顺序排列。
因此,(return_address - 5 + 1)
指向调用指令的偏移量。 offset = *offset_address_ptr
从调用指令读取此偏移量,return_address + offset
指向目标函数。
答案 1 :(得分:0)
我不确定,但看起来代码从返回位置之前的指令中获取了call-address。