我写了一个启用了PIE / PIC的“hello world”程序。我观察到程序头有2个LOAD条目:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
... ...
LOAD 0x000000 0x00000000 0x00000000 0x00870 0x00870 R E 0x1000
LOAD 0x000eb0 0x00001eb0 0x00001eb0 0x0015c 0x00164 RW 0x1000
因此,根据我的理解,ELF二进制文件将被加载到2页。第一页包含从偏移0到文件大小0x870的二进制文件,它是Read&执行。由于它们是0x1000对齐,第二个条目将加载到第二页,其中包含二进制文件(从偏移 0xeb0 到 0xeb0 + 0x15c )。这个页面有Read&写权限。
当我“pmap”正在运行的进程(或cat / proc / pid / maps)时,它显示正在运行的程序有3个页面:
b7554000 4K rw--- [ anon ]
b7555000 1700K r-x-- libc-2.19.so
b76fe000 4K ----- libc-2.19.so
b76ff000 8K r---- libc-2.19.so
b7701000 4K rw--- libc-2.19.so
b7702000 12K rw--- [ anon ]
b771b000 16K rw--- [ anon ]
b771f000 4K r-x-- [ anon ]
b7720000 128K r-x-- ld-2.19.so
b7740000 4K r---- ld-2.19.so
b7741000 4K rw--- ld-2.19.so
b7742000 4K r-x-- main
b7743000 4K r---- main
b7744000 4K rw--- main
bfe68000 132K rw--- [ stack ]
total 2032K
那么如何加载ELF二进制文件,以及程序头如何指示LOAD指令?
部分标题如:
[13] .text PROGBITS 00000480 000480 0002c2 00 AX 0 0 16
[14] .fini PROGBITS 00000744 000744 000014 00 AX 0 0 4
[15] .rodata PROGBITS 00000758 000758 000060 00 A 0 0 4
[16] .eh_frame PROGBITS 000007b8 0007b8 000094 00 A 0 0 4
[17] .eh_frame_hdr PROGBITS 0000084c 00084c 000024 00 A 0 0 4
[18] .jcr PROGBITS 00001eb0 000eb0 000004 00 WA 0 0 4
[19] .fini_array FINI_ARRAY 00001eb4 000eb4 000004 00 WA 0 0 4
[20] .init_array INIT_ARRAY 00001eb8 000eb8 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 00001ebc 000ebc 000108 08 WA 5 0 4
[22] .got PROGBITS 00001fc4 000fc4 00001c 00 WA 0 0 4
[23] .got.plt PROGBITS 00001fe0 000fe0 000020 00 WA 0 0 4
[24] .data PROGBITS 00002000 001000 00000c 00 WA 0 0 4
[25] .tm_clone_table PROGBITS 0000200c 00100c 000000 00 WA 0 0 4
[26] .bss NOBITS 0000200c 00100c 000008 00 WA 0 0 4
答案 0 :(得分:4)
我观察到程序头有2个LOAD条目:
您省略了一个重要的程序标题:GNU_RELRO
,它告诉加载程序在映射LOAD
段后它应该mprotect
部分只读。
当在现有映射上调用具有不同权限的mprotect
时,内核必须将该映射拆分为多个映射,这是额外条目的来源。
在我的测试二进制文件中:
LOAD 0x000000 0x00000000 0x00000000 0x0075c 0x0075c R E 0x1000
LOAD 0x000ef4 0x00001ef4 0x00001ef4 0x0012c 0x00130 RW 0x1000
...
GNU_RELRO 0x000ef4 0x00001ef4 0x00001ef4 0x0010c 0x0010c R 0x1
内核实际上在加载器开始之前映射LOAD
段,此时的映射如下所示:
56555000-56556000 r-xp 00000000 fc:02 801500 /tmp/a.out
56556000-56558000 rw-p 00000000 fc:02 801500 /tmp/a.out
f7fdb000-f7fdc000 r-xp 00000000 00:00 0 [vdso]
...
在mprotect
之后,地图如下所示:
56555000-56556000 r-xp 00000000 fc:02 801500 /tmp/a.out
56556000-56557000 r--p 00000000 fc:02 801500 /tmp/a.out
56557000-56558000 rw-p 00001000 fc:02 801500 /tmp/a.out
...