Guida [SUORCE]C++ CodeCave super commentato + BaseAddress

Stato
Discussione chiusa ad ulteriori risposte.

GabriPr0

Utente Electrum
25 Aprile 2009
303
13
32
132
Ultima modifica da un moderatore:
PREMESSA

Credo che questa guida possa essere la diretta continuazione di quella che avevo postato qualche settimana fa.
[FOR ALL] UTILIZZARE IL "CODE INJECTION" DI CE (code cave)


Conviene leggerla perchè è quasi fondamentale.
In questa guida spiegherò infatti come scrivere un programma che modifica i byte di un programma.
Penso anche che postare interi suorce senza sapere come funzionano sia inutile.
Inoltre utilizzerò un funzione per ottenere il BaseAddress.

OCCORENTE

Un compilatore in C++ (io ho usato DEV-C++ )
CheatEngine o un qualunque debugger. Io uso CE e Olly
Pazienza Asd!

PARTIAMO

Non metto screen (è di una facilità incredibile XD).
Nell'altra guida ho spiegato come fare un CodeCave con Cheat Engine. CE però scrive su address liberi che sceglie in modo "Random"
A noi serve un address sempre libero. Come trovarlo? Aprire Solitario con OllyDBG e scorrere fino in fondo.
Troverete una zona con molti Address con un opcode del genere
Codice:
 ADD BYTE PTR DS:[EAX], AL
