CrackMe 1,2,3 by Cruehead / MiB

Data

by ILM©2001

 

Marzo 2002

UIC's Home Page

Published by Quequero

Ciò che facciamo in vita...

Grazie tante ILM i crackme erano abbastanza semplici e specie il terzo puo' dare una mano ai newbies :)

...riecheggia nell'eternità!

....

E-mail: [email protected]
Nickname: ILM©2001

....

Difficoltà

(X)NewBies ( )Intermedio ( )Avanzato ( )Master

 

>>> CrackMe 1,2,3  by Cruehead / MiB <<<

Introduzione

Con questo Tutorial voglio spiegare come si risolvono i 3 CrackMe by Cruehead / MiB presenti nella sezione CrackMe del sito di Quequero.
Per semplicità, ma anche per una ragione estetica, i listati ASM non contengono gli OP-CODE.

Spero di aver fatto un buon lavoro. 
Auguro a tutti una buona lettura. 

Tools usati

- SoftIce 4.05
- Hex Editor
- File Mon
- Una tabella ASCII (opzionale ma molto utile)
- Calcolatrice di Windows

Essay


CrackMe 1 by Cruehead / MiB
Studio della generazione del Serial Number 

Iniziamo lo studio di questo nostro primo CrackMe. Per prima cosa avviamo il programma e proviamo ad inserire un nome ed un seriale a caso (tanto per vedere cosa succede) premiamo OK e, se non abbiamo un culo sfondato,ci apparirà una MessageBox di errore.
Carichiamo il nostro beneamato Soft-Ice (SICE) premendo CTRL+D (^D) e settiamo un BreakPoint (interruzione) sulla API "getdlgitemtexta". 
Vi chiederete perché proprio su questa? La risposta è semplice, questa API si occupa di prelevare del testo dal programma (in questo caso il nostro nome e il nostro serial). Premete F5 per uscire da SICE ed inserite nuovamente un nome ed un serial fittizio. Io usero' come nome "ILM" e come serial "666111666". Premiamo ok e SICE popperà. Ora dovremo premere F12 per uscire dalla chiamata dell'API ma siccome le chiamate sono 2, una per ogni textbox, dovremo premere più volte F12 fino ad arrivare qui...

:00401223  cmp eax, 00000000 ---> controlla che sia stato inserito un nome
:00401226  je 004011E6 ----------> se non é stato inserito nulla salta a 004011E6 ed esci dal programma
:00401228  push 0040218E -------> carica il nome inserito
:0040122D call 0040137E --------> chiamata ad una routine

    :0040137E mov esi, dword ptr [esp+04] ---> sposta in ESI il valore puntato da [ESP+04]
    :00401382 push esi ------------------------> carica questo valore (ovvero il nome da noi inserito)
    :00401383 mov al, byte ptr [esi] -----------> metti in AL in primo byte di ESI ovvero il primo byte del nome
    :00401385 test al, al -----------------------> controlla che AL non sia vuoto
    :00401387 je 0040139C ------------------> se é vuoto salta a 0040139C 
    :00401389 cmp al, 41 ---------------------> confronta il valore di AL con 41h (65d - "A")
    :0040138B jb 004013AC -----------------> se é minore salta a 004013AC
    :0040138D cmp al, 5A --------------------> confronta AL con 5A (90 - "Z")
    :0040138F jnb 00401394 -----------------> se é maggiore salta a 00401394 (vedi sotto)
    :00401391 inc esi ------------------------->  incrementa ESI ovvero punta alla lettera successiva
    :00401392 jmp 00401383 ---------------->  salta a 00401383 e rifai tutto
   
:00401394 call 004013D2 ---> vai all'indirizzo 004013D2
    
        :004013D2 sub al, 20 ---------------------> sottrai ad AL il valore 20h (32d)
        :004013D4 mov byte ptr [esi], al ----------> sposta il valore modificato di AL in ESI
        :004013D6 ret ----------------------------> ritorna all'istruzione successiva alla chiamata
    
    :00401399 inc esi ------------> punta alla lettera successiva
   
:0040139A jmp 00401383 --> salta a 00401383

