Я могу сказать, почему это терпит неудачу, хотя я фактически не знаю, какая часть системы ответственна. Хотя .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
нет. Я предполагаю, что это функция безопасности в ядре (как вы сказали, «в последнее время наблюдается движение к readonly .dtors, plt, got»), но я не знаю, как именно это называется (в OpenBSD есть нечто очень похожее, называемое W ^ X ; Linux имеет PaX , но не встроен в большинство ядер)
Вы можете обойти это с помощью mprotect
, который позволяет вам изменять атрибуты в памяти страницы:
mprotect((void*)0x8049000, 4096, PROT_WRITE);
При этом моя тестовая программа не завершается сбоем, но если я попытаюсь перезаписать конечный страж функции .dtors
( 0x8049f18
) адресом другой функции, эта функция все равно не будет выполнена; эту часть я не могу понять.
Надеюсь, кто-то еще знает, что отвечает за то, чтобы сделать страницу доступной только для чтения, и почему изменение .dtors
, похоже, ничего не делает в моей системе