Puedo decir por qué está fallando, aunque en realidad no sé qué parte del sistema es responsable. Si bien .dtors
está marcado como editable en el binario, parece que (junto con .ctors
el GOT y algunas otras cosas) se están asignando a una página separada y no editable en la memoria. En mi sistema, .dtors
se está poniendo en 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 ejecuto el ejecutable y compruebo /proc/PID/maps
, veo:
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
todavía se pueden escribir en su propia página, pero los demás 0x8049000-0x804a000
no. Supongo que esta es una característica de seguridad en el kernel (como dijiste, "ha habido un movimiento hacia solo .dtors, plt, últimamente"), pero no sé específicamente cómo se llama (OpenBSD tiene algo muy similar llamado W ^ X ; Linux tiene PaX , pero no está integrado en la mayoría de los núcleos)
Puede solucionarlo con mprotect
, lo que le permite cambiar los atributos en memoria de una página:
mprotect((void*)0x8049000, 4096, PROT_WRITE);
Con eso, mi programa de prueba no se bloquea, pero si intento sobrescribir el centinela final de .dtors
( 0x8049f18
) con la dirección de otra función, esa función aún no se ejecuta; esa parte no puedo entenderlo.
Esperemos que alguien más sepa qué es responsable de hacer que la página sea de solo lectura y por qué la modificación .dtors
no parece hacer nada en mi sistema