Corso UIC Newbies 02
From UIC
Corso UIC Newbies 2
Contents |
| Infos | |
|---|---|
| Author: | Tin Man |
| Email: | None |
| Website: | None |
| Date: | 22/12/1999 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | |
Introduction
Eccoci qui al primo dei libri della serie "Reverse Engineering passo passo". I libri vi guideranno attraverso i segreti dei programmi, su come esplorare dentro il codice, su come modificarlo. Vi insegneranno anche ad usare gli strumenti "tools" che serviranno all'occorrenza.
Tools
Link e Riferimenti
Questo è il Corso UIC Newbies n°02 disponibile alla pagina Corsi UIC Newbies
Notizie sul Programma
Per il primo libro ho scelto 3 crackme di PhoX che ho trovato sul sito crackmes.cjb.net dove potrete trovarne molti altri, ho scelto questi in quanto i più semplici.
Essay
Capitolo 1: I "nag screen"
Il primo dei crackme "crackme1.exe" all'avvio presenta una schermata con un pulsante OK che una volta premuto esegue il programma vero e proprio.
Queste schermate si chiamano "Splash screen" se durano per un periodo di tempo oppure "nag screen" se richiedono un azione da parte dell'utente per chiudersi.
Ecco qui sotto nella figura il nag screen del programma in oggetto la schermata ha una caption (la riga blù in alto) con la seguente stringa "CrackMe 1.0 by PhoX" ed ha un testo interno alla finestra che inizia con "Plz registrate this crackme...."
Una volta che si preme il pulsante OK ecco come si presenta il programma.
Lo scopo del crackme è di arrivare a questa seconda finestra senza far apparire la prima, ovvero eliminare il nag screen.
Apriamo adesso il programma disassemblatore W32Dasm.
Premendo l'icona contrassegnata dal punto 1 appare una finestra di selezione file, selezionate il crackme1.exe.
A questo punto premete l'icona contrassegnata dal punto 2, vi apparira un'altra finestra generata dal W32Dasm come quella qui sotto:
Come potate notare vi sono riportate le scritte che appaiono nel programma. Cliccate 2 volte sulla scritta "Plz registrate this CrackMe..." già evidenziata nella figura.
A questo punto vi chiudete la finestra o riducetela ad icona ed osservate di nuovo la finestra principale di W32Dasm che vi apparirà come qui sotto.
La riga di posizione azzurra si troverà sul punto evidenziato dal numero 1 dove potete vedere che il programma mette nello stack con l'istruzione ASM push la locazione di memoria relativa alla scritta "Plz registrate this CrackMe..." guardando sopra al punto 3 potete vedere la stessa operazione che viene eseguita per la caption ed al punto 2 viene invece salvato un codice che dice alla funzione il tipo di messagebox che desideriamo.
Se guardate al punto 4 vedrete che il programma a questo punto richiama una funzione delle API di nome MessageBoxA situata nella dll USER32.DLL.
Ecco il template della funzione MessageBoxA
HWND hWnd, // handle of owner window
LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);
La funzione richiede 4 parametri, questi parametri vanno passati alla funzione usando lo stack passandoglieli in ordine inverso, in quanto questo è lo standard nelle funzioni delle API di Windows.
Come potete vedere la funzione richiede un handle alla finestra padre, l'indirizzo del testo che deve contenere, l'indirizzo del testo che deve apparire nella caption, e lo stile.
Ora per eliminare la finestra abbiamo diverse possibilita'.
La prima e più semplice è quella di eliminare la chiamata alla funzione USER32.MessageBoxA sostituendola con delle istruzioni ASM nop (Not Operation ovvero Nessuna operazione).
Per fare questo apriamo il programma Crackme1.exe con un editor esadecimale, io consiglio di usare Hiew in quanto oltre ad editare ha alcune funzioni molto utili che useremo in seguito.
Per ora segnatevi i codici esadecimali della funzione USER32.MessageBoxA che, come potete vedere dal punto 4 sono:
Apriamo il file con Hiew (conviene metterne un collegamento nella directory /windows/sendto).
Premiamo 2 volte il tasto INVIO ( o RETURN) e ci apparira la schermata seguente
Premiamo adesso F7 ed inseriamo nella finestra in grigio i codici esadecimali E8 DA 01 00 00 e premiamo INVIO, eccoci al punto del programma dove viene chiamata la funzione MessageBoxA.
Premiamo a questo punto il tasto Funzione 3 (F3) e potremo editare direttamente il programma (notate che premendo F3 la numerazione che precede le istruzioni ASM cambia, e passa dal modo Address quello Offset ovvero vi mostra la distanza dall'inizio del file.
Ora sovrascriviamo i codici della funzione MessageBoxA con le istruzioni nop (codice esadecimale 90) a questo punto possiamo salvare il file modificato premendo F9 e di seguito ESC per uscire da Hiew.
Provate ora a lanciare il file crackme1.exe e vedrete che il nag screen non compare più.
Questo non è l'unico metodo per bypassare il nag screen ma solo il più semplice.
Un'altro metodo molto più elegante è di saltare tutta la routine con un'istruzione ASM di salto incondizionato "jmp".
Quest'ultimo metodo oltretutto velocizza il programma in quanto possiamo anche saltare le istruzioni di push nello stack, dato che noi non vogliamo più la creazione della messagebox esse sono inutili e sprecano cicli del processore.
Riprendiamo il file crackme1.exe originale e riapriamolo di nuovo con hiew.
Questa volta per posizionarci non usiamo la ricerca dei codici esadecimali ma useremo la funzione di posizionamento diretto, tornate un attimo sull'ultima figura di W32Dasm, bene ora se guardiamo in fondo della finestra di w32dasm vedrete come di seguito:
La parte che ci interessa è quella dopo la scritta @offset ovvero 61Eh
Ora in Hiew premiamo di nuovo 2 volte INVIO per trovarci nel modo codice e premiamo F5.
Inseriamo come in figura l'offset che abbiamo trovato ovvero 61E e premiamo invio, eccoci ora nel punto di prima, come vedete tutti e due i metodi funzionano, ma questo è più sicuro, in quanto potrebbero esserci più occorrenze della sequenza E8 DA 01 00 00 nel file e quindi potremmo trovarci in un punto diverso da quello voluto, in questo modo invece siamo sicuri che il punto è quello esatto.
Risaliamo un po' nel codice premendo il tasto freccia su fino a vedere l'istruzione di push 030, una volta lì premiamo di nuovo F3 e di seguito F2, premendo F2 noi abbiamo la possibilita' di inserire direttamente il codice Asm invece degli opcode delle istruzioni, Hiew li immettera' automaticamente per voi.
Ora mettiamo al posto dell'istruzione push un'istruzione di salto corto jmps che salti esattamente all'istruzione successiva alla call USER.MessageBoxA ovvero all'offset 00000623 premiamo INVIO e successivamente ESC.
Hiew ha inserito l'istruzione di salto nel punto voluto, l'istruzione salta 15 byte e si posiziona sull'istruzione successiva alla chiamata di MessageBoxA, non eseguendo più ne la chiamata ne i vari push ad essa relativi.
Come vedete possono esserci diversi metodi per modificare un programma, stà poi ad ognuno usare quello che preferisce.
Inutile dire che una persona decisa ad imparare le tecniche di reversing deve conoscere i principi della programmazione in diversi linguaggi, quelli che volete ad alto livello ad almeno un conoscenza di base del C e dell'ASM tra quelli di basso livello.
Perche' bisogna conoscere questi 2 linguaggi?
Presto detto, il C vi serve per leggere i riferimenti alle API di windows che sono sempre in linguaggio C e l'ASM in quanto ogni compilatore di qualsivoglia linguaggio tradurrà il codice che voi immetterete in quest'ultimo, dato che è l'unico linguaggio che il processore riesce a comprendere direttamente.
Un discorso a parte meritano i linguaggi interpretati tipo il Basic, il java, il Visual Dialog Script, ecc... Questi linguaggi non vengono tradotti direttamente in ASM, ma in un linguaggio intermedio che viene poi eseguito da un programma o una dll apposita.
Un'altra cosa che vi servirà di sicuro è la conoscenza della lingua Inglese in quanto la maggior parte di informazioni si possono trovare in rete solo redatte in questa lingua che in informatica è universale.
Lo scopo di questo libro non è certo quello di insegnarvi a programmare, cosa a cui dovete provedere con altri testi o in altri modi, ma quello di insegnare il reversing ovvero l'arte di comprendere un programma già compilato in linguaggio macchina.
Alcune cose comunque le dobbiamo trattare per forza, soprattutto di linguaggio ASM.
Le cose che vi servono da sapere sono alcune istruzioni basilari per capire o modificare il flusso di un programma, le più importanti sono i salti condizionati e incondizionati, e le istruzioni di comparazione.
I salti (jmp)
In ASM vi sono 2 tipi di salto, il salto incondizionato ed il salto condizionato.
Il salto incondizionato è uno solo, o meglio sono 2 il salto corto ed il salto lungo, questa differenza per un programmatore anche di linguaggio ASM non è evidente, in quanto è il programma compilatore che si occupa di tradurre la richiesta di salto in lunga o corta, ma per noi che dobbiamo lavorare su codice già pronto questa differenza può essere molto importante.
L'istruzione che esegue il salto si chiama jmp (jump = salto in Inglese).
Il suo opcode relativo in linguaggio macchina è EB seguito dal numero di byte da saltare fino ad un massimo di 255 byte (FF) e questo è il salto corto o JMPS (Jump Short).
Il salto lungo si divide in diversi sotto salti, a seconda che il salto sia near o far (nello stesso segmento o in un'altro segmento) che sia diretto o indiretto, oppure che si riferisca a indirizzi a 16 o 32 bit, per una completa descrizione dei salti incondiziati vi rimando ad un trattato sull'asm o un qualsiasi help di un compilatore ASM.
I loro opcode possono essere: E9, FF oppure EA.
I salti incondizionati comunque non sono così importanti come i salti condizionati, essi servono per lo più per saltare dei pezzi di codice che non devono essere eseguiti o per essere sostituiti ai salti condizionati.
I salti condizionati, come dice il loro nome, saltano o meno in un'altro punto del programma a seconda che una certa condizione sia verificata o meno ve ne sono molti, i più comuni sono:
je (jump if egual) salta se si è verificata una condizione di eguaglianza in un confronto
jne (jump if not egual) salta se non si è verificata una condizione di eguaglianza
jz (jump if zero) salta se il se il bit del registro di flag che rappresenta lo zero è settato
jnz (jump if not zero) salta se il se il bit che rappresenta lo zero non è settato
ja (jump if above) salta se è maggiore
jb (jump if below) salta se è minore
jae/jbe (jump if above or equal/jump if below or equal) come sopra ma salta anche se uguale
jg (jump if great) come ja ma tiene conto del segno
jl (jump if less) come jb ma tiene conto del segno
jge/jle (jump if great or equal/jump if less or equal)
ve ne sono degli altri, vi rimando come per i salti incondizionati ad un testo di ASM per la loro trattazione completa.
I loro opcode sono:
je 74 OF 84
jne 75 OF 85
jz 74 OF 84
jnz 75 OF 85
ja 77 OF 87
jb 72 OF 82
jae 73 OF 83
jbe 76 OF 86
jg 7F OF 8F
jl 7C OF 8C
jge 7D OF 8D
jle 7E OF 8E
Come potate notare praticamente le istruzioni je/jne jz/jnz sono esattamente uguali per la cpu.
Le istruzioni di comparazione
Le istruzioni di comparazione sono:
cmp dest,sorg (compare) compara 2 elementi sottraendo sorgente da destinazione.
L'istruzione modifica alcuni flag verificabili in seguito attraverso un salto condizionato.
cmps dest, sorg come sopra ma compara stringhe o byte (cmpsb) o word (compsw) o
doubleword (compsd).
test dest, sorg esegue un'operazione di AND logico tra i bit di sorgente e destinazione.
Questa istruzione si può usare per testare se un registro è a valore zero o nò eseguendo il test con se stesso Es: test eax, eax
Altre istruzioni importanti sono:
call chiama una funzione/subroutine interna o esterna al file
ret termina una subroutine e ritorna al punto successivo da dove è stata effettuata la call
push inserisce dei valori nello stack dei valori per passarli ad una funzione/subroutine
pop estrae dei valori dallo stack
mov dest, sorg copia il contenuto di sorgente in destinazione
Esaminiamo più in dettaglio alcuni di questi comandi:
Push e pop, inserimento ed estrazioni di valori di valori nello stack, cosa significa?
Lo stack e' un'area di memoria dove i programmi o il sistema operativo mette temporaneamente dei valori che possono essere indirizzi di memoria o dati veri e proprio, la particolarita dello stack che bisogna capire è che la sua modalità di uso è di tipo LIFO (Last In First Out in Italiano= Ultimo che entra primo che esce) ovvero e paragonabile ad una pila, immagginiamo di avere un tavolino piccolo ed una decina di libri, se appoaggiamo i libri uno sopra l'altro per
primo potremo prendere solo quello in alto, se vogliamo il quinto libro, dovremmo prima togliere i primi 4 prendere il quinto e rimettere a posto i primi 4, il principio di funzionamento e' lo stesso, si può anche usare un trucco per prendere il quinto libro: conoscendo le dimensioni precise degli altri 4 spostiamo la mano in basso della misura giusta e sfiliamo il quinto libro dalla pila, anche con lo stack è possibile questa operazione, spostiamo il puntatore alla cima dello stack della dimensione complessiva dei primi 4 dati e preleviamo il qinnto, il puntatore allo stack si chima SP (Stack Pointer) ed' un registro della CPU.
Mov, è un'istruzione di copia tra dati, anche essa può essere usata per passare dei dati alla funzioni, spostando un dato o un valore in una locazione di memoria precisa, tornando all'esempio di prima noi possiamo prendere un libro metterlo nel secondo scaffale della libreria come secondo libro da sinistra, poi chiediamo ad un'amico di andarcelo a prendere, possimao dirgli il titolo oppure possiamo dirgli di prendere il secondo libro da sinistra presente sul secondo scaffale della libreria , e lui ci porterà il libro giusto.
inc dest (incrementa) incrementa un valore di 1
dec dest (decrementa) decrementa un valore di 1
add dest,valore Aggiunge valore a destinazione
xor dest, sorg esegue una operazione di xor logico tra i due operandi
L'istruzione xor può avere un utilizzo molto particolare, ovvero l'azzeramento di un registro o di una locazione di memoria, infatti effettuando l'operazione di xor tra du evalori uguali il risultato è sempre zero, quindi xor eax, eax azzera il registro eax qualsiasi valore esso contenga.
Ho spiegato queste poche istruzioni ASM in quanto sono le più comuni che si usano per il reversing, le ho spiegate adesso e non prima dell'esempio pratico, in quanto le avreste saltate subito per passare alla pratica, magari non leggendole mai, così invece sono sicuro che un'occhiata l'avete data.
Un'altra cosa molto importante nell'arte del reversing è il tipo di approccio mentale, mi spiego meglio, la cosa più sbagliata è osservare un programma in modo rigido, molte volte le cose più incomprensibili diventano facili se osservate da un'altro punto di vista, ad esempio una routine di generazione di un seriale può sembrare molto difficile da seguire istruzione per istruzione andando avanti, allora provate e seguirla al contrario, oppure a risolvere prima
delle fasi intermedie, in questo modo potreste capire lo stile di pensiero del programmatore ed avere un'aiuto nei passi più difficili, oppure a volte un algoritmo coplicatissimo di controllo Name/Serial finisce con un'istruzione che ritorna 1 alla fine se il programma è registrato e uno 0 se no', questo è un classico esempio di un programmatore che non ha mai visto un disassemblato dei suoi programmi, programmando ad alto livello in C, C++, Delphi ecc..
Spesso non si conosce il risultato finale in linguaggio macchina, quindi si studiano algoritmi complicatissimi, con giri matematici incredibili che poi si bypassano solamente invertendo un salto da je a jne oppure cambiando un mov, eax, 0 in mov eax, 1 lo studio del reversing aiuta ad evitare questi errori grossolani e porta a sviluppare dei sistemi più sicuri di protezione, il sistema sicuro al 100% non esiste comunque, è come una corda annodata, per quanti nodi complicati si possano fare esiste sempre un metodo per snodarla, certo un nodo a fiocco (tipo quello con cui vi allacciate le scarpe) è semplicissimo da snodare,
mentre una successione di un centinaio di nodi marinari non è svolgibile da tutti, le protezini pì sicure infati sono quelle dove una parte di codice manca proprio, oppure è criptata con una chiave esterna al programma che può essere software o hardware (le famose dongle) in questo caso è praticamente impossibile risalire alla parte mancante, ho iscritto praticamente in quanto è sempre possibile decriptarla, avendo a disposizione un computer molto potente e un centinaio di anni di tempo a dispozione si potrebbe fare lo stesso ma e' molto improbabile, si potrebbe anche riscrivere la parte mancante, ma allora si potrebbe anche scrivere tutto il programma da zero l'unico sistema rimane quella di avere la versione originale e dumpare (ovvero trasferire una parte della memoria in un file) le parti mancanti.
Finite le mie disquisizioni possiamo cominciare con il secondo crackme il crackme2.exe
Lanciamo il programma, vediamo che ci chiede un seriale.
Inseriamo un seriale a caso tipo 1234 e premiamo il pulsante [OK] ci appare una finestra.
Ora abbiamo dati a sufficenza per cominciare a lavorare apriamo W32Dasm e carichiamo il file crackme2.exe come avete visto prima per il crackme1, seguiamo la stessa procedura e apriamo la finestra delle string reference, doppio click sulla stringa "Wrong serial" ed ecco come appare w32Dasm.
AL punto 1 troviamo il push della stringa "Wrong serial" e subito dopo la solita funzione MessageBoxA, prima del push vediamo gli altri push che mettono nello stack la caption "luuuuzeeeer" e il push relativo allo stile della Messagebox, stavolta andiamo ancora più in sù a guardare, notiamo che il W32Dasm ci avverte che quel punto è referenziato da un salto di tipo condizionato (la "c" tra parentesi vicino all'indirizzo), quindi premiamo i tasti SHIFT + F12 e ci appare un finestra di W32Dasm che chiede un indirizzo.
Inseriamo adesso l'indirizzo del salto di cui prima 4011B6 premiamo OK.
Ci ritroviamo al punto 1 un salto di tipo jne salta se non è uguale, quindi subito sotto vediamo la routine che invece ci presenta la messagebox di congratulazioni.
Abbiamo 2 vie per bypassare questo controllo, una è quella di invertire il salto, cambiandolo in un je, a questo punto il programma presenta la messagebox di congratulazioni con qualsiasi seriale tranne che con quello giusto.
Oppure possiamo eliminare il salto il salto, sostituendo i byte 75 1E con 90 90 (nop nop) in questo modo andremo sempre nella routine di congratulazioni con qualsiasi seriale.
Oppure possiamo studiare la routine di controllo del seriale per capire quale è quello giusto, facciamolo:
Potete notare al punto 2 che il programma chiama un'altra funzione delle API di windows la GetWindowTextLenghtA, questa routine ci restituisce la lunghezza della stringa presente in una casella di testo.
Il template della funzione è il seguente:
HWND hWnd // handle of window or control with text
);
La funzione chiede come parametro un handle (un handle è un numero univoco che referenzia ogni processo, finestra, controllo, pulsante ecc... presenti in windows) e restituisce un numero di tipo intero con valore uguale al numero di caratteri presenti nella finestra di cui abbiamo passato l'handle, in parole povere ci dice quanto è lunga la stringa.
Questo valore viene messo nel registro eax, se guardiamo la figura al punto 3 vediamo che il progamma mette il valore presente in eax nel registro esi con l'istruzione mov, poi confronta il registro esi con 0C in esadecimale ovvero con 12 in decimale.
Il risultato di questo confronto condiziona il salto successivo.
Quindi il flusso del programma è il seguente:
Prende la lunghezza della stringa nella finestra
Confronta la lunghezza con 12
e' uguale ?
Si
finestra di congratulazioni
No
Finestra "Wrong serial"
Quindi il seriale giusto può essere una qualsiasi sequenza di caratteri, basta che siano 12 puo' andar bene ad esempio "TiN_MaN_UIC_" Oppure "Il mio primo" (anche lo spazio e' considerato carattere) o anche "12 Caratteri" . Provate e vedrete che è così.
Passiamo adesso al crakme2.exe, lanciamolo, vediamo che chiede sempre un codice seriale, mettiamo 1234 premiamo OK e ci appare una finestra con scritto "Wrong Code", disassembliamo il file con W32Dasm, cerchiamo nelle string reference la stringa di cui sopra, ed ecco qui sotto un'estratto del codice così come ce lo presenta W323Dasm:
|:004011BB(C), :004011C0(C), :004011C6(C), :004011CC(C), :004011D2(C)
|:004011D8(C), :004011DE(C), :004011E4(C), :004011EA(C), :004011F0(C)
|:004011F6(C), :004011FC(C)
|
|: 0040121C 6A30 push 00000030
|* Possible StringData Ref from Data Obj |→"Sorry...(hehehe)"
|
|: 0040121E 68C0204000 push 004020C0
|* Possible StringData Ref from Data Obj →"Wrong Code!"
|
|: 00401223 68D1204000 push 004020D1
|: 00401228 FF3548204000 push dword ptr [00402048]
|* Reference To: USER32.MessageBoxA, Ord:0000h
Vediamo che stavolta i salti che referenziano la chiamata alla messagebox "Wrong code" sono più di uno, anzi per la precisione sono 12, andiamo a vedere il primo di questi salti all'indirizzo 004011BB.
00401196 6898204000 push 00402098
0040119B FF354C204000 push dword ptr [0040204C]
Reference To: USER32.GetWindowTextA, Ord:0000h
|
004011A1 E8C7000000 Call 0040126D
004011A6 BB98204000 mov ebx, 00402098
004011AB FF354C204000 push dword ptr [0040204C]
Reference To: USER32.GetWindowTextLengthA, Ord:0000h
|
004011B1 E8C3000000 Call 00401279
004011B6 8BF0 mov esi, eax
004011B8 83FE12 cmp esi, 00000012
004011BB 755F jne 0040121C ;Primo dei salti
004011BD 803B46 cmp byte ptr [ebx], 46
004011C0 755A jne 0040121C
004011C2 807B0169 cmp byte ptr [ebx+01], 69
004011C6 7554 jne 0040121C
004011C8 807B0372 cmp byte ptr [ebx+03], 72
004011CC 754E jne 0040121C
004011CE 807B0465 cmp byte ptr [ebx+04], 65
004011D2 7548 jne 0040121C
004011D4 807B0657 cmp byte ptr [ebx+06], 57
004011D8 7542 jne 0040121C
004011DA 807B076F cmp byte ptr [ebx+07], 6F
004011DE 753C jne 0040121C
004011E0 807B0872 cmp byte ptr [ebx+08], 72
004011E4 7536 jne 0040121C
004011E6 807B0A78 cmp byte ptr [ebx+0A], 78
004011EA 7530 jne 0040121C
004011EC 807B0C53 cmp byte ptr [ebx+0C], 53
004011F0 752A jne 0040121C
004011F2 807B0D75 cmp byte ptr [ebx+0D], 75
004011F6 7524 jne 0040121C
004011F8 807B1078 cmp byte ptr [ebx+10], 78
004011FC 751E jne 0040121C
004011FE 6A30 push 00000030
Possible StringData Ref from Data Obj //→"Nice Work!!"
|
00401200 687F204000 push 0040207F
Possible StringData Ref from Data Obj //→"Right Code! "
|
00401205 688B204000 push 0040208B
0040120A FF3548204000 push dword ptr [00402048]
Reference To: USER32.MessageBoxA, Ord:0000h
|
00401210 E870000000 Call 00401285
00401215 5E pop esi
00401216 5F pop edi
00401217 5B pop ebx
00401218 C9 leave
00401219 C21000 ret 0010
Come vedete salti sono tutti consecutivi, se guardiamo sopra vediamo la solita funzione GetWindowTextLenghtA ed un'altra funzione nuova la GetWindowTextA.
Vediamo il template di questa nuova funzione:
HWND hWnd, // handle of window or control with text
LPTSTR lpString, // address of buffer for text
int nMaxCount // maximum number of characters to copy
);
La funzione richiede il solito handle della finestra, un indirizzo di memoria dove inziare a mettere il caratteri presi, ed un numero intero con il numero massimo di caratteri da prendere.
Come vediamo il programma gli passa i seguenti dati:
00401196 6898204000 push 00402098 //→L'indirizzo del buffer
0040119B FF354C204000 push dword ptr [0040204C] //→L'handle della finestra
Reference To: USER32.GetWindowTextA, Ord:0000h
|
004011A1 E8C7000000 Call 0040126D
004011A6 BB98204000 mov ebx, 00402098
Notate che l'indirizzo del buffer viene messo nel registro EBX. Andiamo avanti:
Reference To: USER32.GetWindowTextLengthA, Ord:0000h
La funzione che abbiamo gia visto prima che ritorna il numero di caratteri della stringa
004011B8 83FE12 cmp esi, 00000012
004011BB 755F jne 0040121C
Il numero di caratteri viene messo in ESI e confrontato con 12h (18 in decimale) quindi il nostro codice deve essere lungo 18 caratteri altrimenti si và alla finestra di "Wrong code".
Andiamo avanti:
004011C0 755A jne 0040121C
Ecco un punto interessante, il primo carattere del buffer (ricordate che era stato messo in EBX) viene confrontato con 46, 46 corrisponde al carattere "F" altrimenti salta alla finestra "wrong code":
004011C6 7554 jne 0040121C
//→Il secondo carattere viene confrontato con "i"
004011C8 807B0372 cmp byte ptr [ebx+03], 72
004011CC 754E jne 0040121C
//→Il quarto carattere viene confrontato con "r"
004011CE 807B0465 cmp byte ptr [ebx+04], 65
004011D2 7548 jne 0040121C
//→Il quinto carattere viene confrontato con "e"
004011D4 807B0657 cmp byte ptr [ebx+06], 57
004011D8 7542 jne 0040121C
//→Il 7° carattere viene confrontato con "W"
004011DA 807B076F cmp byte ptr [ebx+07], 6F
004011DE 753C jne 0040121C
//→L' 8° carattere viene confrontato con "o"
004011E0 807B0872 cmp byte ptr [ebx+08], 72
004011E4 7536 jne 0040121C
//→Il 9° carattere viene confrontato con "r"
004011E6 807B0A78 cmp byte ptr [ebx+0A], 78
004011EA 7530 jne 0040121C
//→Il 11 carattere viene confrontato con "x"
004011EC 807B0C53 cmp byte ptr [ebx+0C], 53
004011F0 752A jne 0040121C
//→Il 13° carattere viene confrontato con "S"
004011F2 807B0D75 cmp byte ptr [ebx+0D], 75
004011F6 7524 jne 0040121C
//→Il 14° carattere viene confrontato con "u"
004011F8 807B1078 cmp byte ptr [ebx+10], 78
004011FC 751E jne 0040121C
//→Il 17° carattere viene confrontato con "x"
Quindi ricapitoliamo:
Il codice deve essere lungo 18 caratteri.
E deve contenere dei caratteri precisi in alcune posizioni definite.
Ecco qui sotto una tabella che riepiloga le posizioni ed i caratteri che il programma controlla, la prima riga corrisponde alle posizioni in decimale, la seconda alle posizioni in offset esadecimale dall'inizio del codice, la terza riga sono i codici ASCII in esadecimale la quarta i caratteri corrispondenti ai codici ASCII.
Quindi può funzionare sia con:
Fi-re-Wor-x-Su--x-
Che con:
Fi!re!Wor!x!Su!!x!
Provate con altri caratteri e vedrete che è sempre così, in quanto vengono solo controllati alcuni caratteri del codice e gli altri non sono considerati.
Note Finali
Concludiamo così la prima parte, nella prossima vedremo come usare altri strumenti, e soprattutto lo strumento più potente il debugger.
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.