CrackMe1 by massh^CookieCrK
rozwiazanie by Dulek~CookieCrK

Oki. Witam to moj pierwszy tutor a moim zadaniem jest opisanie
zabezpieczenia w CrackMe1 massha , wiec do roboty ;)

Odpalamy CrackMe i widzimy ze celem jest znalezienie poprawnego
hasla.

Zapuszczamy wiec Si, wpisujemy lipny kod np. 099877655
i zakladamy standardowa pulapke (bpx) na Hmemcpy 
(jest to API odpowiedzialna za kopiowanie danych).
Wciskamy guzik OK i Si przejmuje kontrole, nie jestesmy jednak w 
kodzie programu musimy wiec nacisnac kilkakrotnie F12 
(dokladnie 9 razy) az na belce odzielajacej okno kodu (Code Window)
od okna komend (Command Window) pojawi sie "CrackMe1!CODE"
ok, jestesmy juz w kodzie programu:

0040108F                call      USER32!GetDlgItemTextA 
00401094                test      eax,eax     <--------- jestesmy tutaj
00401096                jz        004010D2    //Go_away_looser
00401098                push      004020D3           \
0040109D                push      00                 |na stos odkladane
0040109F                push      0C                 |zostaja parametry
004010A1                push      000003E8           |wywolania API Send..
004010A6                push      DWORD PTR [EBP+08] /
004010A9                call      USER32!SendDlgItemMessageA
004010AE                call      004010F0
004010B3                mov       esi,004020BB
004010B8                call      00401113
004010BD                test      eax,eax
004010BF                jz        004010C8
004010C1                mov       ebx,0040201D
004010C6                jmp       004010CD
 
Po wywolaniu USER32!GetDlgItemTextA rejestr EAX zwraca ilosc znakow 
w naszym hasle , nastepnie sprawdzenie czy zostaly wprowadzone jakie
kolwiek dane, teraz widzimy pushe odkladajace na stos parametry wywo
lania API SendDlgItemMessageA , w naszym przypadku odpowiada ona za
wyczyszczenie okna dialogowego gdzie wpisalismy nasze dane. Wiec zeby
za kazdym razem nie wpisywac tych danych wystarczy ze pierwszy push
zamienimy na skok do calla 4010F0, ok. do roboty gdy jestesmy juz na
tym pushu to wywolujemy nastepujace komendy Si:

a // enter
jmp 4010AE //enter

Zmiany ktore wprowadzilismy zmodyfikowaly Crackme w pamieci operacyjnej. 
Ponowne wyjscie i uruchomienie CracMe anuluje wprowadzone przez nas zmiany.

Jestesmy teraz nad callem 4010F0, wejdmy do niego (F8) 
i ku naszej radosci ujzymy:

1) 004010F0                mov edi, 00402086   
2) 004010F5                push edi
3) 004010F6           |--> cmp byte ptr [edi], 00 
4) 004010F9           |    je 00401111 >-------------|    
5) 004010FB           |    mov eax, dword ptr [edi]  |     
6) 004010FD           |    ror eax, 03               |     
7) 00401100           |    xor eax, 12345678         |    
8) 00401105           |    xchg al, ah               |    
9) 00401107           |    rol eax, 03               |    
A) 0040110A           |    mov dword ptr [edi], eax  |    
B) 0040110C           |    add edi, 00000004         |    
C) 0040110F           |--< jmp 004010F6              |
D) 00401111                pop edi <-----------------|   
E) 00401112                ret     


1. Do EDI przenoszony jest offset naszego hasla
2. Odklada na stos EDI
3. Sprawdza czy bajt pod [edi] jest jakas liczba >0 
4. Skok jezeli nie jest , co oznacza w praktyce koniec naszego hasla
5. Przenosi pierwsze 4 znaki naszego hasla do EAX
6. ror eax,03

Ror (Rotate on right = obrot w prawo) instrukcja ta przesuwa bity
wewnatrz rejestru (32/16).

ok. przyklad.

Nasze pierwsze 4 znaki hasla to '0998'(Dec) = 30393938 (Hex), spojzmy 
teraz na zawartos rejestru EAX = 38393930 , czyli zgadza sie 4 pierwsze
znaki.

Zeby zrozumiec ta operacje musimy potraktowac nasze dane jako liczby 
dwjkowe (Binarne)

38393930 (Hex) = 111000001110010011100100110000 (Bin)
                                            
po operacji Ror eax,03                      
                                             
07072726 (Hex) = 111000001110010011100100110 (Bin)

Teraz juz rozumiesz

111000001110010011100100110000 (1)
111000001110010011100100110    (2)

,przesuniecie spowodowalo obciecie 3 ostatnich 0 i zmienilo wynik

,a gdyby tak teraz zastosowac instrukcje Rol (Rotate on left = obrot w lewo)
sprobujmy rol eax,03

07072726 (Hex) = 111000001110010011100100110 (Bin)

po operacji Rol eax,03

38393930 (Hex) = 111000001110010011100100110000 (Bin)

Tak, tak mamy nasza liczbe poczatkowa, co oznacza ze instrukcje
Ror i Rol sa wpelni "reversable" odwracalne .


ok. to juz jest jasne wiec lecimy dalej.

7. Xoruje wynik naszej operacji (7072726H) z liczba 12345678h
   Po tej instrukcji EAX=1533715Eh   

