Domanda Una mano per il Reversing di un gioco

Dany Dollaro

Utente Silver
14 Luglio 2018
120
27
61
Ultima modifica:
Da quanto ho capito non si è obbligati ad eseguire l'injection di una dll, per modificare i valori interni di una funzione, ma si può tranquillamente sovrascrivere il tutto da "remoto". Qual è allora l'utilità di una dll injection? Perchè si usa, piuttosto che eseguire le call direttamente da remoto?
Gestire il tutto con una dll è molto più performante rispetto all'uso di un programma esterno che sicuramente utilizzerà l'API WriteProcessMemory.
Per cambiare un byte all'interno di un programma usando una dll ti basterà fare:
C++:
size_t* address = 0x00400000;
BYTE new_byte = 0x90;

*address = new_byte; // <-- fase di scrittura
per il semplice fatto che la dll sarà mappata nello spazio degli indirizzi virtuali del processo vittima.

Nel codice qui sopra, ho usato la variabile "DWORD address = 0x22A62C0E308;" che come puoi vedere contiene l'indirizzo di memoria della variabile da modificare. Il problema è che questo indirizzo è stato trovato per mezzo di CheatEngine, e solo dopo averlo trovato l ho aggiunto al programma. Tutte le volte che avvio il gioco, ovviamente l'indirizzo cambia e mi tocca andare a ritrovarlo tutte le volte. Avnedo utilizzato openprocess, dovrei, quindi, già avere il base-address?
DWORD address = 0x22A62C0E308; stai evidentemente salvando un valore le cui dimensioni superano i 32-bit in una DWORD, quindi il valore 0x22A00000000 verrà del tutto estromesso, per ovviare a questo problema ti basterà utilizzare una variabile più grande come: UINT64, __int64, ecc.

Ci sono differenze nel dover trovare l'indirizzo di memoria di una variabile e di una funzione:
  • Nel caso di una funzione ti basterà il nome del modulo in cui è alloggiata e l'offset, quindi dovrai enumerare i moduli del processo, trovare quello corispondente, ottenerne l'indirizzo base e sommarci l'offset, che sarà uguale a: offset = indirizzo (virtuale) assoluto della funzione - indirizzo base del modulo.
  • Nel caso di una variabile il processo è più astruso: potresti trovare un puntatore statico tramite il pointer scanner di Cheat Engine ed usarlo per rintracciare la variabile, oppure sempre tramite Cheat Engine intercetti una qualsiasi istruzione che faccia uso di tale variabile, e con una tecnica chiamata "copy injection" vai a modificare la funzione in modo che scriva il valore del puntatore della variabile in una regione di memoria da te conosciuta, un pò come un hook.
Avnedo utilizzato openprocess
Il fatto che usi l'API OpenProcess è irrilevante, il motivo per cui si chiama quella funzione è per ottenere un handle sul processo, nel caso tu non comprenda a pieno cosa sia un handle, consideralo come una 'chiave' che ti permette di interagire con il processo 'aperto'.
In più non c'entra tanto col topic ma per buona pratica anche se un programma sta per terminare si tende a chiudere gli handle in modo esplicito usando la funzione CloseHandle, ricorda che queste sono variabili paticolari (ed anche molto importanti).

Per quanto riguarda la chiamata a funzione, come sopracitato, mi prendo qualche ora domani per studiarmi il codice, la mia domanda è: quando vado a fare un reverse, come posso capire qual è la funzione che effettivamente sto cercando ?
Una convenzione di chiamata sta ad indicare come una funzione gestirà i parametri e restituirà il valore di ritorno, puoi giungere alla convenzione adoperata analizzando il codice antecedente alla chimamata di funzione, in particolare l'ordine in cui vengono effettuate le operazioni di push e mov.
Potrebbe esserti più chiaro dando un'occhiata al paragrafo "Caller clean-up" di x86 calling conventions - Wikipedia.