Dal listato ASM si intuisce subito che il programma effettua un controllo su tutti i char del nome che abbiamo inserito.
In principio controlla che si sia effettivamente inserito un nome ed in caso contrario carica la MessageBox di errore; poi carica in AL uno per un tutti i char del nome controllando che esso sia composto SOLO da lettere maiuscole e non da altri caratteri (se le lettere sono minuscole il programma le scrive in maiuscolo in automatico). Si arriva a questa conclusione poiché il prog. controlla che i vari char abbiano un valore compreso tra 41h e 5Ah.
Se il valore e' minore esce subito dal programma, invece se e' maggiore viene fatta una sottrazione: chr del nome  - 20h

Esempio: inserisco il nome "ILM" e non ho nessun problema in quanto le lettere sono tutte maiuscole; 
               inserisco il nome "IL{" e il nome viene mutato in "IL[" in quanto al valore del carattere "{" ,che é 123, viene sottratto 20h(32d), per dare il valore 91d che
               coincide con il carattere "["

Ora che abbiamo capito come viene controllato il nome, andiamo avanti e vediamo cosa fa il programma.
Ripartiamo da 0040139C ovvero il punto in cui si arriva quando i caratteri sono stati tutti
controllati

:0040139C pop esi -----------> togli  ESI
:0040139D call 004013C2 ---> chiamata all'indirizzo 004013C2

    :004013C2 xor edi, edi  ---------------> azzera EDI
    :004013C4 xor ebx, ebx --------------> azzera EBX
    :004013C6 mov bl, byte ptr [esi] ------> sposta in BL il primo char di ESI (ovvero il primo char del nome)
    :004013C8  test bl, bl -----------------> controlla che non sia vuoto
    :004013CA je 004013D1 -------------> se è salta a 004013D1
    :004013CC add edi, ebx --------------> somma ad EDI il valore di EBX (ovvero di BL)
    :004013CE  inc esi --------------------> punta al char successivo
    :004013CF  jmp 004013C6 ----------> salta a 004013C6 e ripeti tutto
    :004013D1  ret -----------------------> ritorna all'istruzione successiva alla chiamata 

:004013A2  xor edi, 00005678 ----> xora il valore di EDI con il valore 5678h
:004013A8  mov eax, edi ----------> sposta il valore di EDI in EAX
:004013AA jmp 004013C1 -------> salta a 004013C1
:004013C1 ret ---------------------> ritorna all'istruzione successiva alla chiamata ovvero all'indirizzo 00401232 

Avete capito cosa ha fatto il programma vero? Ha sommato nel registro EDI tutti i valori ASCII dei caratteri del nome e, successivamente, ha xorato il risultato con il valore 5678h mettendolo poi in EAX.
Ora che sappiamo come viene trattato il nome, andiamo a vedere come viene generato il Serial Number

:00401232 push eax --------------> carica nello stack EAX (che è il numero calcolato dal nostro nome)
:00401233 push 0040217E ------> carica il valore all'indirizzo 0040217E (se premete "d 0040217e" su SICE apparirà il seriale che avrete inserito)
:00401238 call 004013D8 -------> chiamata all'indirizzo 004013D8

    :004013D8  xor eax, eax -------------------> azzera EAX
    :004013DA xor edi, edi --------------------> azzera EDI
    :004013DC xor ebx, ebx -------------------> azzera EBX
    :004013DE  mov esi, dword ptr [esp+04] --> sposta in ESI il valore puntato da [ESP+04] (ovvero il char del nostro seriale)
    :004013E2  mov al, 0A ---------------------> sposta in AL il valore 0Ah (10d)
    :004013E4  mov bl, byte ptr [esi] ----------> sposta il char il BL
    :004013E6  test bl, bl ----------------------> controlla che non sia vuoto
    :004013E8  je 004013F5 ------------------> se é vuoto salta a 004013F5
    :004013EA sub bl, 30 ----------------------> sottrai a BL il valore 30h (48d)
    :004013ED imul edi, eax -------------------> moltiplica EAX per EDI e il risultato mettilo in EDI 
    :004013F0  add edi, ebx -------------------> somma EBX (BL) a EDI e metti il risultato su EDI
    :004013F2  inc esi -------------------------> punta al char successivo
    :004013F3  jmp 004013E2 ----------------> salta a 004013E2 e rifai tutto il giro
    :004013F5  xor edi, 00001234 ------------> xora EDI col valore 1234h
    :004013FB  mov ebx, edi -----------------> sposta EDI in EBX
    :004013FD  ret ---------------------------> ritorna all'istruzione successiva alla chiamata ovvero 0040123D

