为什么所有 libc 函数调用都会得到 e8 00 00 00 00?

逆向工程 x86-64
2021-07-08 20:58:38

我刚开始学习逆向工程。接近呼叫指令 (e8) 对我来说非常混乱。我花了一段时间才弄清楚地址计算是如何用于本地函数的。

现在我在看输出

// gcc -c test.c 
void test() {
     puts("Hello from puts");
     printf("Hello from printf");
}

e8 00 00 00 00适用于两个电话。不知何故,我的反汇编程序可以找出哪个调用是哪个。

这是 objdump 输出:

    0000000000000000 <_test>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   48 83 ec 10             sub    rsp,0x10
   8:   48 8d 3d 1f 00 00 00    lea    rdi,[rip+0x1f]        # 2e <_test+0x2e>
   f:   e8 00 00 00 00          call   14 <_test+0x14>
  14:   48 8d 3d 23 00 00 00    lea    rdi,[rip+0x23]        # 3e <_test+0x3e>
  1b:   89 45 fc                mov    DWORD PTR [rbp-0x4],eax
  1e:   b0 00                   mov    al,0x0
  20:   e8 00 00 00 00          call   25 <_test+0x25>
  25:   89 45 f8                mov    DWORD PTR [rbp-0x8],eax
  28:   48 83 c4 10             add    rsp,0x10
  2c:   5d                      pop    rbp
  2d:   c3                      ret

料斗的输出:

_test:
0000000000000000   push  rbp
0000000000000001   mov   rbp, rsp
0000000000000004   sub   rsp, 0x10
0000000000000008   lea   rdi, qword [0x2e]      ; argument "s" for _puts
000000000000000f   call  _puts
0000000000000014   lea   rdi, qword [0x3e]      ; argument "format" for _printf
000000000000001b   mov   dword [rbp+var_4], eax
000000000000001e   mov   al, 0x0
0000000000000020   call  _printf
0000000000000025   mov   dword [rbp+var_8], eax
0000000000000028   add   rsp, 0x10
000000000000002c   pop   rbp
000000000000002d   ret                          ; endp

编辑

我找到了我最初问题的答案:

如果您正在反汇编尚未链接的 .o 目标文件,则调用地址将只是一个由链接器填充的占位符。

那么链接器如何知道调用的是哪个函数呢?

1个回答

如果您使用-dr而不是 plain -dobjdump在说明旁边列出重定位信息例如,这是我刚刚编译的随机样本

00000000 <main>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 e4 f0                and    $0xfffffff0,%esp
   6:   83 ec 20                sub    $0x20,%esp
   9:   c7 44 24 18 a9 03 00    movl   $0x3a9,0x18(%esp)
  10:   00
  11:   c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
  18:   00
                        15: R_386_32    m1
  19:   c7 04 24 30 00 00 00    movl   $0x30,(%esp)
                        1c: R_386_32    .rodata
  20:   e8 fc ff ff ff          call   21 <main+0x21>
                        21: R_386_PC32  wprintf
  25:   89 44 24 1c             mov    %eax,0x1c(%esp)
  29:   b8 00 00 00 00          mov    $0x0,%eax
  2e:   c9                      leave
  2f:   c3                      ret

您可以看到 20 处的调用具有重定位信息wprintf(在 21 处,就在与到调用目标的偏移量相对应的字节处)。链接器 ( ld) 在链接时使用此信息用函数的最终解析地址修补指令。

Hopper 似乎使用了重定位信息符号的名称来进行更友好的反汇编。