Ci sono due tipi di problemi che penso tu stia confondendo. Uno è l'indirizzo delle funzioni chiamate dal tuo shellcode fornite dall'applicazione vulnerabile o dalle librerie caricate, e l'altro è salti assoluti o relativi all'interno del tuo shellcode.
Chiamate di libreria
Supponiamo, per un secondo, che tu stia tentando un exploit return-to-libc su un semplice binario. Quindi vuoi l'indirizzo di system
per molti di questi exploit. Costruiamo un piccolo binario che stampa l'indirizzo di system
.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
printf("system @%p\n", system);
return 0;
}
Compila ed esegui alcune volte:
% gcc -o getsystem getsystem.c
% ./getsystem
system @0x7fdc54419d40
% ./getsystem
system @0x7fbc15b61d40
% ./getsystem
system @0x7fbeacfb6d40
Si noti che ogni volta che viene eseguito, l'indirizzo di system
è cambiato. Ciò è dovuto a una moderna mitigazione della sicurezza chiamata ASLR: la libreria C viene caricata su un indirizzo di base diverso, quindi system
verrà caricato in un indirizzo diverso. Di conseguenza, lo shellcode deve prima individuare libc, quindi chiamare system
a un indirizzo relativo all'inizio della libreria. (Chiamato "indirizzo base".)
Salta
In uno shellcode più complesso, potrebbe essere necessario creare un jmp
o call
all'interno del payload stesso. In questi casi, devi avere salti e chiamate relativi, perché non conosci l'indirizzo esatto in cui verrà caricato il codice shell. Invece di dire "salta a 0x0804abcd
", dovresti "saltare 5 byte avanti". Questo è il significato di "Position-Independent Code": può funzionare quando caricato in qualsiasi posizione, e non solo ad un indirizzo di partenza fisso.
Poiché lo shellcode di solito viene caricato nello stack o nell'heap, entrambi sono soggetti a varie manipolazioni (ASLR, altri dati che utilizzano lo stack / heap, threading, ecc.), è impossibile prevedere un indirizzo assoluto in cui lo shellcode terreni.