Il serial viene generato in questo modo: ogni char che abbiamo inserito verrà modificato,  in quanto al valore di ogni char verrà sottratto 30h.
Ogni char verrà sommato in EDI e, il registro, verrà moltiplicato di volta in volta per il valore 0Ah (10d).
Il risultato verrà poi xorato con 1234h e messo in EBX.

:0040123D add esp, 00000004 ---> somma 04h ad ESP
:00401240  pop eax ---------------> togli EAX
:00401241 cmp eax, ebx ----------> confronta che i valori di EAX (valore numerico calcolato dal nome) e EBX (seriale inserito modificato) siano uguali
:00401243  je 0040124C ---------> se sono uguali salta a 0040124C dove verra' caricata la MessageBox di complimenti
:00401245 call 00401362 ---------> se non sono uguali vai a 00401362 e carica la MessageBox di errore

Ecco risolto il primo CrackMe. 
In poche parole, per trovare un seriale corretto, basta fare una somma dei vari char del nome (ricordarsi le regole vigenti per i char maggiori di 5Ah e minori di 41h) e xorare il risultato prima col valore 5678h e poi con il valore 1234h.Convertire poi il risultato in decimale e il gioco e' fatto ;)
Esempio: nome "ILM" 

Valore ASCII in HEX delle lettere
"I"=49h 
"L"=4Ch  
"M"=4Dh  

Somma dei valori ASCII
49+4C+4D=E2  

1° Xor
E2 xor 5678=569A

2° Xor
569A xor 1234=44AE 

Conversione HEX-DEC 
44AEh=17582d

Se volete potete partire dal numero 17582, fare tutte le operazioni su ogni char (sub bl,30 / imul eax,edi / xor ecc.) e vedere che il risultato sarà effettivamente 44AEh.

 

 

CrackMe 2 by Cruehead / MiB
Serial Fishing

 

Il CrackMe2 si presenta in modo diverso in quanto si registra inserendo solo un seriale. Compito nostro sarà trovare quel seriale.
Avviamo il programma e andiamo nella sezione "Enter Password" (che sta sotto "Help"). Inseriamo una Password a caso e premiamo OK. Apparirà una MessageBox di errore. Bene! Ora apriamo SICE premendo ^D e settiamo un bel breakpoint sull'api "getwindowtexta" (bpx getwindowtexta). Usciamo da SICE premendo F5 e poi inseriamo un seriale a caso (io inserirò il mio solito 666111666). Premiamo OK e SICE poppera' sullo schermo. Ora premiamo un po' di volte F12 fino a che non arriviamo in questo punto:

:00401223  cmp eax, 00000000

Come mai ho deciso di fermarmi qui? Beh semplice. Se premo nuovamente F12 esco dal prog. e appare la MessageBox di errore ;) ma ora commentiamo un po' il codice.

:00401223 cmp eax, 00000000 ---------> confronta che la lunghezza del seriale inserito col valore 0
:00401226 je 004011E6 ----------------> se é 0,ovvero se non si é inserita nessuna stringa, salta a 004011E6 ed esci dal prog.
:00401228 push 0040217E -------------> carica i dati all'indirizzo 0040217e (se in SICE scriviamo d 0040217E apparirà il serial da noi inserito!)
:0040122Dcall 00401365 ---------------> chiamata ad una routine all'indirizzo 00401365

      :00401365  mov byte ptr [00402118], 00 --------> sposta il valore 0 al primo byte dell'indirizzo 00402118 
      :0040136C mov esi, dword ptr [esp+04] ---------> sposta in ESI la DoubleWord puntata da [ESP+04] (SICE: dd *(ESP+04) --> nostro serial!)
      :00401370  push esi ------------------------------> carica ESI
      :00401371  mov al, byte ptr [esi] -----------------> sposta il AL il byte puntato di ESI
      :00401373  test al, al -----------------------------> confronta che non sia vuoto
      :00401375  je 00401390 -------------------------> se é vuoto salta a 00401390
      :00401377  inc byte ptr [00402118] --------------> incrementa il byte all'indirizzo 00402118
      :0040137D cmp al, 41 ----------------------------> confronta AL col valore 41h (65d - "A")
      :0040137F  jb 00401385 -------------------------> se é minore salta a 00401385
      :00401381  cmp al, 5A ---------------------------> confronta AL con 5Ah (90d - "Z")
      :00401383  jnb 00401388 ------------------------> se non é minore salta a 00401388 altrimenti vai avanti (00401385)
           
          
:00401388 call 004013B2 ---------> chiamata all'indirizzo 004013B2

                  :004013B2 sub al, 20 -------------------> sottrai 20h (32d) a AL
                  :004013B4 mov byte ptr [esi], al --------> sposta AL in ESI
                  :004013B6 ret --------------------------> ritorna all'istruzione successiva alla chiamata

           :0040138D inc esi -----------------> incrementa ESI
           :0040138E jmp 00401371 --------> salta a 00401371
            

      :00401385  inc esi --------------------------------> incrementa ESI
      :00401386  jmp 00401371 -----------------------> salta a 00401371 e rifai tutto

Fino a questo punto il CrackMe si comporta esattamente come il suo fratello minore in quanto effettua dei controlli sui char del seriale da noi inserito.
C'é solo una piccola differenza. Se il char da noi inserito è minore di 41h non si fa problemi e va subito a controllare quello successivo; se è maggiore di 5Ah viene effettuata una sottrazione --> valore del char - 20h. 
Ma ora andiamo avanti nel codice....

:00401390 pop esi ----------------> togli ESI
:00401391 call 00401399 ---------> chiamata alla routine 00401399

     :00401399 xor ebx, ebx ----------------------------> azzera EBX
     :0040139B xor edi, edi -----------------------------> azzera EDI
     :0040139D mov cl, byte ptr [edi+004021A3] ------> muovi il byte puntato da (EDI+004021A3) in CL (SICE: d 004021A3) --> "Messing_in_bytes")
     :004013A3 mov bl, byte ptr [esi] -------------------> muovi in BL il byte puntato da ESI (nostro serial modificato dalle routine precedenti)
     :004013A5 test bl, bl -------------------------------> controllo se BL é vuoto
     :004013A7 je 004013B1 ---------------------------> se é vuoto salta a 004013B1
     :004013A9 xor bl, cl --------------------------------> fai uno XOR tra BL e CL (risultato in BL)
     :004013AB mov byte ptr [esi], bl -------------------> sposta BL in ESI
     :004013AD inc esi ----------------------------------> incrementa ESI
     :004013AE inc edi ----------------------------------> incrementa EDI
     :004013AF jmp 0040139D -------------------------> salta a 0040139D e rifai tutto
     :004013B1 ret --------------------------------------> ritorna all'indirizzo 00401326


:00401396 jmp 00401398 --------> salta a 00401398
:00401398 ret --------------------> ritorna all'istruzione successiva alla prima chiamata che abbiamo esaminato (00401232)

La routine all'indirizzo 00401399 e' una delle + importanti di tutto il programma in quanto risiedo il cuore dell'algoritmo di crittazione della password.
Il punto cruciale è all'indirizzo 0040139D dove viene spostato in CL il primo byte presente all'indirizzo 004021A3.
Se noi con SICE andiamo a vedere cosa c'é li (db 004021A3) ci apparirà la stringa "Messing_in_bytes".
Le istruzioni successive si occupano praticamente di effettuare uno Xor tra i char del nostro serial con i char della stringa "Messing_in_bytes" e di mettere il risultato di tale Xor al posto della char utilizzato. In pratica il char del nostro seriale che viene utilizzato per lo Xor (e vengono usati tutti uno ad uno) viene sostituito con il char risultante dal Xor.

00401232   push 0040217E ----------> carica il valore all'indirizzo 0040217E (il nostro seriale lavorato) 
:00401237  call 004013B8 -----------> chiamata alla routine 004013B8

   :004013B8  xor edi, edi ----------------------> azzera EDI
   :004013BC mov cl, byte ptr [00402118] -----> muovi il byte all'indirizzo 00402118 in CL (lunghezza del nostro seriale)
   :004013C2 mov esi, dword ptr [esp+04] -----> sposta la DB puntata da [ESP+04] in ESI
   :004013C6 mov edi, 00402150 --------------> sposta il valore all'indirizzo 00402150 in EDI
   :004013CB repz  cmpsb-----------------------------> confronta CL con EDI. Se sono uguali decrementa CL e EDI e rifai il controllo.
                                                                                       Va avanti quando CL ed EDI sono vuoti oppure se sono diversi tra loro.

   :004013CD ret -------------------------------> ritorna all'istruzione successiva alla chiamata