8. Zamienia miejscami 8 bitowe rejestry al,ah 
   
                  EAX= 15 33 71 5E (Hex)
                             /\ /\
 8 straszych bitow EAX <---  AH AL ---> 8 mlodszych bitow EAX
                             \\//
                              AX --> 16 mlodszych bitow EAX 

   Po tej instrukcji EAX=15335E71h

9. To juz jest jasne
   Po tej instrukcji EAX=A99AF388h

A.Wynik wszystkich naszych operacji przeprowadzonych na rejestrze EAX
  zapisuje w miejsce danych poczatkowych.

B.Zwieksza wartosc edi o 4, czyli edi wskazuje na 4 kolejne znaki 
  naszego hasla

C.Skok do poczatku procedury 

Gdy juz wszystkie dane wprowadzonego przez nas hasla zostana
przemaglowane w petli, nastapi wyjscie z Calla.

004010AE                call      004010F0     // nasze petelki
004010B3                mov       esi,004020BB ---> Jestesmy tutaj
004010B8                call      00401113
004010BD                test      eax,eax
004010BF                jz        004010C8
004010C1                mov       ebx,0040201D
004010C6                jmp       004010CD


ok. wchodzimy (F8) teraz do Call 00401113

1)00401113                xor eax, eax
2)00401115                mov ecx, 00000015h
3)0040111A                repz cmpsb
4)0040111C                jne 0040111F
5)0040111E                inc eax
6)0040111F                ret

1. Zeruje rejestr EAX
2. Przenosi do ECX wartosc 15(Hex) = 21 (Dec)
3. Repz (powtarzaj dopoki rowne) cmpsb (porownuje bajty)
   Wyglada to tak: porownuje kolejno bajty z EDI i ESI jezeli rowne
   to flaga Z=1 , EDI i ESI incrementowne o 1 (+1) , decrementownie ECX
   (-1) ktory jest licznikiem.

4. Jezeli 15h bajtow wskazanych przez EDI bylo rowne tym wskazanym przez
   ESI to flaga Z=1 i skok nie nastapi. 

5. Zwieksza o 1 EAX
6. Wyjscie z calla


Wychodzimy z Call:

1)004010BD                test      eax,eax
2)004010BF                jz        004010C8
3)004010C1                mov       ebx,0040201D
4)004010C6                jmp       004010CD

Test eax,eax i skok jezeli rowne (skok nie nastapi jezeli EAX>0), 
przenosi do ebx offset wiadomosci gratulujacej ktora pojawi sie po
wpisaniu poprawnego hasla.

Czyli wszystko jasne dane z pod EDI musza rownac sie tym z pod ESI i
wtedy program zostanie zarejestrowany:

EDI- to offset z naszymi danymi zmodyfikowanymi w petli
ESI- to offset z danymi zapisanymi w programie (na stale).

"d esi" i widzimy w oknie z danymi:

D6 81 D2 E5 C5 A2 81 E5 D0 AC CA B1
DC AD C2 F9 DC B3 CD FF B7 A2 A3 91

Musimy odwrocic teraz dzialanie petli tak by wygenerowac dane ktore 
po przejsciu przez nia dadza nam dane rowne tym z pod ESI.

Do roboty , jeszcze raz spojzmy na petle.

    
    mov eax, dword ptr [edi]    
    ror eax, 03                    
    xor eax, 12345678h           
    xchg al, ah                
    rol eax, 03                
    mov dword ptr [edi], eax    


Po pierwszym przejsciu przez petle EAX musi myc rowny E5 D2 81 D6 H
czyli po kolei:

1)mov  eax,E5D281D6h
2)ror  eax,03h
3)xchg al,ah
4)xor  eax,12345678h
5)rol  eax,03

1. Umiescimy w eax liczbe E5D281D6h, (pierwsze dane z pod ESI)
2. Jak juz pisalem instrukcje rol/ror sa odwracalne czyli instrukcje
   rol eax,03 odwracamy za pomoca ror eax,03
3. 8 bitowe polowki rejestru AX wracaja na swoje miejsca.
4. Instrukcja Xor tez jest odwracalna
5. Patrz (2)

Teraz wpisujemy 
"? eax" //enter 

;komenda "?" rejestr/liczba wyswietla nam kolejno wartosci:
;(Hex) (Dec) (ASCII)
;w naszym przypadku "? eax" zwroci nam wartosci:
;74736146(Hex) 1953718598(Dec) 'tsaF'(ASCII)
;Znaku "?" mozna uzywac takze do obliczen np:
; ? x*z  //enter wyswietli w lini komend wynik mnozenia 
; ? x/z  //dzielenie
; ? x^z  //Xorowanie
; ? x>>z //Shr (Shift Right)
; ? x<<z //Shl (Shift Left)     
; ? x&z  //AND 
; ? x|z  //OR   
; ? ~x   //NOT 
; 'x' i 'z'to dowolne liczby w przedziale (0H - FFFFFFFFH)
; ? +x   //w tym przypadku x traktowany jest jako liczba (Dec)
; np. (? 999 ) wyswietli nam kolejno 3E7(HEX) 999(DEC) ''(ASCII)

Nas interesuje wartosc ASCII czyli 'tsaF' odwroc to czyli 'Fast'
pierwsze 4 znaki hasla, teraz juz sam to skoncz ;)



   


