2013-11-17 15 views
6

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.

+1

Cercare "shellcode" nel WEB. –

+2

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

+1

Correlati: [Prevenzione dell'esecuzione dei dati su Wikipedia] (https://en.wikipedia.org/wiki/Data_execution_prevention) – user2802841

risposta

3

In effetti è possibile riempire un array con codice macchina x86 e tentare di eseguirlo. Si chiama shellcode e riesce a fare in modo che un'applicazione o una libreria eseguano tale codice quando non era destinato a essere chiamato "exploit".

Sfortunatamente non è così facile, poiché l'hardware e il sistema operativo moderni normalmente impediscono l'esecuzione del codice da aree scrivibili, come ad esempio array di caratteri non const. Questo è chiamato W^X (permessi di scrittura o di esecuzione, ma non entrambi) Ma è possibile richiedere sistemi operativi conformi a POSIX per disabilitare tale protezione con la funzione mprotect(). Ecco un esempio che funziona, poiché abilita le autorizzazioni di lettura, scrittura ed esecuzione sulla serie di byte di codice macchina interessati:

#include <stdio.h> 
#include <stdint.h> 
#include <sys/mman.h> 


typedef int(*FUNKY_POINTER)(void); 


char shellcode[] = { 
    0xb8, 0x2a, 0x00, 0x00, 0x00, //mov $0x2a,%eax 
    0xc3       //retq 
}; 



int main(void){ 
    uintptr_t pageSize  = 4096; 
    uintptr_t shellcodeAddr = (uintptr_t)shellcode; 
    uintptr_t pageAlignedAddr = shellcodeAddr & ~(pageSize-1); 
    FUNKY_POINTER shellcodeFn = (FUNKY_POINTER)shellcode; 

    /* Magic */ 
    mprotect((void*)pageAlignedAddr, 
      (shellcodeAddr - pageAlignedAddr) + sizeof(shellcode), 
      PROT_EXEC|PROT_WRITE|PROT_READ); 

    printf("The answer to the ultimate question of life, " 
      "the universe and everything is %d\n", 
      shellcodeFn()); 

    return 0; 
} 
+0

grazie! ma sembra che mprotect() non esista su piattaforme Windows. ho usato VirtualProtect [collegamento] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366898%28v=vs.85%29.aspx) da WinAPI e mi ha permesso di eseguire shellcode. questo rude mi ha aiutato a capire cose di basso livello. – Ivars

+0

ma ancora non capisco come chiamare funzioni o modificare variabili da shellcode. – Ivars

+0

Ah ora per quello dovresti guardare qualcosa chiamato _calling convention_. http://en.wikipedia.org/wiki/X86_calling_conventions –

Problemi correlati