:0040123C add esp, 00000004 --------> aggiungi ad ESP il valore 4h
:0040123F  test cl, cl -------------------> controlla se CL é uguale a 0
:00401241  je 0040124A --------------> se é uguale a 0 salta a 0040124A e carica la MessageBox di complimenti
:00401243  call 00401349 -------------> vai all'indirizzo 00401349 e carica la MessageBox di errore

Bene!Dovreste aver capito!NO??????? Beh ora vi spiego meglio;)
Allora la routine all'indirizzo 004013B8 non fa altro che controllare i char del nostro seriale modificato con i char alla locazione 00402118.
Se sono TUTTI uguali avete risolto il CrackMe, altrimenti no!
Dovete sapere quindi quali sono i byte con i quali si esegue il confronto; andate in SICE e scrivete db 00402118. Annotatevi in un foglio di carta tutti i bytes della prima riga che sono : 1F 2C 37 36 3B 3D 28 19 3D 26 1A 31 2D 3B 37 3E.
Ora vi ricordate prima che il nostro serial era stato xorato con la stringa "Messing_in_bytes"? Allora la soluzione del CrackMe è semplice.
Basterà xorare i bytes al'indirizzo 0042118 con i char (in HEX) della stringa "Messing_in_bytes" e si troverà il corretto seriale! Semplice no!

1F XOR 4D "M" = 52 --> R
2C XOR 65 "e" = 49 --> I
37 XOR 73  "s" = 44 --> D
36 XOR 73  "s" = 45 --> E
3B XOR 69  "i" = 52 --> R
3D XOR 6E "n" = 53 --> S
28 XOR 67  "g" = 4F --> O
19 XOR 5F "_"= 46 --> F
3D XOR 69 "i" = 54 --> T
26 XOR 6E "n" = 48 --> H
1A XOR 5F "-" = 45 --> E
31 XOR 62 "b" = 53 --> S
2D XOR 79 "y" = 54 --> T
3B XOR 74 "t" = 4F --> O
37 XOR 65 "e" = 52 --> R
3E XOR 73 "s" = 4D --> M

La password corretta sarà quindi "RIDERSOFTHESTORM".

 

 

CrackMe 3 by Cruehead / MiB
Make a KeyFile


Siamo giunti all'ultimo CrackMe,il terzo. Come leggiamo dalle istruzioni questo prog. necessità di un KeyFile. Per prima cosa avviamo il programma e vediamo cosa succede. Niente!!!! Solo una stringa "Uncracked" in alto! Allora cominciamo a cracckarlo ;)
Avviamo FileMon e poi avviamo il programma. Su FileMon appariranno delle stringhe relative al nostro CrackMe3 ed in particolare:

- CRACKME3        READ        C:\CrackMe\3\CRACKME3.EXE        SUCCESS
- CRACKME3        READ        C:\CrackMe\3\CRACKME3.KEY        NOTFOUND

Da questo notiamo che il KeyFile avrà nome CRACKME3.KEY e che dovrà essere nella stessa cartella del prog.
Allora creiamone uno. Avviamo il programma e... "Uncracked".
Beh, sarebbe stato troppo semplice!!!!
Apriamo allora SICE e settiamo un BreakPoint all'API ReadFile (API che gestisce la lettura di file); usciamo premendo F5 e poi avviamo il programma.
Dovremo premere un bel po' di volte F12 fino a che in basso a destra di SICE apparirà il nome CRACKME3 (prima ci sono tutte le chiamate di Windows).
Arriveremo in questo punto.....

