简体   繁体   English

为什么这段代码可以从返回地址获取函数地址?

[英]why this piece of code can get the function address from return address?

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* return_address是通过编写一小段获得ebp的汇编代码而获得的,因此我们可以通过将ebp加4来获得返回地址。这里return_addressint类型的,但可以将其return_addressint*

 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逐步解决

(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. 我将返回地址作为0x08048344传递给了该函数。 The offset will be -64 and the return value will be 0x8048304 which is the starting address of bar. 偏移量为-64 ,返回值为0x8048304 ,它是bar的起始地址。

Why is this work? 为什么要这样做?

This is the C file where bar and foo locate 这是barfoo所在的C文件

#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) . 我把这段代码放在traceback(FILE *fp)

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, ie from the return address. 调用指令汇编到E8 AA BB CC DD ,其中AA BB CC DD是目标函数相对于调用后指令(即返回地址)的偏移量。 Try x/5bx 0x0804833f in gdb to see the encoded instruction. 尝试在gdb中使用x/5bx 0x0804833f查看编码指令。 Note that the offset would be in little endian byte order. 请注意,偏移量将以小尾数字节顺序。

Therefore, (return_address - 5 + 1) points to the offset of the call instruction. 因此, (return_address - 5 + 1)指向调用指令的偏移量。 offset = *offset_address_ptr reads this offset from the call instruction and return_address + offset points to the target function. offset = *offset_address_ptr return_address + offset从调用指令中读取此偏移量,而return_address + offset指向目标函数。

我不确定,但是它看起来像代码在返回位置之前的指令中调用了地址。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM