1

我很好奇程序是怎样的readelfobjdump并且知道在指令gdb旁边显示什么。callq既然程序还没有运行,他们怎么知道要“通过”多远.plt?他们是否根据传递给它的参数进行猜测?或者他们是否真的对程序进行了模拟运行以找出答案?

例如:

  400ca4:       e8 e7 fb ff ff          callq  400890 <printf@plt>
  400ca9:       48 8b 85 28 ff ff ff    mov    -0xd8(%rbp),%rax

上面的代码知道去printf()0x400890.plt处:

0000000000400890 <printf@plt>:
  400890:       ff 25 ba 17 20 00       jmpq   *0x2017ba(%rip)        # 602050 <_GLOBAL_OFFSET_TA$
  400896:       68 07 00 00 00          pushq  $0x7
  40089b:       e9 70 ff ff ff          jmpq   400810 <_init+0x20>

这只是输出,objdump -d所以我不确定程序是如何知道它想要的printf。我能看到的唯一相关性是重定位索引 ( pushq $0x7) 和 section .dynsym,尽管它是一个值,因为它从 0 开始:

8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)

让我感到困惑的另一件事是.plt条目中对 GOT 的引用 (#602050)。从中我看到readelf它是.got.plt基于地址范围的一部分,但是这些程序是如何在程序运行之前确定该值的呢?

[23] .got.plt          PROGBITS         0000000000602000  00002000
       00000000000000b8  0000000000000008  WA       0     0     8

** 编辑 **

Symbol table '.dynsym' contains 22 entries:

       Num:    Value          Size Type    Bind   Vis      Ndx Name
         0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.2.5 (2)
         2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND putchar@GLIBC_2.2.5 (2)
         3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strncpy@GLIBC_2.2.5 (2)
         4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
         5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fclose@GLIBC_2.2.5 (2)
         6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strlen@GLIBC_2.2.5 (2)
         7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (3)
         8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
         9: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
        10: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND ftell@GLIBC_2.2.5 (2)
        11: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
        12: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND malloc@GLIBC_2.2.5 (2)
        13: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _IO_getc@GLIBC_2.2.5 (2)
        14: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fseek@GLIBC_2.2.5 (2)
        15: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fopen@GLIBC_2.2.5 (2)
        16: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND perror@GLIBC_2.2.5 (2)
        17: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND getopt@GLIBC_2.2.5 (2)
        18: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND atoi@GLIBC_2.2.5 (2)
        19: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.2.5 (2)
        20: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fwrite@GLIBC_2.2.5 (2)
        21: 0000000000400a4d    34 FUNC    GLOBAL DEFAULT   13 err
4

1 回答 1

0

这其中的一部分已经失忆了,但让我们看看我是否不能帮助你......

至于你的第一个问题,有一连串的事情联系在一起。我不能保证这就是这些工具的工作方式,只是为了表明有一种方法。

  1. PLT 与 .rel(a).plt 部分具有一对一的对应关系(PLT[0] 除外,这是特殊的)。本节包含 PLT 条目的重定位。
  2. 每个.rel(a).plt 条目都有一个信息字段,该字段具有符号表索引,例如.dynsym。
  3. 每个符号表条目在字符串表(例如 .dynstr)中都有一个偏移量作为其名称。此偏移量是从字符串部分开头开始的字节偏移量。

如您所见,您可以按照 PLT 找到 rel(a).plt、符号表、字符串表,您会在其中找到“printf”。

要回答您的第二个问题,请查看程序标头 ( readelf -Wl <program>),您将看到不同部分的虚拟地址。这就是地址范围的来源。

于 2014-10-02T15:57:08.900 回答