Questi sono degli address liberi che il programma alloca nella memoria ma non usa. Prendiamone uno a caso. Io prenderò
2AF721. Non vi preoccupate se ne avete uno diverso. Molti dei programmi di sistema (diciamo pure tutti) hanno un "allocazione dinamica"
ma diversa da quella che siamo abituati a vedere. Non si tratta di pointer. Il programma ogni volta che spengiamo-accendiamo il PC
cambia il BaseAddress ovvero l'address da cui inizia l'allocazione. Il nostro hack quindi sarà diverso dai soliti che vedete in giro.
Segnamoci l'address e cerchiamo di capire quant'è in questo caso il nostro BaseAddress.
In Cheat Engine è scritto sopra l'Hex Dump nel Debugger (memory view). In olly invece basta andare "all'inizio"
del programma. L'address base è dato delle prime due cifre... (esempio se la prima operazione che vedo è all'address
00236000 il base address sarà 00230000)
Apriamo quindi la calcolatrice e sottraiamo all'address che avevamo segnato l'address base. Quindi 2AF721 - 230000 = 7F721
Stessa cosa per l'address che dobbiamo modificare (guarda nell'altra guida inc[eax+08] 256A5E - 230000 = 26A5E
Segnamoci i risultati. Ora apriamo il Solitario e attacchiamo il processo con CE. Andiamo all'Address 256A5E (quello da scrivere. come trovarlo è sulla parte 1). Quindi clic destro, go to e mettere address.
Vediamo che l'opcode è INC[EAX+08]. Segnamoci l'opcode della CALL che si trova sotto la nostra istruzione "call 00254CF2" nel mio caso.
Ora clicchiamo due volte e modifichiamo l'assembly di inc eax ecc. con quello che ci interessa ovvero jmp (address che abbiamo segnato prima, io 2AF721). Quindi jmp 2AF721. Vi chiederà di settare dei Nop.
Naturalmente risponde sì. Scrivetevi i byte che sono stati scritti (io ho segnato "e9 be 8c 00 00 90 90 90").
Ora andate cliccate col destro sulla istruzione jmp.. e fate follow.
Troverete gli address liberi che avevamo visto prima con Olly. Modifichiamo quindi con quello che vogliamo.
Essendo il seguito dell'altra guida io metto
Codice:
 dec[eax+08] , (la call che ci siamo segnati) call 254cf2 , (dopo questa operazione deve tornare indietro 
quindi appena dopo i nop che abbiamo settato ovvero all'adress 256a66), jmp 256a66
Scriviamo tutti i byte che sono stati scritti.
Bene siamo arrivati al suorce.
Chiudiamo tutto e apriamo dev. Questo è il suorce. Davvero troppo commentato.
PHP:
 //Spero possa essere d'aiuto questa guida...
//Per eventuali informazioni [email protected] o mandami un PM.
#include <windows.h> 
#include <iostream> 
#include <tlhelp32.h>


using namespace std;
//Funzione fatta da me. Restituisce il Pid o il BaseAddress conoscendo il nome
//del processo e del modulo. Il terzo argomento invece specifica se restituire il pid
//o l'address ( mettere True per far restituire il pid).
DWORD PidOrBaseAddress(LPSTR NomeProcesso , LPSTR NomeModulo, BOOL Set);
HANDLE Processo();

int main() {
    HANDLE hProcess = Processo();
    DWORD BaseAddress;
    
    //Come secondo argomento ho messo NULL perchè il NomeModulo è uguale al NomeProcesso
    //e False come terzo argomento (devo far restituire Base Address).
    BaseAddress = PidOrBaseAddress("Solitaire.exe" , NULL , FALSE );
    if (BaseAddress == 1) {
        cout << "Impossibile trovare il processo!" << endl;
        system("pause");
    }
    else if (BaseAddress == 0) {
        cout << "Impossibile trovare il modulo!" << endl;
        system("pause");
    }

    
    //Dichiarazione dei Byte da scrivere.
    //Sono quelli che ci siamo segnati durante la guida.
    //L'array JumpNop sono i byte del jmp mentre Operazione quello che viene svolto e il ritorno. 
    BYTE JumpNop[] = { 0xe9 , 0xbe , 0x8c , 0x05 , 0x00 , 0x90 , 0x90 , 0x90 } ;
    BYTE Operazione[] = { 0xff , 0x48 ,  0x08, 0xe8 ,0xc9 , 0x55 , 0xfa , 0xff , 0xe9 , 0x38 , 0x73 , 0xfa , 0xff};

    //Address da scrivere. Ho sommato il BaseAddress con l'address che devo scrivere.
    int Address = BaseAddress + 0x7F721 ; //Mettiamo qui il risultato del calcolo 2AF721 - 230000 = 7F721
    int Address2 = BaseAddress + 0x26A5E ; // e qui 256A5E - 230000 = 26A5E

    //Scrivo sul processo (hProcess) e sul address ((LPVOID)Address) i byte che mi interessano (Operazione).
    //Il quarto argomento è il numero dei byte da scrivere ovvero la dimensione dell'array di byte.
    WriteProcessMemory(hProcess, (LPVOID)Address,  &Operazione, sizeof(Operazione), NULL);
    WriteProcessMemory(hProcess, (LPVOID)Address2, &JumpNop, sizeof(JumpNop), NULL);
    return 0;
}

//Funzione che restituisce l'handle del processo:
//in molti suorce si trova l'api FindWindow ma secondo me è meglio
//specificare il nome del processo e non il nome della finestra.
HANDLE Processo() {
    //Qui ho usato la mia funzione per restituire l'ID del processo.
    //Ho messo True infatti come terzo argomento e NULL come secondo.     
    DWORD proc_id = PidOrBaseAddress("Solitaire.exe" , NULL , TRUE);
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc_id);  
    return hProcess;
}


