Je peux dire pourquoi cela échoue, même si je ne sais pas vraiment quelle partie du système est responsable. Bien qu'il .dtors
soit marqué en écriture dans le binaire, il semble qu'il (avec .ctors
le GOT et quelques autres choses) soit mappé dans une page séparée et non inscriptible en mémoire. Sur mon système, .dtors
se met à 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
Si je lance l'exécutable et vérifie /proc/PID/maps
, je vois:
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
sont toujours inscriptibles dans leur propre page, mais les autres 0x8049000-0x804a000
ne le sont pas. Je suppose que c'est une fonctionnalité de sécurité dans le noyau (comme vous l'avez dit, "il y a eu un mouvement vers readonly .dtors, plt, got dernièrement"), mais je ne sais pas précisément comment il s'appelle (OpenBSD a quelque chose de très similaire appelé W ^ X ; Linux a PaX , mais n'est pas intégré à la plupart des noyaux)
Vous pouvez le contourner avec mprotect
, ce qui vous permet de modifier les attributs en mémoire d'une page:
mprotect((void*)0x8049000, 4096, PROT_WRITE);
Avec cela, mon programme de test ne plante pas, mais si j'essaie d'écraser la sentinelle de fin de .dtors
( 0x8049f18
) avec l'adresse d'une autre fonction, cette fonction ne s'exécute toujours pas; cette partie que je ne peux pas comprendre.
J'espère que quelqu'un d'autre sait ce qui est responsable de rendre la page en lecture seule, et pourquoi la modification .dtors
ne semble rien faire sur mon système