La mia domanda è dedicata principalmente ai prof e riguarda l'uso di C++ in modo "strano". In C++ non c'è davvero una grande differenza tra i puntatori alle variabili e i puntatori alle funzioni. Possiamo fare qualcosa di inutile in questo modo:Come eseguire i comandi x86 dal buffer di dati?
char* buff = new char[32];
void (*func)() = (void (*)())buff;
Ma abbiamo creato una funzione che non è mai esistita, giusto? Cosa succede se andiamo oltre e riempiamo buff con i comandi x86 stord in un file? Il sistema operativo non saprà mai che è stata creata una funzione.
#include <iostream>
using namespace std;
// no stack push'ing or pop'ing, nothing to return
void func(void){cout << "Hello?";}
int main()
{
char* x86_code = new char[6];
x86_code[0] = 0x9A; // call (far)
*((__int32*)(x86_code + 1)) = (__int32)func; // load 32-bit address
x86_code[5] = 0xC3; // ret
void (*x86_func)(void) = (void (*)(void))x86_code;
x86_func();
return 0;
}
Calling x86_func() fa un errore di runtime (violazione posizione lettura 0xFFFFFFFF). In che modo il sistema operativo carica i suoi binari o moduli nella RAM se non in questo modo? Grazie molto.
Cercare "shellcode" nel WEB. –
Non chiamare lontano. Questo è quasi sicuramente non corretto nel codice a 32 bit. Utilizzare una chiamata quasi assoluta (opcode 0xFF con il campo reg nel byte ModRM impostato su 2) (o una chiamata quasi normale, ma tenere presente che è relativa). Inoltre, potrebbe essere necessario effettuare alcune chiamate di sistema per rendere tale memoria eseguibile. – harold
Correlati: [Prevenzione dell'esecuzione dei dati su Wikipedia] (https://en.wikipedia.org/wiki/Data_execution_prevention) – user2802841