UPDATE: nel codice che hai riportato, in particolare questa parte:
C++:
if (std::wstring(entry.szExeFile) == targetProcessName)
puoi semplicemente sostituirla con:
C++:
if (entry.szExeFile == targetProcessName)
 
  • Mi piace
Reactions: Hastro

Hastro

Helper
14 Febbraio 2012
272
56
123
Ti ringrazio dany per la risposta molto esaustiva! Sto cercando di capirci di più e di studiare sia il tuo codice, sia quello di @JunkCoder !
Ci sono differenze nel dover trovare l'indirizzo di memoria di una variabile e di una funzione:
  • Nel caso di una funzione ti basterà il nome del modulo in cui è alloggiata e l'offset, quindi dovrai enumerare i moduli del processo, trovare quello corispondente, ottenerne l'indirizzo base e sommarci l'offset, che sarà uguale a: offset = indirizzo (virtuale) assoluto della funzione - indirizzo base del modulo.
  • Nel caso di una variabile il processo è più astruso: potresti trovare un puntatore statico tramite il pointer scanner di Cheat Engine ed usarlo per rintracciare la variabile, oppure sempre tramite Cheat Engine intercetti una qualsiasi istruzione che faccia uso di tale variabile, e con una tecnica chiamata "copy injection" vai a modificare la funzione in modo che scriva il valore del puntatore della variabile in una regione di memoria da te conosciuta, un pò come un hook
Ho alcune domande da porti su questa sezione:
  • "Nel caso di una funzione ti basterà il nome del modulo", non sembra essere il prototipo di una funzione, ma mi ha più ricordato le sub di VBA. Tuttavia se il codice è compilato, non dovrebbe avere sub, dove sto sbagliando (?)
  • "quindi dovrai enumerare i moduli del processo" in senso più concreto, a cosa corrisponde questa operazione?

  • "Nel caso di una variabile il processo è più astruso: potresti trovare un puntatore statico", il puntatore "statico" sarebbe quello che vienee direttamente allocato quando lancio il programma? l'address di questo puntatore non cambia ad ogni lancio?

Ti/Vi ringrazio per la disponibilità
 

Dany Dollaro

Utente Silver
14 Luglio 2018
120
27
61
Ultima modifica:
  • "Nel caso di una funzione ti basterà il nome del modulo", non sembra essere il prototipo di una funzione, ma mi ha più ricordato le sub di VBA. Tuttavia se il codice è compilato, non dovrebbe avere sub, dove sto sbagliando (?)
  • "quindi dovrai enumerare i moduli del processo" in senso più concreto, a cosa corrisponde questa operazione?

  • "Nel caso di una variabile il processo è più astruso: potresti trovare un puntatore statico", il puntatore "statico" sarebbe quello che vienee direttamente allocato quando lancio il programma? l'address di questo puntatore non cambia ad ogni lancio?
Mi sono appena informato sul termine "sub di VBA" e ti dico che il termine "modulo" varia molto a seconda del contesto (i miei riferimenti non hanno nulla a che vedere con il Visual Basic).
Partiamo dal fatto che io parlo di un programma scritto in C++, un linguaggio nativo che non ha bisogno di un interprete, in questo caso per modulo intendo il file eseguibile .exe che è stato mappato nello spazio degli indirizzi virtuali del processo.
Per essere più chiaro, considerando il seguente codice:
C++:
#include <iostream>

int sum(int a, int b)
{
    return a + b;
}

int main()
{
    std::cout << sum(1, 1);
}
Abbiamo in primis la funzione main e sum, ora agganciando un debugger all'eseguibile prodotto, visualizzando i moduli caricati nel processo:
moduli.png


Il primo modulo (quello in verde) è il file eseguibile stesso che io ho chiamato "progettoesempio.exe", e poi ci sono delle dll, sia il file eseguibile che le dll mappate sono definite con il termine "modulo".
Ora avendo definito il termine modulo, "Perchè nel codice sopra riportato ho aggiunto la funzione sum?" soltanto per dirti che quella funzione si troverà nel modulo "progettoesempio.exe".

