Posso dire perché sta fallendo, anche se in realtà non so quale parte del sistema sia responsabile. Mentre .dtors
è contrassegnato come scrivibile nel file binario, sembra che (insieme a .ctors
, GOT e poche altre cose) vengano mappati in una pagina separata, non scrivibile in memoria. Sul mio sistema, .dtors
viene messo a 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
Se eseguo il file eseguibile e controllo /proc/PID/maps
, vedo:
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
sono ancora scrivibili nella propria pagina, ma gli altri 0x8049000-0x804a000
non lo sono. Presumo che questa sia una funzionalità di sicurezza nel kernel (come hai detto, "c'è stato un movimento verso di sola lettura .dtors, plt, got ultimamente"), ma non so esattamente come si chiama (OpenBSD ha qualcosa di molto simile chiamato W ^ X ; Linux ha PaX , ma non è integrato nella maggior parte dei kernel)
Puoi aggirarlo con mprotect
, che ti consente di modificare gli attributi in memoria di una pagina:
mprotect((void*)0x8049000, 4096, PROT_WRITE);
Con ciò, il mio programma di test non si arresta in modo anomalo, ma se provo a sovrascrivere la sentinella di fine di .dtors
( 0x8049f18
) con l'indirizzo di un'altra funzione, quella funzione non viene ancora eseguita; quella parte che non riesco a capire.
Spero che qualcun altro sappia qual è il responsabile della lettura della pagina in modo semplice e perché la modifica .dtors
non sembra fare nulla sul mio sistema