Tutorial per QUE3
Tutorial per QUE3 di The_Dux
============================
INTRO:
Il tutorial che seguirà è la soluzione per il crackme QUE3.
Ok, siamo di fronte al nostro crackme. Leggiamo le regole e scopriamo che non possiamo usare un disassemblatore (poco male, come vedremo), non possiamo modificare il programma (e non ci conviene farlo...). Come vedremo però, sarà necessario aggiungere alcuni bytes al file ma non considero quest'aggiunta come patch per due motivi:
- Per patch intendo una modifica ai jmp condizionali della routine di controllo o una modifica della routine stessa.
- Nel nostro caso la modifica NON verrà applicata alla parte di codice eseguibile. Verrà applicata all'esterno delle aree degli oggetti.
Inoltre è necessario applicare la suddetta modifica per risolvere interamente il crackme altrimenti irrisolvibile.
TUT:
A parte l'introduzione iniziamo subito il nostro tutorial. Abbiamo letto di un key file, di un codice e di un packer usato per la criptazione.
Visto che il packer è stato concepito proprio per non poter disassemblare, usiamo solamente Soft-Ice. Carichiamo il Symbol Loader e apriamo il nostro programma. Troviamo immediatamente una chiamata. Entriamoci con F8 e proseguiamo, tenendo presente che dobbiamo trovare qualche jmp
tipo jmp eax, jmp ebx, ecc. A dispetto dei nostri pensieri non c'è nessun tipo di questi jmp. C'è però un jmp 401000 che più chiaro di così...
Va bene, siamo arrivati all'inizio del codice reale del crackme. Il codice che subito ci si presenta è:
mov ebp, 4243484Bh
mov eax, 4
int 3
cmp eax, 4
jnz s_ice_è_caricato
E' il classico trucco anti-SIce quindi eseguiamo fino a jnz e diamo 'r fl z' per andare oltre. Adesso che la routine per il rilevamento di SIce è fuori uso possiamo premere CTRL+D per ritornare in Windows e vedere com'è fatto il crackme... Inseriamo la nostra password e settiamo un bpx in hmemcpy.
Premiamo 'Check' e SIce appare...
Portiamoci all'interno del codice del crackme (con F11 e F12) e siamo subito dopo una chiamata a GetWindowTextA.
In questo punto eax viene confrontato con 0 (eax equivale alla lunghezza del codice inserito) e poi con 0Ch cioé 12. Sappiamo adesso che il codice dev'essere di dodici caratteri. Usciamo da SIce, accettiamo la Message Box che ci avvisa che il nostro codice è sbagliato, reinseriamo un codice lungo 12 caratteri, entriamo in SIce e impostiamo un bpx in GetWindowTextA in modo da accedere quasi direttamente al codice che ci interessa. Premiamo di nuovo Check e aspettiamo SIce.
Adesso i due jnz sono esclusi 'legalmente' e possiamo continuare. Troviamo subito una chiamata (401577) che possiamo ignorare.
Avanziamo fino a 4014E5 e vediamo un loop che esegue alcuni calcoli sul nostro codice. Proseguiamo, è soltanto del fumo che tende a
sviare le nostre attenzioni. Arriviamo quindi a 4013AD. Avanziamo evitando un'altra parte di codice inutile, ritroviamo la chiamata a 401577 che ci decifra
una parte di codice sottostante e continuiamo. Troviamo un confronto tra ebx e ecx ovvero tra il nostro codice e la stringa '*MaskWinner*', ignoriamola perchè ci informa solamente di come siano efficaci questi trucchi anti-crackers (!!) e continuiamo la nostra odissea.
Arriviamo ad una chiamata (401420) che dobbiamo considerare perchè come possiamo notare steppando oltre con F10 la Message Box con il
messaggio di errore appare. Entriamo dunque e notiamo subito una chiamata. Provate a modificare il codice dopo averlo spacchettato e capirete quale sia la sua utilità...
Tra parentesi, ecco un altro motivo per cui ritengo valida l'aggiunta dei bytes a cui accennavo all'inizio. Andiamo avanti e scopriamo la vera routine in cui il nostro codice viene confrontato con quello reale (che naturalmente è criptato anche se solo attraverso un xor). Per decifrarlo dobbiamo scriverci il contenuto dei due buffer presenti (4022FB e 4022EF) e eseguire un xor tra loro. (Potrebbe esserci qualche errore... non me ne vogliate, non è comodo copiare dalla finestra data di SIce...)
4022FB: 75 3F 8B 41 D2 FF B1 18 DB 49 B8 52
4022EF: 20 76 C8 1E B4 90 C3 7D AD 2C CA 72
-----------------------------------
Codice: 55 49 43 5f 66 6F 72 65 76 65 72 20
U I C _ f o r e v e r
Il codice è dunque 'UIC_forever ' compreso lo spazio finale. Abbiamo finito!!!!! Usciamo da SIce inseriamo il nostro codice e...
'Dlin Dlon!'
???
Il programma ci ha di nuovo avvisati che abbiamo SIce e si è chiuso... Non scoraggiamoci... possiamo sempre rifare il tutto (con maggior velocità, sicuramente). Riportiamoci alla routine di controllo del codice e pazientemente eseguiamo il loop notando che all'uscita (come abbiamo fatto a non vederlo prima?) c'è di nuovo il codice per il rilevamento di SIce. Ripetiamo il 'r fl z' all'altezza di jnz SIce_rilevato e continuiamo. Visto il recente insuccesso continuiamo il programma passo-passo con F10. Rispondiamo OK alla Message Box, lasciamo che SetWindowText
imposti il testo 'Still Unregistered' nella caption della nostra !!!
EHI!! Still Unregistered???
Ah, il key file, me l'ero dimenticato... Continuiamo il nostro passo-passo e arriviamo in prossimità della chiamata OpenFile...
Secondo la mia guida API il primo parametro di OpenFile è il nome ASCII del file quindi diamo un 'd 4020DA' (che è l'argomento che viene pushato nello stack subito prima di OpenFile) e vediamo il nome del key file: 'mask.key'. Usciamo, creiamo il file riportiamoci a questo punto del crackme e andiamo avanti. Se il file viene trovato il programma legge alcuni bytes (25, adesso ve lo dico perchè l'ho già cracckato...) e poi andiamo in un'altra routine che similmente a quella del confronto del codice esegue un xor tra i bytes letti e una tavola presente nell'eseguibile.
Il tutto viene ripetuto 19h volte cioè 25 volte...
402252(1): 65 4A B5 89 12 58 9F FF FB ED 55 21 A8 7B CE E5 18 97
402239(1): 3F 3F D7 ED 67 34 F3 9E 97 C1 34 0F 86 55 AC 9C 38 C6
402252(2): 45 3A 12 37 77 EE 58
402239(2): 30 5F 63 42 12 9C 37
Il risultato è: 'Zubdullalla...by Quequero' Questa frase è da scrivere nel file mask.key.
Andiamo avanti e all'indirizzo 401272 troviamo il terzo controllo per verificare la presenza di SIce. Poche righe più sotto vediamo un altro OpenFile e se controlliamo vediamo che il file da aprire è proprio il nostro eseguibile. Lasciamo che sia aperto e andiamo alla chiamata successiva, SetFilePointer che ci avvisa al termine che la posizione del file corrente è 0B0h (è riportato in eax). Continuiamo e scopriamo che vengono letti alcuni bytes (14h, anche qui lo so perchè sono già arrivato in fondo) e di nuovo cadiamo in un loop, ripetuto 14h volte, in cui viene verificata una terza stringa. Se pensiamo un attimo arriviamo alla conclusione che la stringa qui letta è prelevata dall'header del file EXE e quindi è AL DI FUORI del codice che viene decriptato dal loader. Questo punto è l'unico in cui può sorgere il dubbio se abbiamo violato o no le regole del gioco. Io credo di no. Annotiamoci i due buffer conosciuti:
40226B: 28 2A 24 E8 BA 6D 6D 25 71 49 D4 38 3E 4E 57 EF E9 75 4C 33
40227F: 6F 45 4B 8C 9A 21 18 46 1A 69 97 4A 5F 2D 3C 8A 9B 54 6D 12
-----------------------------------------------------------
Codice: 47 6F 6F 64 20 4C 75 63 6B 20 43 72 61 63 6B 65 72 21 21 21
G o o d L u c k C r a c k e r ! ! !
Quindi all'offset 0B0h del file mask.exe andremo a scrivere: 'Good Luck Cracker!!!'.
E' tutto...
Ricapitolando inseriamo il codice, 'UIC_forever ', con già presenti un file chiamato mask.key di lunghezza 25 bytes contenente 'Zubdullalla...by Quequero' e la stringa 'Good Luck Cracker!!!' nel file eseguibile all'offset 0B0h. Premiamo Check (ricordandoci i tre controlli per SIce) e abbiamo ciò che volevamo, TOTALLY REGISTERED!
PS: Ho inteso la sorpresa annunciata da Quequero come quel trucchetto del 'Good Luck Cracker!!!' all'interno dell'eseguibile.