//La mia funzione che ho già commentato prima... credo non ci sia altro da dire!
DWORD PidOrBaseAddress(LPSTR NomeProcesso , LPSTR NomeModulo , BOOL Set) {
    //Se l'argomento NomeModulo è NULL allora      
    if(NomeModulo == NULL) {
        NomeModulo = NomeProcesso;
    }    
    DWORD process_id = 0;
    
    //Dichiarazione della struttura PROCESSENTRY32. Salva le informazioni dell'API "CreateToolhelp32Snapshot".    
    PROCESSENTRY32 StrutturaP;
    
    //"CreateToolhelp32Snapshot" crea un instantanea (Snapshot) dei processi, dei moduli ecc.
    //Qui mi sembra fondamentale mettere la documentazione.. http://msdn.microsoft.com/en-us/library/ms682489%28VS.85%29.aspx
    HANDLE SnapshotPr = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
    //Come dice la documentazione prima di poter usare la struttura va dichiarata la sua dimensione.
    StrutturaP.dwSize = sizeof(PROCESSENTRY32);
    
    //Process32First ritorna le informazioni del primo processo in una istantanea di sistema. 
    // http://msdn.microsoft.com/en-us/library/ms684834%28VS.85%29.aspx
    Process32First(SnapshotPr , &StrutturaP);
    
    //Se process_id è 0 (non è stato ancora "trovato") inizia il ciclo
    while (process_id == 0) {
        //Se il nome del Processo della struttura è uguale a quello del Processo che mi serve
        //(strcmp ritorna 0 se le stringhe sono uguali)
        if(strcmp( StrutturaP.szExeFile, NomeProcesso ) == 0 ) {
            //Process_id diventa uguale a th32ProcessID. Per informazioni vedi documentazione
            //della struttura.
            process_id = StrutturaP.th32ProcessID;
            
            //Chiudo l'Handle
            CloseHandle(SnapshotPr);
        }
        //Se sono diverse Process32Next restituisce le informazione del prossimo processo e torna all'inizio del ciclo.
        // http://msdn.microsoft.com/en-us/library/ms684836%28VS.85%29.aspx
        Process32Next(SnapshotPr , &StrutturaP);
        DWORD Error = GetLastError();
        
        //Se la funzione Process32Next non trova altri processi
        //restituisce l'errore ERROR_NO_MORE_FILES.
        //Se trova l'errore quindi la funzione ritorna 1
        if (Error == ERROR_NO_MORE_FILES) {
            return 1;
        }
    }
    
    //Se il terzo argomento è True allora restituisce il PID.
    if(Set == TRUE) {
        return process_id;
    }
    //Come prima un altra struttura. Questa però salva le informazioni dei moduli di un processo
    // http://msdn.microsoft.com/en-us/library/ms684225%28VS.85%29.aspx
    MODULEENTRY32 StrutturaM;
    
    //Stavolta faccio un istantanea dei moduli del processo di cui ho specificato il PID
    //trovato prima.
    HANDLE SnapshotMd = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, process_id );
    
    //Stessa cosa: devo specificare la dimensione della struttura.
    StrutturaM.dwSize = sizeof(MODULEENTRY32);
    
    //Module32First restituisce le informazioni del primo modulo di un
    //processo e le salva nella struttura MODULEENTRY32
    Module32First(SnapshotMd , &StrutturaM);
    
    while (1) {
        //Come prima: se le stringhe sono uguali
        if(strcmp( StrutturaM.szModule, NomeModulo ) == 0 )    {
            //la funzione ritorna il BaseAddress del modulo e
            return (DWORD)StrutturaM.modBaseAddr;
        
            //chiudo l'Handle.
            CloseHandle(SnapshotMd);
        }
        //Oppure uso la funzione Module32Next per restituire
        //le informazioni del prossimo modulo e ricominciare il ciclo.
        //Se non ci sono altri moduli
        Module32Next(SnapshotMd , &StrutturaM);
    
        //la funzione GetLastError ritorna ERROR_NO_MORE_FILES
        DWORD Error2 = GetLastError();
    
        //se trova l'errore quindi ritorna 0
        if (Error2 == ERROR_NO_MORE_FILES) {
            return 0;
        }
    }
}
Se avete qualunque problema non esitate a scrivere.
I +1 non mordono :D
 
Ristrutturazione sezioni
Discussione rimossa dal rilievo. Motivo: tutorial troppo superficiale, non adatta al livello della community (potrebbe essere migliorata nei prossimi giorni).
 
Stato
Discussione chiusa ad ulteriori risposte.