Un altro esempio per fare capire che alla fine un puntatore è di fatto un indirizzo è quello che alla fine è alla base del concetto di buffer overflow nelle tecniche di hacking.
Se noi prendiamo un programma e lo guardiamo con il debug in modalità esadecimale possiamo vedere le istruzioni binarie come se fossero degli array di numeri.
Ad esempio un programmino molto corto chiamato boot.com che non faceva altro che resettare la macchina può essere visto in modalità esadeciomale ed essere assegnato ad un array di numeri interi.
Codice:
unsigned char array[] = {
/* ---- [CODICE DI BOOT.COM] ---- */
0xFB,0x31,0xDB, /* FB STI */
0x8E,0xDB,0xBB, /* 31DB XOR BX,BX */
0x72,0x04,0xB8, /* 8EDB MOV DS,BX */
0x34,0x12,0x89, /* BB7204 MOV BX,0472 */
0x07,0xEA,0x00, /* B83412 MOV AX,1234 */
0x00,0xFF,0xFF /* 8907 MOV [BX],AX */
/* EA0000FFFF JMP FFFF:0000 */
/* ------------------------------- */
};
Ora se dichiarassimo un puntaore a funzione in pratica avremmo uno spazio in memoria per contenere un indirizzo, che si suppone essere di una funzione.
Il C possiede il concetto di CAST o forzatura.
In pratica un certo tipo viene forzato ad assumere le proprietà di un altro tipo.
Per cui se noi avessimo il puntatore a funzione :
void (far *funct)()
&array[0] o semplicemente array (gli array il c li vede come indirizzi) sarebbe a questo punto l'indirizzo del primo elemernto del vettore.
Ma se mediante un cast noi lo assegnassimo al puntaore a funzione con :
void (*funct)() = (void(*)()) array;
costringeremmo il C a vedere funct come un puntatore a funzione il cui indirizzo di fatto è quello del primo elemento dell'array.
Ma una funzione può essere richiamata !
E quindi ....
(*funct)();
non farebbe altro che chiamare la funziopne all'indirizzo &array[0].
Il C salterebbe a questo indirizzo convinto che sia una funzione e quindi eseguirebbe i codici all'interno che di fatto sono querlli di boot.com ....
Detto in altre parole: come fare eseguire al sistema dei numeri esadecimali (convincendolo che sono codici operativi binari) !!!