:00401066 cmp dword ptr [004021A0], 00000012 ---------> confronta la lunghezza del testo inserito nel KeyFile con il valore 12h (18d)
:0040106D jne 00401037 -----------------------------------> se non é uguale a 12h salta a 00401037 ed esci dal programma
:0040106F push 00402008 ----------------------------------> carica il dato all'indirizzo 00402008 (SICE: dd 00402008 ---> testo nel KeyFile)
:00401074 call 00401311 -----------------------------------> chiamata all'indirizzo 00401311

    :00401311 xor ecx, ecx ---------------------------> azzera ECX
    :00401313 xor eax, eax ---------------------------> azzera EAX
    :00401315 mov esi, dword ptr [esp+04] ----------> sposta in ESI la DoubleWord puntata da [ESP+04]
    :00401319 mov bl, 41 ----------------------------> sposta in BL il valore 41h (65d - "A")
    :0040131B mov al, byte ptr [esi] ------------------> sposta il byte di ESI il AL
    :0040131D xor al, bl ------------------------------> fai uno XOR tra AL e BL (risultato in AL)
    :0040131F mov byte ptr [esi], al ------------------> sposta AL in ESI (sostituisci il byte di ESI con quello xorato)
    :00401321 inc esi ---------------------------------> incrementa ESI
    :00401322 inc bl ----------------------------------> incrementa BL
    :00401324 add dword ptr [004020F9], eax -------> somma EAX (ovvero AL) alla DoubleWord all'indirizzo 004020F9
    :0040132Acmp al, 00 -----------------------------> confronta AL con 00
    :0040132C je 00401335 --------------------------> se é uguale a 00 salta a 00401335
    :0040132E inc cl ----------------------------------> incrementa CL
    :00401330 cmp bl, 4F -----------------------------> confronta BL con 4Fh (79d - "O")
    :00401333 jne 0040131B -------------------------> se é uguale salta all'indirizzo 0040131B
    :00401335 mov dword ptr [00402149], ecx -------> sposta ECX (ovvero CL) nella DoubleWord all'indirizzo 00402149
    :0040133B ret -------------------------------------> ritorna all'indirizzo successivo alla chiamata

:00401079 xor dword ptr [004020F9], 12345678 ----------> fai uno Xor tra la DoubleWord presente all'indirizzo 004020F9 e il valore 12345678h

Analizziamo questo pezzo di codice. Allora il programma prima di tutto controlla che la lunghezza di ciò che abbiamo inserito nel KeyFile sia uguale a 12h ovvero 18d; in poche parole dovremmo inserire 18 char. Se ne ha trovati 12h va avanti ed effettua uno Xor tra il char inserito da noi ed il char presente in BL.
Come vediamo in BL all'inizio viene caricato il char "A"; poi, quando si punto al char successivo nel nostro KeyFile, BL viene incrementato e quindi il secondo Xor verrà effettuato con il char "B" (controllate una tabella ASCII) e cosi via fino alla fine.Ogni risultato dello Xor viene memorizzato in una DoubleWord all'indirzzo 004020F9. Quando BL assume il char "O" allora si esce dal ciclo e la DoubleWord all'indirizzo 004020F9 viene Xorata col valore 12345678h.
(Ricordarsi che ogni char xorato viene poi sostituito, nel KeyFile, col risultato dello xor)

Riassumendo: pensiamo di aver inserito la stringa ">>>ILM@2001<<<<1234" le operazioni sranno le seguenti:

Primi 14 char del nome = ">>>ILM@2001<<<"

Chr Seriale (in HEX)

>=3E
>=3E
>=3E
I=49
L=4C
M=4D
@=40
2=32
0=30
0=30
1=31
<=3C
<=3C
<=3C

Chr (in HEX) con i quali verra' effettuato lo XOR

A=41
B=42
C=43
D=44
E=45
F=46
G=47
H=48
I=49
J=4A
K=4B
L=4C
M=4D
N=4E

Operazioni di Xor

3E xor 41 = 7F
3E xor 42 = 7C
3E xor 43 = 7D
49 xor 44 = D
4C xor 45 = 9
4D xor 46 = B
40 xor 47 = 7
32 xor 48 = 7A
30 xor 49 = 79
30 xor 4A = 7A
31 xor 4B = 7A
3C xor 4C = 70
3C xor 4D = 71
3C xor 4E = 72

Somma i risultati dello XOR

7F+7C+7D+D+9+B+7+7A+79+7A+7A+70+71+72=4DA

XORA il risultato col valore 12345678h

4DA xor 12345678=123452A2

Quindi se inseriamo la stringa ">>>ILM@2001<<<1234" la DoubleWord all'indirizzo 004020F9 assumerà il valore 123452A2

Ma ora andiamo avanti nel programma....

