.dtors看起来可写,但尝试编写segfault


9

这是Ubuntu 9.04、2.6.28-11-server,32位x86


$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
...
$ ./test
Segmentation fault
$

对于未初始化的对象:gcc .dtors在elf可执行文件中创建一个析构函数段,该段在main()退出后调用。该表长期可写,在我看来,它应该是可写的(请参阅readelf输出)。但是尝试写入表会导致段错误。

我知道最近有一种向只读.dtors前进的趋势,但是我不明白的是,段之间的不匹配readelf


真正的问题是为什么您希望它可写?
alex

1
我正在教授一个安全类,其中涉及破坏一系列易受攻击的程序,但其中一个练习涉及编写.dtors来执行Shell代码。它不再起作用,我正试图找出问题所在。
Fixee 2011年

之所以不匹配,是因为那里可能存在一些数据重定位(在将其标记为只读之前需要修复,并且无论如何也不能延迟,因此一旦修复将保持不变)。
ninjalj 2011年

Answers:


5

这些部分标记为GNU_RELRO(只读重定位),这意味着一旦动态加载程序修复了所有重定位(在加载时,那里没有惰性重定位),它将这些部分标记为只读。请注意,大多数.got.plt内容位于另一页上,因此没有得到处理。

您可以使用查看链接器脚本ld --verbose,如果您搜索RELRO,则会发现类似以下内容:

.got            : { *(.got) }
. = DATA_SEGMENT_RELRO_END (12, .);
.got.plt        : { *(.got.plt) }

这意味着RELRO节以12个字节结尾.got.plt(动态链接器函数的指针已解析,因此可以标记为只读)。

强化的Gentoo项目在http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO上有一些有关RELRO的文档。


5

尽管我实际上不知道系统的哪个部分负责,但我可以说出它为什么会失败。虽然.dtors在二进制文件中被标记为可写,但看起来它(以及.ctors,GOT和其他一些东西)被映射到内存中单独的不可写页面。在我的系统上,.dtors放置在0x8049f14

$ readelf -S test
  [17] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
  [20] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4
  [21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [22] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   0  4
  [23] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4

如果我运行可执行文件并检查/proc/PID/maps,我会看到:

08048000-08049000 r-xp 00000000 08:02 163678     /tmp/test
08049000-0804a000 r--p 00000000 08:02 163678     /tmp/test
0804a000-0804b000 rw-p 00001000 08:02 163678     /tmp/test

.data/ .bss仍可在自己的页面中写入,但其中的其他字符0x8049000-0x804a000则不可。我认为这是内核中的安全功能(正如您所说的,“最近有向只读.dtors,plt转移的趋势”),但是我不知道它的具体含义(OpenBSD具有与之非常相似的称呼。W ^ X; Linux具有PaX,但大多数内核中均未内置)

您可以使用来解决它mprotect,它使您可以更改页面的内存属性:

mprotect((void*)0x8049000, 4096, PROT_WRITE);

这样,我的测试程序就不会崩溃,但是,如果我尝试用另一个函数的地址覆盖.dtors0x8049f18)的结尾标记,则该函数仍不会执行;那部分我不知道。

希望其他人知道什么导致页面只读,以及为什么修改.dtors似乎对我的系统没有任何作用


3
如果带有PaX的OP Linux mprotect无法使可执行文件页面可写或使页面可执行文件之前是可写的,除非使用禁用了该功能paxctl -m
stribika 2011年

@stribika啊,很高兴认识
Michael Mrozek
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.