ELF - 验证可执行内存区域

时间:2016-03-24 01:55:56

标签: linux memory shared-libraries elf

我正在学习精灵二进制文件。我想手动验证程序中编写的代码是否在可执行的内存区域(对于要链接的共享库的代码也一样)。

我有一个简单的程序:

int main() { return 0; }

当我这样做时:

readelf -a myprog

我得到以下内容:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000040 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0804820c 00020c 000045 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048252 000252 000008 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0804825c 00025c 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             0804827c 00027c 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048284 000284 000010 08   A  5  12  4
  [11] .init             PROGBITS        08048294 000294 00002e 00  AX  0   0  4
  [12] .plt              PROGBITS        080482d0 0002d0 000030 04  AX  0   0 16
  [13] .text             PROGBITS        08048300 000300 00016c 00  AX  0   0 16
  [14] .fini             PROGBITS        0804846c 00046c 00001a 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048488 000488 000008 00   A  0   0  4
  [16] .eh_frame_hdr     PROGBITS        08048490 000490 000034 00   A  0   0  4
  [17] .eh_frame         PROGBITS        080484c4 0004c4 0000c4 00   A  0   0  4
  [18] .ctors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049f1c 000f1c 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049f24 000f24 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f28 000f28 0000c8 08  WA  6   0  4
  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049ff4 000ff4 000014 04  WA  0   0  4
  [24] .data             PROGBITS        0804a008 001008 000008 00  WA  0   0  4
  [25] .bss              NOBITS          0804a010 001010 000008 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 001010 00002a 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 00103a 0000fc 00      0   0  1
  [28] .symtab           SYMTAB          00000000 0015e8 000400 10     29  45  4
  [29] .strtab           STRTAB          00000000 0019e8 0001ea 00      0   0  1

要检查程序代码是否可执行,我可以看到标有.text的{​​{1}}部分。这里的AX是否可以使X函数中的代码可执行?

当程序在运行时动态链接时,将加载共享库(例如glibc)的哪个部分?我在网上找到了解释在动态链接的背景下使用GOT,PLT的解释。标记为main()的唯一部分为Xinitplt(除fini之外)。共享库是否链接到其中一个部分,以确保在程序开始执行时它们的代码是可执行的?

(如果在回答上述内容时可以指出一些参考文件会很棒)

1 个答案:

答案 0 :(得分:2)

  

X这里是否可以执行我的main()函数中的代码?

正确。虽然涉及的不仅仅是main()函数;还有一些其他代码链接到您的可执行文件中,该代码也包含在本节中。

  

当程序在运行时动态链接时,将加载共享库(例如glibc)的哪个部分?

他们都不是。共享库是一个单独的ELF对象,它有自己的部分,其中一些是可执行的;它本质上是一起加载,而不是加载到中。也就是说,内存中生成的图像将包含可执行文件的.text部分以及它已加载的所有共享库中的许多其他.text(以及其他类型的)部分。

例如,以下是我的Linux系统上正在运行的/proc/self/maps进程的/bin/cat内容。此输出的格式与readelf向您显示的格式不同,但是一些相似之处应该变得明显:

00400000-0040b000 r-xp 00000000 08:00 32968                              /bin/cat
0060a000-0060b000 r--p 0000a000 08:00 32968                              /bin/cat
0060b000-0060c000 rw-p 0000b000 08:00 32968                              /bin/cat
0242a000-0244b000 rw-p 00000000 00:00 0                                  [heap]
7fdf299a2000-7fdf29c6b000 r--p 00000000 08:00 949                        /usr/lib/locale/locale-archive
7fdf29c6b000-7fdf29e26000 r-xp 00000000 08:00 18508                      /lib/x86_64-linux-gnu/libc-2.19.so
7fdf29e26000-7fdf2a025000 ---p 001bb000 08:00 18508                      /lib/x86_64-linux-gnu/libc-2.19.so
7fdf2a025000-7fdf2a029000 r--p 001ba000 08:00 18508                      /lib/x86_64-linux-gnu/libc-2.19.so
7fdf2a029000-7fdf2a02b000 rw-p 001be000 08:00 18508                      /lib/x86_64-linux-gnu/libc-2.19.so
7fdf2a02b000-7fdf2a030000 rw-p 00000000 00:00 0
7fdf2a030000-7fdf2a053000 r-xp 00000000 08:00 18255                      /lib/x86_64-linux-gnu/ld-2.19.so
7fdf2a246000-7fdf2a249000 rw-p 00000000 00:00 0
7fdf2a250000-7fdf2a252000 rw-p 00000000 00:00 0
7fdf2a252000-7fdf2a253000 r--p 00022000 08:00 18255                      /lib/x86_64-linux-gnu/ld-2.19.so
7fdf2a253000-7fdf2a254000 rw-p 00023000 08:00 18255                      /lib/x86_64-linux-gnu/ld-2.19.so
7fdf2a254000-7fdf2a255000 rw-p 00000000 00:00 0
7ffd516aa000-7ffd516cb000 rw-p 00000000 00:00 0                          [stack]
7ffd517f9000-7ffd517fb000 r--p 00000000 00:00 0                          [vvar]
7ffd517fb000-7ffd517fd000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

特别是,您可以看到从顶部的/bin/cat加载了三个部分:第一部分是可执行的(r-xp),第二部分是只读的(r--p) ,第三个是读写(rw-p)。此外,还有许多可执行和不可执行的段从libc-2.19.so以及ld-2.19.so(动态链接器)映射。

(在这个转储中也出现了一些有些神秘的段,包括[vdso][vsyscall]。这些段由内核映射到进程中,很难解释;我不会得到进入他们。)