:00401083 add esp, 00000004 ----------> somma ad ESP il valore 4h
:00401086 push 00402008 --------------> carica il valore presente all'indirizzo 00402008 (il nostro testo del KeyFile modificato)
:0040108B call 0040133C --------------> chiamata alla routine all'indirizzo 0040133C

    :0040133C mov esi, dword ptr [esp+04] --------> sposta la DoubleWord puntata da [ESP+04] in ESI (il nostro testo modificato)
    :00401340 add esi, 0000000E ------------------> somma 0Eh (14d) ad ESI
    :00401343 mov eax, dword ptr [esi] ------------> sposta la DoubleWord puntata da ESI in EAX (ovvero gli utlimi 4 char del testo del KeyFile)
    :00401345 ret -----------------------------------> ritorna all'istruzione successiva alla chiamata

:00401093  cmp eax, dword ptr [004020F9] -----------> confronta la DoubleWord in 004020F9 con EAX
:00401099  setz al --------------------------------------> non ne sono sicuro ma dovrebbe essere setta il flag Z ad AL (o almeno una cosa del genere)
:0040109C push eax ------------------------------------> carica EAX
:0040109D test al, al ------------------------------------> Al é 0?
:0040109F je 00401037 --------------------------------> SI'. Allora salta a 00401037 e carica la MessageBox di complimenti
:004010A1 push 0040210E -----------------------------> carica la stringa "CrackMe 3.0         "
:004010A6 call 00401346 -------------------------------> chiamata che caricherà la stringa "CrackMe 3.0 Uncracked"

L'ultimo pezzo del codice é molto semplice e ci fa capire che gli ultimi 4 char del testo che noi abbiamo inserito nel KeyFile devono essere uguali alla DoubleWord presente all'indirizzo 004020F9. Questo si deduce in quanto in EAX vengono caricati gli ultimi 4 char del testo del KeyFile e poi EAX viene comparata con la DoubleWord, Se sono uguali allora abbiamo Cracckato il programma altrimenti no.
Per vedere quali sono questi bytes, o fate i calcoli come vi ho spiegato precedentemente, oppure basta aprire SICE e digitare (in un qualsiasi indirizzo purché sia successivo alle operazioni di Xor precedentemente fatte)  dd 004020F9. In questo modo apparirà il valore della DoubleWord che per me é 123452A2.
Adesso basta aprire il KeyFile con un HexEditor ed inserire gli ultimi 4 bytes del testo in modo corretto.
Bisogna inserire i bytes partendo da destra verso sinistra a coppia.
In poche parole bisognerà scrivere: A2 52 34 12. Salvate, avviate il CrackMe e... voila'! Cracckato!!!!!!!!!

Apparirà anche una MessageBox di complimenti dove comparirà "Cracked by " ed una serie di simboli che guarda caso sono uguali al nostro testo dopo che ha subito le modifiche. Per far apparire il nome che si vuole bisogna procedere in questo modo:

  1. Scegliere un nome da far apparire, io scelgo >>>ILM@2001<<< 

  2. Fare le operazioni di Xor con le lettere "ABCDEFGHILMN"

  3. Scrivere i risultati dei vari Xor sul KeyFile 

  4. Calcolare gli ultimi 4 bytes da inserire nel KeyFile

Operazioni di Xor

3E xor 41 = 7F
3E xor 42 = 7C
3E xor 43 = 7D
49 xor 44 = D
4C xor 45 = 9
4D xor 46 = B
40 xor 47 = 7
32 xor 48 = 7A
30 xor 49 = 79
30 xor 4A = 7A
31 xor 4B = 7A
3C xor 4C = 70
3C xor 4D = 71
3C xor 4E = 72

Il primi 14 bytes del KeyFile saranno quindi 7F 7C 7D 0D 09 0B 07 7A 79 7A 7A 70 71 72
Calcolo gli ultimi 4 bytes e trovo: 2B 55 34 12
Quindi il mio CRACKME3.KEY sarà formato da questi bytes: 7F 7C 7D 0D 09 0B 07 7A 79 7A 7A 70 71 72 2B 55 34 12

Ricordarsi che il nome che verrà stampato dovrà essere OBBLIGATORIAMENTE di 14 char.

ILM©2001                        

Note finali

Spero di essere stato chiaro e preciso in ogni mio punto. Mi scuso per qualsiasi errore non voluto :)

Disclaimer

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.