Eurytus CrackMe Reversing and KeyMaker Coding |
Data |
by Misanthropic |
|
17/11/2004 |
UIC's Home Page |
Published
by Quequero |
Just lay down for me,
naked for me to see... |
Che pazienza che hai misa
:) grazie del tute! |
...It's just one kiss
that's all I need. (A Kiss To Remember - My Dying Bride) |
.... |
- Home
page: http://korn88.altervista.org/
- E-mail: korn -at- mytux -dot- org
-
Misanthropic,
#crack-it@AzzurraNET
|
.... |
Difficoltà |
(X)NewBies ( )Intermedio (
)Avanzato ( )Master |
|
- Benvenuti. In questo tutorial verrà
analizzato il crackme Eurytus di Novice. Il crackme analizzato dal punto di
vista informatico è molto semplice, infatti non vi è nessun trick anti
debugger et similia... invece dal punto di vista matematico è un po' un
casino, come vedremo, perché dovremmo svolgere qualche equazioncina (o
quasi... ihihihih :)
- IDA
- Visual Studio 6
- http://pmode.impazz.it/crackme/Eurytus.zip
- Cominciamo col dire che a questo tutorial
c'è un allegato che contiene il codice sorgente del
keymaker.
- Bene, apriamo il crackme, notiamo subito che appare una finestra con due
pulsanti, info e check... bene bene... adesso apriamo il nostro fido IDA e
cerchiamo la Window Procedure della finestra principale. Scrolliamo un po' fin
quando non arriviamo alla procedura handler dei pulsanti, soffermiamoci in
questo punto:
-
-
- .text:00401174 loc_401174:
; CODE XREF:
DialogFunc+168 j
.text:00401174 lea eax, [esp+64h+var_5C]
; file name
.text:00401178 lea ecx, [esp+64h+var_58]
; method
.text:0040117C
push eax
; pusha il nome (\Key)
.text:0040117D
push ecx
; e il metodo (rb)
.text:0040117E call
_fopen
; chiama _fopen per aprire il file
.text:00401183 mov esi, eax
; mette l'handle in esi
.text:00401185 add esp, 8
.text:00401188
test esi, esi
; controlla se è zero
.text:0040118A mov [esp+64h+arg_4],
esi
; lo memorizza in una locazione
.text:0040118E jnz short loc_4011B0
; salta se non è zero
.text:00401190
push 10h
; uType
.text:00401192 lea edx, [esp+68h+Text]
.text:00401196
push offset aEurytus
; lpCaption
.text:0040119B
push edx
; lpText
.text:0040119C
push eax
; hWnd
.text:0040119D call ds:MessageBoxA
.text:004011A3
pop esi
.text:004011A4
mov eax, 1
.text:004011A9
pop ebx
.text:004011AA
add esp, 5Ch
.text:004011AD
retn 10h
; esci dalla procedura |
Come possiamo notare, vengono pushati nello
stack due parametri (nome file e modo di lettura si suppone..) e viene chiamata
la funzione _fopen. se il return value è l'handle al file allora lo memorizza in
[esp+64h+arg_4] e salta a loc_4011B0 (che ora analizzeremo) altrimenti
se che c'è stato un errore in apertura...
per esempio se il file non esiste :) mostra una MessageBox dicendo che il
crackme non è registrato. A questo punto, quali sono il nome del file e il
metodo di lettura? Apriamo il tutto con un debugger e mettiamo un breakpoint su
00401174 a questo punto ci leggiamo il tutto con un bel data dump :P (d'ora in
poi darò per scontato che userete il debugger per leggere le stringhe...). Ora
tocca a:
-
-
.text:004011B0 loc_4011B0:
; CODE XREF:
DialogFunc+18E j
.text:004011B0
push 2
; pusha 2
.text:004011B2
push 0
; pusha 0
.text:004011B4
push esi
; pusha l'handle al file
.text:004011B5
call _fseek ;
chiama fseek
.text:004011BA
push esi
; pusha l'handle al file
.text:004011BB
call _ftell
; chiama _ftell (ritorna in eax la lunghezza del file)
.text:004011C0
add esp, 10h
.text:004011C3
cmp al, 14h
; controlla se la lunghezza è 20 (14 in esadecimale)
.text:004011C5
jz short loc_4011F1 ; se si salta a loc_4011F1
.text:004011C7
push 10h ; uType
.text:004011C9
lea eax, [esp+68h+Text]
.text:004011CD
push offset aEurytus ; lpCaption
.text:004011D2
push eax ; lpText
.text:004011D3
push 0 ; hWnd
.text:004011D5
call ds:MessageBoxA ; dii che il crackme non è registrato
.text:004011DB
push esi
.text:004011DC
call _fclose ;
chiudi il file
.text:004011E1
add esp, 4
.text:004011E4
mov eax, 1
.text:004011E9
pop esi
.text:004011EA
pop ebx
.text:004011EB
add esp, 5Ch
.text:004011EE
retn 10h
; esci
|
Un semplice controllo della lunghezza...
-
-
.text:004011F1 loc_4011F1:
; CODE XREF:
DialogFunc+1C5 j
.text:004011F1 push 0
; pusha 0
.text:004011F3 push 0
; pusha 0
.text:004011F5 push esi
; pusha l'handle al file
.text:004011F6 call _fseek
; chiama _fseek
.text:004011FB add esp, 0Ch
.text:004011FE mov byte ptr [esp+64h+hDlg], 0
.text:00401203 mov ebx, 1
.text:00401208
.text:00401208 loc_401208:
; CODE XREF: DialogFunc+236 j
.text:00401208
; DialogFunc+254 j ...
.text:00401208 push esi
; pusha l'handle al file
.text:00401209 call _getc
; chiama _getc
|
Fin qui non fa altro che mettere il file pointer
a 0 e chiamare _getc per leggere un solo carattere dal file.
-
-
-
- .text:0040120E add esp, 4
.text:00401211 cmp al, 0FFh
.text:00401213 jz loc_401387
.text:00401219 cmp al, 30h
.text:0040121B jnz short loc_401238
.text:0040121D mov ecx, [esp+64h+hDlg]
.text:00401221 mov al, byte ptr [esp+64h+hDlg]
.text:00401225 and ecx, 0FFh
.text:0040122B inc al
.text:0040122D mov byte ptr [esp+64h+hDlg], al
.text:00401231 mov byte ptr [esp+ecx+64h+var_50], 0
.text:00401236 jmp short loc_401208
.text:00401238 ; ---------------------------------------------------------------------------
.text:00401238
.text:00401238 loc_401238: ; CODE XREF: DialogFunc+21B j
.text:00401238 cmp al, 31h
.text:0040123A jnz short loc_401256
.text:0040123C mov edx, [esp+64h+hDlg]
.text:00401240 mov al, byte ptr [esp+64h+hDlg]
.text:00401244 and edx, 0FFh
.text:0040124A inc al
.text:0040124C mov byte ptr [esp+64h+hDlg], al
.text:00401250 mov byte ptr [esp+edx+64h+var_50], bl
.text:00401254 jmp short loc_401208
.text:00401256 ; ---------------------------------------------------------------------------
.text:00401256
.text:00401256 loc_401256: ; CODE XREF: DialogFunc+23A j
.text:00401256 cmp al, 32h
.text:00401258 jnz short loc_401274
.text:0040125A mov eax, [esp+64h+hDlg]
.text:0040125E and eax, 0FFh
.text:00401263 mov byte ptr [esp+eax+64h+var_50], 2
.text:00401268 mov al, byte ptr [esp+64h+hDlg]
.text:0040126C inc al
.text:0040126E mov byte ptr [esp+64h+hDlg], al
.text:00401272 jmp short loc_401208
.text:00401274 ; ---------------------------------------------------------------------------
.text:00401274
.text:00401274 loc_401274: ; CODE XREF: DialogFunc+258 j
.text:00401274 cmp al, 33h
.text:00401276 jnz short loc_401296
.text:00401278 mov ecx, [esp+64h+hDlg]
.text:0040127C mov al, byte ptr [esp+64h+hDlg]
.text:00401280 and ecx, 0FFh
.text:00401286 inc al
.text:00401288 mov byte ptr [esp+64h+hDlg], al
.text:0040128C mov byte ptr [esp+ecx+64h+var_50], 3
.text:00401291 jmp loc_401208
.text:00401296 ; ---------------------------------------------------------------------------
.text:00401296
.text:00401296 loc_401296: ; CODE XREF: DialogFunc+276 j
.text:00401296 cmp al, 34h
.text:00401298 jnz short loc_4012B8
.text:0040129A mov edx, [esp+64h+hDlg]
.text:0040129E mov al, byte ptr [esp+64h+hDlg]
.text:004012A2 and edx, 0FFh
.text:004012A8 inc al
.text:004012AA mov byte ptr [esp+64h+hDlg], al
.text:004012AE mov byte ptr [esp+edx+64h+var_50], 4
.text:004012B3 jmp loc_401208
.text:004012B8 ; ---------------------------------------------------------------------------
.text:004012B8
.text:004012B8 loc_4012B8: ; CODE XREF: DialogFunc+298 j
.text:004012B8 cmp al, 35h
.text:004012BA jnz short loc_4012D9
.text:004012BC mov eax, [esp+64h+hDlg]
.text:004012C0 and eax, 0FFh
.text:004012C5 mov byte ptr [esp+eax+64h+var_50], 5
.text:004012CA mov al, byte ptr [esp+64h+hDlg]
.text:004012CE inc al
.text:004012D0 mov byte ptr [esp+64h+hDlg], al
.text:004012D4 jmp loc_401208
.text:004012D9 ; ---------------------------------------------------------------------------
.text:004012D9
.text:004012D9 loc_4012D9: ; CODE XREF: DialogFunc+2BA j
.text:004012D9 cmp al, 36h
.text:004012DB jnz short loc_4012FB
.text:004012DD mov ecx, [esp+64h+hDlg]
.text:004012E1 mov al, byte ptr [esp+64h+hDlg]
.text:004012E5 and ecx, 0FFh
.text:004012EB inc al
.text:004012ED mov byte ptr [esp+64h+hDlg], al
.text:004012F1 mov byte ptr [esp+ecx+64h+var_50], 6
.text:004012F6 jmp loc_401208
.text:004012FB ; ---------------------------------------------------------------------------
.text:004012FB
.text:004012FB loc_4012FB: ; CODE XREF: DialogFunc+2DB j
.text:004012FB cmp al, 37h
.text:004012FD jnz short loc_40131D
.text:004012FF mov edx, [esp+64h+hDlg]
.text:00401303 mov al, byte ptr [esp+64h+hDlg]
.text:00401307 and edx, 0FFh
.text:0040130D inc al
.text:0040130F mov byte ptr [esp+64h+hDlg], al
.text:00401313 mov byte ptr [esp+edx+64h+var_50], 7
.text:00401318 jmp loc_401208
.text:0040131D ; ---------------------------------------------------------------------------
.text:0040131D
.text:0040131D loc_40131D: ; CODE XREF: DialogFunc+2FD j
.text:0040131D cmp al, 38h
.text:0040131F jnz short loc_40133E
.text:00401321 mov eax, [esp+64h+hDlg]
.text:00401325 and eax, 0FFh
.text:0040132A mov byte ptr [esp+eax+64h+var_50], 8
.text:0040132F mov al, byte ptr [esp+64h+hDlg]
.text:00401333 inc al
.text:00401335 mov byte ptr [esp+64h+hDlg], al
.text:00401339 jmp loc_401208
.text:0040133E ;
---------------------------------------------------------------------------
.text:0040133E
.text:0040133E loc_40133E: ; CODE XREF: DialogFunc+31F j
.text:0040133E cmp al, 39h
.text:00401340 jnz short loc_401360
.text:00401342 mov ecx, [esp+64h+hDlg]
.text:00401346 mov al, byte ptr [esp+64h+hDlg]
.text:0040134A and ecx, 0FFh
.text:00401350 inc al
.text:00401352 mov byte ptr [esp+64h+hDlg], al
.text:00401356 mov byte ptr [esp+ecx+64h+var_50], 9
.text:0040135B jmp loc_401208
.text:00401360 ; ---------------------------------------------------------------------------
.text:00401360
.text:00401360 loc_401360: ; CODE XREF: DialogFunc+340 j
.text:00401360 push 10h ; uType
.text:00401362 lea edx, [esp+68h+Text]
.text:00401366 push offset aEurytus ; lpCaption
.text:0040136B push edx ; lpText
.text:0040136C push 0 ; hWnd
.text:0040136E call ds:MessageBoxA
.text:00401374 push esi
.text:00401375 call _fclose
.text:0040137A add esp, 4
.text:0040137D mov eax, ebx
.text:0040137F pop esi
.text:00401380 pop ebx
.text:00401381 add esp, 5Ch
.text:00401384 retn 10h |
Tutto questo casino di codice è un loop che legge un carattere alla volta dal
file, controlla se è da "0" a "9" (ma non bastava una sottrazione invece che un
check del genere!?) e lo memorizza, altrimenti da una MessageBox, arrivato a 20
caratteri letti dal file salta a una locazione (loc_401387), il check vero e
proprio.
-
-
- .text:00401387
loc_401387: ; CODE XREF: DialogFunc+213 j Eccoci qua...
.text:00401387
push ebp
; preserva i registri
.text:00401388
push edi
; preserva i registri
.text:00401389
push esi
; pusha l'handle al file
.text:0040138A
call _fclose
; lo chiude
.text:0040138F
mov esi, [esp+70h+var_50]
; mette in esi il primo numero letto dal file
.text:00401393
mov edi, [esp+70h+var_50+3] ; in
edi il quarto
.text:00401397
mov ebp, [esp+70h+var_50+2] ; in
ebp il terzo
.text:0040139B
mov edx, [esp+70h+var_50+1] ; in
edx il secondo
.text:0040139F
add esp, 4
.text:004013A2
xor eax, eax
.text:004013A4
and esi, 0FFh
; lascia in esi solo il primo byte
.text:004013AA
and edi, 0FFh
; uguale a prima però in edi
.text:004013B0
and ebp, 0FFh
; inutile continuare a scrivere
.text:004013B6
and edx, 0FFh
; ma io commento ugualmente
.text:004013BC
lea ecx, [esp+6Ch+var_50]
; carica l'indirizzo dell'aray delle chiavi in ecx
.text:004013C0
mov [esp+6Ch+hDlg], 14h
; memorizza 20 in una locazione di memoria
.text:004013C8
.text:004013C8
loc_4013C8: ; CODE XREF: DialogFunc+3E3 j Ecco il loop
.text:004013C8
xor ebx, ebx
; azzera ebx
.text:004013CA
mov bl, [ecx]
; muove l'elemento puntato da ecx in bl
.text:004013CC
add ebx, eax
; somma eax a ebx
.text:004013CE
imul ebx, esi
; moltiplica ebx per la prima chiave
.text:004013D1
add ebx, edx
; aggiunge la prima chiave
.text:004013D3
add ebx, ebp
; aggiunge la seconda
.text:004013D5
add ebx, edi
; e aggiunge la prima
.text:004013D7
inc ecx
; incrementa il puntatore al vettore di chiavi
.text:004013D8
mov eax, ebx
; mette ebx in eax
.text:004013DA
mov ebx, [esp+6Ch+hDlg]
; mette in ebx il numero che avevamo memorizzato prima (è
un contatore)
.text:004013DE
dec ebx
; lo decrementa
.text:004013DF
mov [esp+6Ch+hDlg], ebx
; lo memorizza di nuovo
.text:004013E3
jnz short loc_4013C8
; se l'ultima operazione non ha dato zero come risultato
allora salta a short loc_4013C8
.text:004013E5
pop edi
; eccoci fuori, ristora edi
.text:004013E6
cmp eax, 40h
; controlla se il risultato del check precedente è 64d
.text:004013E9
pop ebp
; ristora ebp
.text:004013EA
jz short loc_40141A
; se si salta congratulati
.text:004013EC
push 10h ; uType
.text:004013EE
lea eax, [esp+68h+Text]
.text:004013F2
push offset aEurytus ; lpCaption
.text:004013F7
push eax ; lpText
.text:004013F8
push 0 ; hWnd
.text:004013FA
call ds:MessageBoxA
; altrimenti fanculo
.text:00401400
mov ecx, [esp+64h+arg_4]
.text:00401404
push ecx
.text:00401405
call _fclose
; chiudi il file
.text:0040140A
add esp, 4
.text:0040140D
mov eax, 1
.text:00401412
pop esi
.text:00401413
pop ebx
.text:00401414
add esp, 5Ch
.text:00401417
retn 10h
; esci |
Benissimo... a quanto pare questa funzione
prende le nostre 20 chiavi dal keyfile e fa alcune operazioni su di esse... se
il risultato di queste operazioni è 64 (in decimale) allora le 20 chiavi sono
esatte... trasformiamo la nostra funzione in una equazione:
(c1 + c2 + c3 + c0 ((c1 + c19 + c2 + c3 + c0 ((c1 +
c18 + c2 + c3 + c0 ((c1 + c17 + c2 + c3 + c0 ((c1 + c16 + c2 + c3 + c0 ((c1 +
c15 + c2 + c3 + c0 ((c1 + c14 + c2 + c3 + c0 ((c1 + c13 + c2 + c3 + c0 ((c1 +
c12 + c2 + c3 + c0 ((c1 + c11 + c2 + c3 + c0 ((c1 + c10 + c2 + c3 + c0 ((c1 + c2
+ c3 + c0 ((c1 + c2 + c3 + c0 ((c1 + c2 + c3 + c0 ((c1 + c2 + c3 + c0 ((c1 + c2
+ c3 + c0 ((c1 + c2 + c3 + c0 ((c1 + c2 + 2 c3 + c0 ((c1 + 2 c2 + c3 + c0 ((c0^2
+ 2 c1 + c2 + c3)))))) + c4)) + c5)) + c6)) + c7)) + c8)) +
c9))))))))))))))))))))))) = 64
Dove c0, c1, c2...c17, c18, c19 stanno per le
nostre venti chiavi. Non lasciamoci confondere dalla lunghezza della nostra
equazione perché non ne vale la pena... :) prima di cominciare a risolverla...
vorrei farvi notare una cosa... analizziamo la funzione per calcolare:
for (contatore = 0; contatore>20;contatore--)
valore = (keys[contatore] + valore) * keys[0] + keys[1] +
keys[2] + keys[3];
Notiamo subito che l'unica operazione di moltiplicazione che svolgiamo
è quella con keys[0] ovvero la prima chiave... ma... wow! questo ci facilita un
po' tutto!!! perché se noi come prima chiave mettiamo 1 la moltiplicazione
avverrà sempre col numero uno! e poi se impostiamo le chiavi dalla seconda alla
quarta a 0... riduciamo la nostra funzione a una funzione sommatoria, nella
quale si sommano le chiavi :)))))) e grazie a questa debolezza
di questa funzione riusciamo a non impazzire nel risolvere un'equazione a 20
parametri :)
Dunque per trovare una soluzione valida ci basta impostare la
prima chiave a 1, la seconda, la terza e la quarta a 0 e le restanti le
imposteremo in modo che la loro somma mi dia 63 (la prima chiave è a 1) :) (ricordiamoci che ogni chiave
può essere da 0 a 9).
Molto bene, cominciamo col scrivere il keymaker!!!
-
-
- #include <stdio.h>
#include
<stdlib.h> #include <time.h>
void seed(); int randomize(int);
void main() {
int i, indice, ok=0;
unsigned int keygen_keys[20] = {0};
keygen_keys[0]=1;
keygen_keys[1]=0;
keygen_keys[2]=0;
keygen_keys[3]=0;
seed();
for (i=0;i<63;i++) {
while (!ok) {
indice=randomize(16)+4;
if (keygen_keys[indice]<9)
{
keygen_keys[indice]++;
ok=1;
} // end if
} // end while
ok=0;
} // end for
for (i=0;i<20;i++)
printf("%i", keygen_keys[i]);
return;
}
void seed() {
srand(time(NULL));
}
int randomize(int bound) {
return rand()%bound;
} |
Misanthropic
Note finali e ringraziamenti |
Come vedete il keymaker risulta facilissimo :)
Con questo è tutto vi ringrazio per aver letto tutto il tutorial ;p
In prima posizione ringrazio
pirloz ché senza di lui non avrei potuto scrivere questo tutorial.... :) grazie
tante! Poi ringrazio dionis` per avermi dato una mano sull'estetica del keymaker
(intendo quello da scaricare, il link in alto) ringrazio il papero per l'hosting,
inoltre saluto Ntoskrnl
perché è un genio (spero si accontenti...ahahah). Ovviamente ringrazio Novice per questo crackme. Dulcis in fundo saluto Evilcry... buona fortuna evil
:) azz... quasi quasi dimenticavo.. la gentaglia di #crack-it, #cryptorev e #pmode
:)
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 che ogni sviluppatore ha
dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti
possibili.
Reversiamo al solo scopo informativo e per
migliorare la nostra conoscenza del linguaggio Assembly.
Arrestatemi perché ho reversato un crackme
:)