Yado Crypton v1.0 Reversing generico |
Data |
by
active85k |
|
09/11/2002 |
UIC's Home
Page |
Published
by Quequero |
Morireteee! Moriretee!!! Morirete tutti!!!!!! :)
|
Active sei un inno
all'ottimismo oggi :PPPP cmq bravo anche questo tute e' ben fatto
complimenti
|
Morireteee! Moriretee!!! Morirete tutti!!!!!! :) |
|
- E-mail:
[email protected]
-
active85k, #crack-it
|
|
Difficoltà |
( )NewBies (X)Intermedio (
)Avanzato ( )Master |
|
Conoscete tutti Yado, no? Bene... reversiamo il
suo Krypton 1.0! Reversiamo quello per due motivi: 1) perché il 2.0, per me, è
davvero impossibile; 2) perché ci cercavo un tutorial sulla U.I.C. ma non ne ho
trovati :D
- Yado Krypton v1.0
- Reversing generico
Written by active85k
- Eccocci arrivati! Dopo un bel paio d'ore passate
a reversare 'sto crackme... devo togliermi lo sfizio di scriverci un bel
tutorial dettagliato! :D
- SoftICE v4.5
FrogSICE (beh... anche se il cm è facilino... stiamo sempre parlando di Yado
;)- FileMon
Due palle cubiche con gli angoli smussati ;)
-
http://www.quequero.cjb.net
- E' un CrackMe che non richiede di inserire
nessun nome o nessun serial... o almeno... non nel classico modo! Non tentate
di disassemblarlo perché è polimorfe (l'ho constatato a mie spese ;). L'unica
cosa che dovete fare è avete taaaaaaaaaaaaaaanta pazienza! ;)
- Si parte! Inizio col dire che non credo che
nessuno abbia mai fatto un reversing simile a quello che ho fatto io! Ho usato
deduzioni assurde e provenienti da mente sicuramente perversa... ma
l'importante è riuscirci! Per farvi capire meglio... vi dirò quali sono tutti
i passaggi che ho fatto, spiegandoli nel dettaglio! ;)
Iniziamo come sappiamo tutti: apriamo il CrackMe. Come siamo soliti,
critichiamo (in bene o in male) l'interfaccia grafica e procediamo con il
nostro compito! ;) Non ci sono campi! Da questo possiamo dedurre qualcosa: che
per registrarlo serve o un KeyFile oppure una chiave nel registro di
configurazione. Ad un certo punto, dovete essere attirati dal pulsante 'Info',
altrimenti avrete delle difficoltà a registrarlo ;) Quindi, dopo aver premuto
il tasto, potete rendervi conto che è inutile disasmare il proggy (anche se
non ne spiega il motivo) e che c'è un piccolo 'Joke' (ahò... così lo chiama :)
che serve per dirottarci e che dobbiamo evitare (anche se secondo me... ne ha
messi più di uno! :). Allora, attivate il SoftICE (se non lo avete già fatto)
e clicchiamo sul pulsante 'Register'. Ecco che compare il bel messaggio di
errore! Quindi, le possibilità sono 2: o brekiamo su CreateFile oppure su una
chiamata di registro. Ma torniamo un attimo indietro: il tasto 'Info' ci ha
detto che è inutile disasmare il proggy perché c'è un piccolo trucchetto...
ma, a me è venuto spontaneo e l'ho passato sotto il W32Dasm :D. Ho notato che,
nella String Reference, ci sono un po' di scritte incomprensibili, mentre due
si leggono perfettamente: una è "12345" e l'altra è "Software\Cripton\v1.0".
Mi ha colpito una cosa: come mai solo queste si leggono? E' chiaro che questa
è una chiave di registro, quindi mi son detto: << sicuramente non legge nulla
dalla registry >> e sono andato direttamente sulla CreateFileA (in effetti nel
registro ha creato qualcosa, ma noi non abbiamo fatto niente, quindi è
veramente inutile... era questo il joke di cui parlava Yado). Apriamo il
FileMon e includiamo solo il Krypton. Poi clickiamo su 'Register' e vediamo
quali sono i risultati! Urrrk! Oltre al suono del messaggio... non viene letto
nessun file! E allora? Se non va sul registro e non va sull'hdd... dove
diamine va? Niente panico! Insistete ancora: breakate su CreateFileA e premete
di nuovo il tasto di registrazione. Effettivamente il Sice poppa... e vediamo
che dopo ci porta ad una MessageBox di errore! Quindi... senza dubbio... va
sull'hdd! Arrivato a questo punto... ero davvero disperato, quando mi è venuto
in mente il nick di Yado che mi ha fatto insospettire: e se fosse perché c'è
attivato il SoftICE? E' una buona possibilità che non abbiamo preso in
considerazione! Attiviamo il FrogSICE e il FileMon e clickiamo di nuovo su
'Register'. Eccolo qua! il nostro file! Si chiama YA.DO (che nome! :)
Benissimo! Ci tocca creare un file con questo nome nella directory del
Krypton! Se adesso cliccate su 'Register', nel FileMon, la richiesta ritorna
SUCCESS, ma, nonostante questo... il crackme continua imperterrito a mandarci
a cagare! ^_^ Adesso è arrivato il momento di scervellarci con un po' di
assembly! Breakiamo sulla CreateFileA e analizziamo un po' di codice:
...-
0177:0040114E
PUSH 00
0177:00401150 PUSH
01
0177:00401152 PUSH
03
0177:00401154 PUSH
00
0177:00401156 PUSH
00
0177:00401158 PUSH
80000000
0177:0040115D PUSH
00402372 Indirizzo del nome del file
0177:00401162 CALL
KERNEL32!CreateFileA Cahiamata
0177:00401167 CMP
EAX, -1 Il file esiste?
0177:0040116A JZ
004011B3 No (salto a errore)
0177:0040116C MOV
[0040248B], EAX Si, file trovato
...
Ecco. Se il file viene trovato, il suo
handle viene salvato all'indirizzo 0040248B, altrimenti, si salta ad errore
(ricordate, quindi, che 004011B3 è un salto ad errore!). Una volta che
l'handle del file viene messo al sicuro, vediamo come procede il programma!
- ...
-
0177:00401171
PUSH 00
0177:00401173 PUSH
DWORD PTR [0040248B] Viene pushato l'handle del
file
0177:00401179 CALL
KERNEL32!GetFileSize E ne viene calcolata la
lunghezza.
0177:0040117E CMP
EAX, 15 Il file è grande 15h byte?
0177:00401181 JNZ
004011B3 No (salto a errore, lo stesso errore di prima)
...
Arrivati a questo punto, potete
tranquillamente lasciare andare il SoftICE perché il file che abbiamo creato
noi non è di 15h bytes! Ecco, adesso sappiamo un'altra cosa: che il programma
vuole un file che sia lungo 15h byte (15h = 21). Quindi, apriamo questo file,
con qualsiasi editor, e scriviamoci dentro 21 lettere a casaccio. Ribreakiamo
col SICE fino ad arrivare nuovamente al punto di prima. Adesso il programma
non salterà più ad errore perché il nostro file è di 21 byte. Analizziamo
quindi che cosa avviene dopo:
...
0177:00401183 PUSH
00
0177:00401185 PUSH
004023BA
0177:0040118A PUSH
15 Prende i primi 15h caratteri del contenuto del
file
0177:0040118C PUSH
00402378
0177:00401191 PUSH
DWORD PTR [0040248B]
0177:00401197 CALL
KERNEL32!ReadFile e li mette in 00402378
0177:0040119C PUSH
DWORD PTR [0040248B]
0177:004011A2 CALL
KERNEL32!CloseHandle Chiude l'handle del file
...
Da quanto abbiamo visto, possiamo capire che
dobbiamo inserire un codice valido all'interno del file YA.DO e che deve
essere lungo 21 caratteri. Adesso non dobbiamo fare altro che intercettare il
codice finale. Per fare questo, ci vuole un po' di pazienza in quanto il
nostro Yado, quel giorno, non aveva proprio niente di più divertente da fare,
quindi, si è divertito (come spiegherò di seguito) con un po' di xoring! :D
Prima di analizzare il codice successivo, devo chiarire qualcosina in più
sullo xoring. Mettiamo in caso di dover fare uno xoring tra la lettera A (65)
e la lettera C (67). Lo xoring è un'operazione logica con due parametri:
restituisce 0 se i due parametri sono uguali, mentre, restituisce 1 se i due
parametri sono differenti tra loro. Vediamo quindi cosa esce xorando la A con
la C. La A è uguale al valore 65, mentre la C è uguale al valore 67. Quindi
deriva:
A xor C = ?
65 xor 67 = ?
A 1000001 xor
C 1000011 =
--------------
? 0000010
Quindi, A xor C è uguale al binario
0000010 che è uguale a 2. Questo risultato lo chiamiamo R (da qui R = 2).
Tutta 'sta storia a che serve? Beh... a livello pratico, non serve a niente,
ma a livello teorico, ci permetterà di risalire al nostro codice. Non capite?
Beh... è normale... ancora non abbiamo finito (voi dite, ma questo è pazzo!
Sta dando i numeri! :)! Da questo, possiamo facilmente capire che lo xoring è
un'operazione simmetrica. Questo significa che se A xor C = R allora
A xor R = C. In poche parole, ottenuta la terza cifra, con una formula
inversa, posso riottenere la prima! Infatti abbiamo:
A
1000001 xor
R 0000010 =
--------------
? 1000011
Come vedete, xorando la precedente A con il
valore R precedentemente ottenuto, ci siamo ricavati C, il secondo parametro
precedentemente utilizzato. Dopo questo spezzone di matematica, ritorniamo al
nostro Krypton. Nel file che abbiamo creato, dobbiamo scrivere un codice di 21
caratteri che ci servirà per essere identificato durante l'operazione di
debugging. Il codice che ci inserisco io è "La fine del krypton!!",
esattamente 21 caratteri! Salvo il file e ritorno al proggyno. L'ultima
istruzione che abbiamo visto è la CloseHandle, quindi, per riprendere
da dove eravamo rimasti, breakiamo su CloseHandle e premiamo F11 per entrare
nella procedura pricipale. Adesso dovete fare un lavoro di ricerca: steppando
sempre col SiftICE, dovete andare a vedere dove viene messo il codice che
abbiamo inserito nel file. Dovete steppare fino a quando, il nostro codice,
non viene usato per qualcosa. Steppa qua e steppa là, arriviamo in un punto in
cui, il codice, viene puntato da EAX (ci troviamo esattamente in 00401414). A
questo punto ci tocca analizzare il codice assembly:
...
0177:00401414 MOV
EAX, 00402378 EAX punta al nostro codice
0177:00401419 MOV
EBX, 004023CE EBX punta ad una stringa sconosciuta
0177:0040141E MOV
ECX, 0040234C ECX punta ad un'altra stringa
sconosciuta
...
Fin qua è chiaro! Abbiamo EAX che punta
proprio al nostro codice, mentre EBX ed ECX che puntano ad altre stringhe. In
pratica noi dobbiamo stare attenti ai movimenti di EAX (e derivati) e
dell'offset 00402378. Una volta chiarito questo, andiamo a vedere che succede
dopo (commento solo le prime due parti perché le successive sono identiche e
si ripetono per tutti i caratteri del codice, quini per 21 volte :):
...
0177:00401423 MOV
CL, [ECX-01] CL assume un valore
0177:00401426 SUB
CL, 10 CL = CL - 10h
0177:00401429 MOV
CH, [EBX] CH assume un altro valore
0177:0040142B XOR
CH, CL CH = CH xor CL
0177:0040142D MOV
DH, [EAX] DH assume l'EAXesimo carattere del
nostro codice
0177:0040142F ADD
CL, 0D CL assume un altro valore
0177:00401432 XOR
DH, CL DH = DH xor CL
0177:00401434 CMP
CH, DH Il carattere è valido?
0177:00401436 JNZ
00401797 No (salta ad errore)
-
0177:0040143C
MOV DL, [004022B1]
Si (continua)
0177:00401442 XOR
DL, DH
0177:00401444 MOV
[004022E8], DL
0177:0040144A ADD
EAX, 01 Incrementa i puntatori al codice
0177:0040144D ADD
EBX, 01 e alla stringa sconosciuta
Continua per 21 volte
...
Vediamo che cosa abbiamo fatto. Se
osserviamo bene col debugger, arriviamo a 0040142F in cui CL assume un valore.
Facendo ? CL notiamo che è uguale a 96. Andando avanti, possiamo notare
che CL è sempre uguale a 96. Arriviamo poi in 00401432, dove DH (cioè uno dei
caratteri del nostro codice) viene xorato con CL (sarebbe 96). In poche
parole, il carattere valido dovrebbe essere DH xor 96, e questo, nel passaggio
successivo, dovrebbe essere uguale a CH. In poche parole noi abbiamo:
CL = 96
CH cambia sempre (ma abbiamo anche quello)
I caratteri del nostro codice.
Quindi, per ottenere il codice finale, non dobbiamo fare altro che applicare
la formula inversa dello xoring, di cui abbiamo parlato prima: Chiamiamo CV il
carattere valido, CS il carattere sbagliato e CL rimane CL. Abbiamo quindi:
CV = CS xor CL
CV = CS xor 96
In poche parole, non dobbiamo far altro che
prendere tutti e 21 i valori che CH assume man mano che passa l'algoritmo e
xorarli con 96 per ottenere il carattere valido. Per ottenere tutti i valori
senza saltare ad errore, basta usare il comando r per modificare il
flag Zero del jump (digitare r fl z ogni volta che si incontra un salto
ad errore) In questo modo, in circa 45 secondi, possiamo ricavarci il codice
valido in assembly in questo modo:
MyCode db 21 dup (?)
è il mio codice
Values db 87, 114, ecc...
sono i valori che CH assume ogni volta
RegCode db 21 dup (?)
la variabile che conterrà il giusto codice
xor ecx, ecx
@@STARTLOOP:
cmp ecx, 22
jz @@ENDLOOP
mov al, byte ptr
[Values+ecx]
xor al, 96
mov byte ptr
[RegCode+ecx], al
inc ecx-
jmp @@STARTLOOP
@@ENDLOOP:
push offset RegCode-
push hEdit1
call SetWindowText
ret
Dove hEdit1 è l'handle di un componente
Edit in cui verrà scritto il codice valido. I valori che CH assume sono 87,
114, 105, 116, 101, 89, 97, 100, 111, 89, 97, 100, 111, 64, 104, 111, 116,
109, 97, 105, 108, 46, 99, 111, 109. Xorando ognuno di questi valori con 96 si
ottiene il codice finale ;) Forse come metodo è un po' assurdo, ma ne abbiamo
approfittato per fare un po' di matematica e abbiamo reversato un crackme
molto bello (almeno, io mi son divertito molto :). Ahhh se tutti i programmi
fossero come questo! ;)
- [active85k]
Note finali? E boh! Ne approfitto per salutare
tutta la U.I.C. Un saluto particolare va ad AndreaGeddon perché perde veramente
i migliori anni della sua vita per far di me il suo miglior allievo! ;) ROTFL
NdQue Spero di esser stato chiaro nella spiegazione! ;)
Qui inserirete con questo carattere il vostro
piccolo disclaimer, non è obbligatorio però è meglio per voi se c'è. Dovete
scrivere qualcosa di simile a: vorrei ricordare che il software va comprato
e non rubato, dovete registrare il vostro prodotto dopo il periodo di
valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro
computer determinati dall'uso improprio di questo tutorial. Questo documento è
stato scritto per invogliare il consumatore a registrare legalmente i propri
programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete,
infatti tale documento aiuta a comprendere lo sforzo immane che ogni singolo
programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i
migliori prodotti possibili.
Noi reversiamo al solo scopo informativo e di
miglioramento del linguaggio Assembly.
Capitoooooooo????? Bhè credo di si ;))))