尽管我实际上不知道系统的哪个部分负责,但我可以说出它为什么会失败。虽然.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);
这样,我的测试程序就不会崩溃,但是,如果我尝试用另一个函数的地址覆盖.dtors
(0x8049f18
)的结尾标记,则该函数仍不会执行;那部分我不知道。
希望其他人知道什么导致页面只读,以及为什么修改.dtors
似乎对我的系统没有任何作用