in senso più concreto, a cosa corrisponde questa operazione?
Nel codice che hai riportato prima hai usato la funzione [URL='https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot']CreateToolhelp32Snapshot[/URL] usando la flag "TH32CS_SNAPPROCESS", e se dai un'occhiata alla documentazione vedrai anche la flag "TH32CS_SNAPMODULE", oppure puoi usare la funzione [URL='https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules']EnumProcessModules[/URL], il resto penso sia intuitivo.

Dettagli aggiuntivi: Per effetto dell ASLR l'indirizzo del modulo dell'exe (0x00E70000) e delle dll cambiera dopo ogni riavvio del sistema, mentre l'indirizzo delle variabili impiegate dal processo cambieranno ogni riavvio del programma stesso, potresti trovare interessante questa mia vecchia domanda sull'ASLR.

il puntatore "statico" sarebbe quello che vienee direttamente allocato quando lancio il programma? l'address di questo puntatore non cambia ad ogni lancio?
Consideralo come un puntatore che si trova sul modulo base del processo in questione, e questo puntatore punti sull'ambiente di gioco, che a sua volta comprende altri puntatori ad altre strutture inerenti al programma stesso.
 
Supporta Inforge con una donazione
Banner pubblicitario per Bright Data su Inforge.net azienda di vendita Proxy, Data Collector e Content Unlocker

Hastro

Helper
14 Febbraio 2012
272
56
123
Mi sono appena informato sul termine "sub di VBA" e ti dico che il termine "modulo" varia molto a seconda del contesto (i miei riferimenti non hanno nulla a che vedere con il Visual Basic).
Partiamo dal fatto che io parlo di un programma scritto in C++, un linguaggio nativo che non ha bisogno di un interprete, in questo caso per modulo intendo il file eseguibile .exe che è stato mappato nello spazio degli indirizzi virtuali del processo.
Per essere più chiaro, considerando il seguente codice:
C++:
#include <iostream>

int sum(int a, int b)
{
    return a + b;
}

int main()
{
    std::cout << sum(1, 1);
}
Abbiamo in primis la funzione main e sum, ora agganciando un debugger all'eseguibile prodotto, visualizzando i moduli caricati nel processo: View attachment 47352

Il primo modulo (quello in verde) è il file eseguibile stesso che io ho chiamato "progettoesempio.exe", e poi ci sono delle dll, sia il file eseguibile che le dll mappate sono definite con il termine "modulo".
Ora avendo definito il termine modulo, "Perchè nel codice sopra riportato ho aggiunto la funzione sum?" soltanto per dirti che quella funzione si troverà nel modulo "progettoesempio.exe".


Nel codice che hai riportato prima hai usato la funzione [URL='https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot']CreateToolhelp32Snapshot[/URL] usando la flag "TH32CS_SNAPPROCESS", e se dai un'occhiata alla documentazione vedrai anche la flag "TH32CS_SNAPMODULE", oppure puoi usare la funzione [URL='https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules']EnumProcessModules[/URL], il resto penso sia intuitivo.

Dettagli aggiuntivi: Per effetto dell ASLR l'indirizzo del modulo dell'exe (0x00E70000) e delle dll cambiera dopo ogni riavvio del sistema, mentre l'indirizzo delle variabili impiegate dal processo cambieranno ogni riavvio del programma stesso, potresti trovare interessante questa mia vecchia domanda sull'ASLR.


Consideralo come un puntatore che si trova sul modulo base del processo in questione, e questo puntatore punti sull'ambiente di gioco, che a sua volta comprende altri puntatori ad altre strutture inerenti al programma stesso.
Ti ringrazio moltissimo per la risposta. Più che continuare a chiedere, raccolgo il materiale che tu e @JunkCoder mi avete passato e proverò a raccapezzarci qualcosa questo pomeriggio!