*****************************************                                   
                                            RingZer0 Presents                   
                                              
                                 "CoSH Crackme3" by PUSILLUS 
                                                                 18/2/99
                                *****************************************
-------------------------------------------------------------------------------------------------------------
Ottimo tutorial, ottimo soprattutto per chi non conosce bene la tecnica dello xoring e la vorrebbe affinare.
Quequero
-------------------------------------------------------------------------------------------------------------
 
 
Tools: SoftIce

Ciao a tutti, questa volta siamo alle prese con un classico crackme:

Lanciando l'eseguibile verra' richiesta nome e password, con il tasto ok viene eseguito il Check della password. Come di consueto ho inserito il mio nome, una password a caso e settato il canonico BPX GetDlgItemTextA con il Sice, ma il debugger, una volta dato l'OK non e' intervenuto!
Le API usate per leggere da un edit control sono:
GetDlgItemText
GetDlgItemTextA
GetWindowText
GetWindowTextA
Bisognerebbe provarle tutte; allora ho deciso di prendere una strada diversa:
lanciamo il crackme, una volta che appare la dialogbox entriamo in Sice e
digitiamo TASK. Compariranno un bel po' di processi che il Win sta eseguendo ma
quello che interessa a noi e' solo il crackme3:

Taskname SS:SP StackTop StackBot StackLow TaskDB hQueue Events
crackme3 0000:0000 005ED000 05F0000 11DE 0E47 0000
...

adesso andiamo a vedere quali handle appartengono al nostro processo "HWND crackme3"

Window-Handle hQueue SZ QOwner Class_Name Window Procedure
03AC(1) OE47 32 CRACKME3 #32770 (Dialog) 1457:00000694
03CC(2) OE47 32 CRACKME3 Button ...
03A8(2) OE47 32 CRACKME3 Static ...
0400(2) OE47 32 CRACKME3 Static ...
03FC(2) OE47 32 CRACKME3 Edit ...
03E0(2) OE47 32 CRACKME3 Edit ...
...

Prendiamo nota della handle della prima Edit control (nel mio caso 03FC)
E' possibile impostare un break al verificarsi di un Window Message con il comando BMSG, nel nostro caso il messaggio che ci interessa e' WM_GETTEXT sull'handle dell'edit control.
Allora impostiamo "BMSG 03fc WM_GETTEXT" e usciamo da Sice (Attenzione perch� il valore 03fc sul mio cp cambia ogni volta che riavvio iil prog NdQ).

Inseriamo i valori nelle dialogbox, nel mio caso "pusillus" e "00000000" e diamo OK.
Il debugger ha brekkato in Kernel.alloc, tramite F12 torniamo indietro dalle varie call e ci accorgiamo che il programmino fa uso delle MFC42 (MFC42!.text.00...) e la
funzione usata dalle MFC per leggere il testo e' GetWindowTextA mmm...
una vera rottura di scatole, infatti io non ho nessuna reference x le MFC e non so
cosa cavolo fanno le funzioni! Comunque Proprio prima della GetWindowTextA noterete:
....
PUSH EAX
PUSH DWORD PTR [ESI+20]
GetWindowTextA
....

Consultando la reference alle API si vedra' che quel Push EAX corrisponde
all'indirizzo del buffer dove viene memorizzato il valore letto dall'edit control
bastera' impostare un bpx su quella riga e disabilitare gli altri brakpoint
per conoscere gli indirizzo nel quale viene memorizzato il nome e la pwd.
La prima volta che ho eseguito il debugging non ho analizzato a fondo il codice
delle MFC e ho proseguito:
diamo l'ultimo F12 e ci troveremo finalmente al codice del Crackme3.exe,
e precisamente ci dovremmo trovare alla riga 00401538 dopo la call alla funzione delle MFC che come abbiamo visto si occupa di fare un Gettext.

A questo punto mi sono messo a smanettare con i registri e ho scoperto che
l'indirizzo a cui punta ECX (00760A7C) contiene il nome inserito. In queste cose
ci vuole anche una buona dose di curiosita' e di culo! Probabilmente quella
funzione delle MFC restituisce in ECX l'indirizzo in cui memorizza le stringhe!

Disabilitiamo i brekpoint e andiamo avanti con f10 fino ad eseguire la seconda call
alla riga 00401533 e andiamo a leggere in ECX l'indirizzo della Pwd (00760A9C).

---------------------------
:00401521 8B45E0 mov eax, dword ptr [ebp-20]
:00401524 05E0000000 add eax, 000000E0
:00401529 50 push eax
:0040152A 8B4DE0 mov ecx, dword ptr [ebp-20]
:0040152D 81C1A0000000 add ecx, 000000A0

* Reference To: MFC42.Ordinal:0F22, Ord:0F22h
|
:00401533 E866030000 Call 0040189E <----- Legge Nome
:00401538 8B4DE0 mov ecx, dword ptr [ebp-20]
:0040153B 81C1E4000000 add ecx, 000000E4
:00401541 51 push ecx
:00401542 8B4DE0 mov ecx, dword ptr [ebp-20]
:00401545 83C160 add ecx, 00000060

* Reference To: MFC42.Ordinal:0F22, Ord:0F22h
|
:00401548 E851030000 Call 0040189E <---- Legge Pwd
:0040154D 8B55E0 mov edx, dword ptr [ebp-20]
:00401550 81C2E0000000 add edx, 000000E0
:00401556 52 push edx
:00401557 8D4DE4 lea ecx, dword ptr [ebp-1C]
---------------------------


andiamo avanti con F10 fino a raggiungere la riga 00401570: il programma azzera
tutti i registri mmm... si sta preparando a fare qualcosa di importante, infatti
alla riga 0040157D in eax viene caricato l'indirizzo del nome:


---------------------------
:00401570 33C0 xor eax, eax
:00401572 33DB xor ebx, ebx
:00401574 33C9 xor ecx, ecx
:00401576 B901000000 mov ecx, 00000001 <-- cl<1
:0040157B 33D2 xor edx, edx
:0040157D 8B45E4 mov eax, dword ptr [ebp-1C] <-- EAX<00760A7C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040158B(C)
|
:00401580 8A18 mov bl, byte ptr [eax] <-- bl byte puntato da EAX
:00401582 32D9 xor bl, cl <-- xor bl e cl
:00401584 8818 mov byte ptr [eax], bl <-- sostituisce il valore puntato da EAX con bl
:00401586 41 inc ecx <-- incrementa ECX
:00401587 40 inc eax <-- incrementa EAX
:00401588 803800 cmp byte ptr [eax], 00
:0040158B 75F3 jne 00401580 <-- esegue il loop fino a che
non e' stata processata
tutta la stringa.
---------------------------

Allora avete capito cosa fa questa parte di codice? Ricapitoliamo:

00760A7C > 70 75 73 69 6c 6c 75 73 (pusillus)
XOR cl 01 02 03 04 05 06 07 08
00760A7C > 71 77 70 6d 69 6a 72 7b


Continuando con F10 arriviamo alla parte di codice in cui viene processata la
Pwd:

---------------------------
:0040158D 33C0 xor eax, eax
:0040158F 33DB xor ebx, ebx
:00401591 33C9 xor ecx, ecx
:00401593 B90A000000 mov ecx, 0000000A <-- ECX<0A
:00401598 33D2 xor edx, edx
:0040159A 8B45F0 mov eax, dword ptr [ebp-10] <-- EAX<00760A9C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004015A8(C)
|
:0040159D 8A18 mov bl, byte ptr [eax] <-- bl< valore puntato da eax
:0040159F 32D9 xor bl, cl <-- xor bl e cl
:004015A1 8818 mov byte ptr [eax], bl <-- valore puntato da eax < bl
:004015A3 41 inc ecx
:004015A4 40 inc eax
:004015A5 803800 cmp byte ptr [eax], 00 <-- esegue il loop fino che non ha
:004015A8 75F3 jne 0040159D processato l'intera stringa
---------------------------

Niente di diverso da prima solo che in questo caso CL viene inizializzato con 0A:


00760A9C > 30 30 30 30 30 30 30 30 (00000000)
XOR cl 0A 0B 0C 0D 0E 0F 10 11
00760A9C > 3A 3B 3C 3D 3E 3F 20 21


andando avanti ci accorgiamo che i valori delle due stringhe cosi' modificati
vengono confrontati:

---------------------------
:004015AA 8B45E4 mov eax, dword ptr [ebp-1C] <-- 00760A7C
:004015AD 8B55F0 mov edx, dword ptr [ebp-10] <-- 00760A9C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004015BF(C)
|
:004015B0 33C9 xor ecx, ecx
:004015B2 8A18 mov bl, byte ptr [eax] <-- bl< val. puntato da eax
:004015B4 8A0A mov cl, byte ptr [edx] <-- cl< val. puntato da edx
:004015B6 3AD9 cmp bl, cl <-- comparazione
:004015B8 7509 jne 004015C3 <-- non uguali salta a "ERROR"
:004015BA 40 inc eax
:004015BB 42 inc edx
:004015BC 803800 cmp byte ptr [eax], 00 <-- controllo su fine stringa
:004015BF 75EF jne 004015B0 <-- riesegue il ciclo x tutta la stringa
:004015C1 EB16 jmp 004015D9 <-- salta a "YOU DID IT"

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00401503(U), :0040151C(U), :004015B8(C)
|
:004015C3 6A00 push 00000000

* Possible StringData Ref from Data Obj ->"ERROR"
|
:004015C5 686C304000 push 0040306C

* Possible StringData Ref from Data Obj ->"One of the Details you entered "
->"was wrong"
|
:004015CA 6840304000 push 00403040
:004015CF 8B4DE0 mov ecx, dword ptr [ebp-20]

* Reference To: MFC42.Ordinal:1080, Ord:1080h
|
:004015D2 E8BB020000 Call 00401892
:004015D7 EB14 jmp 004015ED

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004015C1(U)
|
:004015D9 6A00 push 00000000

* Possible StringData Ref from Data Obj ->"YOU DID IT"
|
:004015DB 6834304000 push 00403034

* Possible StringData Ref from Data Obj ->"Well done,Cracker"
|
:004015E0 6820304000 push 00403020
---------------------------

Arrivati a questo punto non ci resta che calcolare una password corretta
per il nome inserito:

71 77 70 6d 69 6a 72 7b <-- valori calcolati dal programma sul nome
0A 0B 0C 0D 0E 0F 10 11 <-- xoring
7B 7C 7C 60 67 65 62 6A <-- password corretta: {||`gebj


Facile no?
============================================================================
Copyright:

Questo testo pu� essere liberamente divulgato a patto di non essere modificato in nessuna sua parte.
La presente copia in particolare � riservata al progetto UIC su richiesta di Quequero.
============================================================================

Pusillus.