
             .......::::::: T  U  T  O  R  I  A  L :::::::.......



  For : CrackMe1 by Zenek Jajko
   By : haxmen ind.
Skill : easy
Tools : SoftIce 4.05
 Date : 19.o4.2oo2



/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

 Witam!
 Na samym poczatku chcialbym zaznaczyc, ze jezeli nie jestes newbies to wez
 sie sam za te crackme. A jezeli jest inaczej to czytaj dalej. Aha jest to
 moj pierweszy tut i prosze o wyrozumialosc (i sorki za ort.). Postaram
 sie wszystko przedstawic tak lopatologicznie jak tylko umiem i zdolam ;-)

 Odrazu mozna zauwazyc, ze crackme jest malych rozmiarow (4KB) a po blizszym
 przyjzeniu sie zawartosci pliku widac, ze jest ono spakowane (UPX).
 Nie bedziemy rozpakowywac progsa bo nie bedzie nam to potrzebne, gdyz nie
 zawiera zadnych sztuczek typu antydebug itp.
 Odpalamy crackme i widzimy jedno pole do wpisania haselka a wiec wpisujemy
 jakis dowolny text np.: 12121212, stawiamy "bpx getwindowtexta" i
 klikamy "OK" i wywala nam messagebox'a, ze wpisalismy zle haslo.
 Ok teraz walimy "bpx messageboxa" i klikamy "OK" teraz przerwalo nam SI
 a wiec wciskamy F12 i widzimy okienko, ze zle ... i teraz "OK".
 I znowu przerwalo nam SI tym razem w kodzie crackemesa pod ostatnim callem
 odpowiedzialnym za message'a widzimy wszystkie funkcje api jakie zostaly
 uzyte i jest tez api adpowiedzialne za pobranie dlugosci textu.
 wpisujemy "bc *" (aby wyczyscic wszystkie breakpointy)
 teraz stawiamy na nie "bpx getwindowtextlengtha" i wychodzimy z SI (CTRL+D)
 kilikamy na "OK" i przerywa nam si potem F12 i jestesmy w kodzie programu
 widzimy cos takiego:

:00401114 E89B010000              call GetWindowTextLengthA
:00401119 83F80E                  cmp eax, 0000000E
:0040111C 0F855E010000            jne 00401280

 Teraz w EAX mamy dlugosc wpisanego przez nas textu (8) i w drugiej linijce
 jest porownanie EAX z E (14 dec) czyli wpisane haselko musi miec 14 zankow.
 Jezeli nie ma to skok (jne 00401280) sie wykona i wywali nam messagebox'a.
 Wychodzimy z SI i wpisujemy 14 cyferek np.: 12121212121212 klikamy "OK".
 Jestesmy w SI i po przejsciu skoku wywolywana jest funkcja api
 GetWindowTextA. Po jej wywolaniu mamy taki kod:

:0040112B E87E010000              call GetWindowTextA
:00401130 33DB                    xor ebx, ebx                  (1)
:00401132 8A1DA4314000            mov bl, byte ptr [004031A4]   (2)
:00401138 83EB26                  sub ebx, 00000026             (3)
:0040113B B887314000              mov eax, 00403187             (4)
:00401140 03C3                    add eax, ebx                  (5)
:00401142 803850                  cmp byte ptr [eax], 50        (6)
:00401145 0F851C010000            jne 0040126                   (7)

 W linijce (2) zerowany jest rejestr EBX. W (3) linijce do BL ladowany jest
 pierwszy znak naszego password'a. Potem od niego odejmowane jest 26h a
 do EAX ladoawny jest pewien offset.  W linijce (5) do tego offsetu
 dodawany jest wynik odejmowania. A w (6) mamy porownanie czy bajt ktory
 wskazuje rejestr EAX  jest rowny 50h (P). A wiec nie myslac dlugo ;-) wiemy,
 ze do EAX musi byc dodana taka wartosc aby wskazywal offset do bajtu "P".
 Chili EAX=00403187 i teraz musimy sobie obliczyc pierwsza literke haselka.
 "P" znajduje sie pod offsetem 00403196. Wiec odwrocmy procke w SI: 

 ? 00403196-00403187 (= F)
 ? F+26 (= 35 "5")

 I mamy juz pierwsza cyferke hasla jest nia "5".
 Wychodzimy z SI i zmieniamy pierwsza cyferke na "5".
 Potem "OK" i po nie wykonanym skoku z punktu (7)
 dalej mamy taki kod:

:0040114B 33DB                    xor ebx, ebx                 (8)
:0040114D 8A1DA5314000            mov bl, byte ptr [004031A5]  (9)
:00401153 83EB21                  sub ebx, 00000021            (10)
:00401156 B887314000              mov eax, 00403187            (11)
:0040115B 03C3                    add eax, ebx                 (12)
:0040115D 803845                  cmp byte ptr [eax], 45       (13)
:00401160 0F8501010000            jne 00401267                 (14)

 W punkcie (9) do BL ladowana jest 2 cyferka hasla od niej odejmowane
 jest 21h i do EAX ladowany jest offset ten co ostatnio i tak jak
 poprzednio dodawany jest do EAX wynik odejmowania.
 Tym razem postepujemy tak jak poprzednio czyli w SI wpusujemy:

 ? 00403197-00403187 (= 10)
 ? 10+21 (=31 "1") 

 I w ten sposob mamy 2 cyferke hasla, po wyjsciu z SI wpisujemy ja zamiast
 "1" i dajemy "OK" i dochodzimy do instrukcji nastepnej po nie wywolanym
 skoku z punktu (14) i mamy taki oto kod:

:00401166 33DB                    xor ebx, ebx                (15)
:00401168 8A1DA6314000            mov bl, byte ptr [004031A6] (16)
:0040116E B88D114000              mov eax, 0040118D           (17)
:00401173 F60075                  test byte ptr [eax], 75     (18)
:00401176 0F84EB000000            je 00401267                 (19)
:0040117C B89B114000              mov eax, 0040119B           (20)
:00401181 F60075                  test byte ptr [eax], 75     (21)
:00401184 0F84DD000000            je 00401267                 (22)
:0040118A F6C331                  test bl, 31                 (23)
:0040118D 0F84D4000000            je 00401267                 (24)

 W punkcie (16) do BL ladowana jest 3 cyferka hasla a w (17) do EAX offset
 do kodu programu i od punktu (17) do (22) sprawdzane jest czy nie
 zpachowalismy crackmeka (konkretnie czy nie zmienilismy skokow) pod
 offsetami: 0040118B i 0040119B. Ale my tego nie robilismy i przechodzimy
 ten kawalek kodu gladko i docieramy do punktu (23) gdzie jest sprawdzenie
 czy BL (3 cyferka hasla) rowna sie 31h (31h= "1") czyli juz wiemy jaka
 powinna byc 3 cyferka hasla. Wychodzimy z SI i wypisujemy "1"
 na 3 miejcu.
 Potem kilkamy "OK" i docieramy do nastepnego kawalka kodu:

:00401193 B876114000              mov eax, 00401176           (25)
:00401198 F60074                  test byte ptr [eax], 74     (26)
:0040119B 0F84C6000000            je 00401267                 (27)
:004011A1 803DA731400037          cmp byte ptr [004031A7], 37 (28)
:004011A8 0F8CB9000000            jl 00401267                 (29)
:004011AE 803DA731400039          cmp byte ptr [004031A7], 39 (30)
:004011B5 0F8FAC000000            jg 00401267                 (31)

 Zaczynajac od punktu (25) - (27), do EAX ladowany jest offset do kodu
 i tez jest sprawdzane czy nie zpachowalismy crackmeka.
 W punkcie (28) jest sprawdzanie czy 4 cyferka hasla jest "7" jezeli tak
 to skok nie zostanie wykonany i w punkcie (30) tez jest sprawdzanie
 ale czy 4  cyferka hasla jest "9" jezeli nie to skok nie jest wykonany
 i idziemy dalej. A wiec 4 cyferka hasla to "7". Wychodzimy z SI i
 zmieniamy na prawidlowa.
 Potem "OK" i dochodzimy do nastepnej czesci sprawdzania hasla:

:004011BB 33C0                    xor eax, eax                (32)
:004011BD 33D2                    xor edx, edx                (33)
:004011BF 33C9                    xor ecx, ecx                (34)
:004011C1 A0A7314000              mov al, byte ptr [004031A7] (35)
:004011C6 8A15A8314000            mov dl, byte ptr [004031A8] (36)
:004011CC 32C2                    xor al, dl                  (37)
:004011CE 2C15                    sub al, 15                  (38)
:004011D0 86C8                    xchg al, cl                 (39)
:004011D2 67E305                  jcxz 004011DA               (40)
:004011D5 E98D000000              jmp 00401267                (41)

 Od punktu (41) do (43) sa zerowane rejesry. Nastepnie do AL ladowana
 jest 4 cyferka hasla "7" a do DL 5 cyferka sa one xorowane ze soba
 poczym od wyniku xorowania odejmowane jest 15h i w punkcie (48) jest
 zamiana miejscami Al i CL, po wykonaniu tych obliczen w punkcie (49)
 skok wykona sie tylko w tedy, gdy w CX bedzie 00h.
 I tutaj tez trzeba to obliczyc. A zatem wynikiem xorowania musi byc
 15h, gdyz 15-15=00. Obliczymy to sobie w SI:
 ^ - to xorowanie

 ? 15^37 (= 22 " " ")

 I w ten sposob otrzymalismy 5 literke hasla jest nia " " " to co
 znajduje sie pomiedzy dwoma cudzyslowami, czyli cudzyslow ;-)
 Wychodzimy z SI i zmieniamy 5 literke na " .
 Dajemy "OK" i jestesmy w nastepnej czesci crackme:

:004011DA 33D2                    xor edx, edx                  (42)
:004011DC 8A15A9314000            mov dl, byte ptr [004031A9]   (43)
:004011E2 80C25D                  add dl, 5D                    (44)
:004011E5 8D05ED114000            lea eax, dword ptr [004011ED] (45)
:004011EB 3810                    cmp byte ptr [eax], dl        (46)
:004011ED 90                      nop                           (47)
:004011EE 7402                    je 004011F2                   (48)
:004011F0 EB75                    jmp 00401267                  (49)

 W punkcie (43) do DL ladowana jest 6 cyferka hasla.
 Do niej dodawane jest 5D, nastepnie do EAX idzie offset 004011ED do
 instrukcji  NOP (90h). I w punkcie (46) jest sprawdzenie czy w DL
 jest 90h (NOP) jezeli tak to skok z punktu (48) sie wykona i
 przejdziemy dalej. Ufff,  jezeli nadal to czytasz to musze Ci
 napisac, ze jestes wytrwaly ;-). No i jak poprzednim razem obliczymy
 to sobie w SI:

 ? 90-5D  (= 33h "3")

 I mamy juz 6 cyferke hasla. Jest nia "3". Wychodzimy z SI wypisujemy
 trojke i walimy "OK" i przechodzimy do nastepnego punktu:

:004011F2 33C0                    xor eax, eax                 (50)
:004011F4 33C9                    xor ecx, ecx                 (51)
:004011F6 33D2                    xor edx, edx                 (52)
:004011F8 66A1AA314000            mov ax, word ptr [004031AA]  (53)
:004011FE 3225AC314000            xor ah, byte ptr [004031AC]  (54)
:00401204 8AC4                    mov al, ah                   (55)
:00401206 6691                    xchg ax,cx                   (56)
:00401208 67E302                  jcxz 0040120D                (57)
:0040120B EB5A                    jmp 00401267                 (58)

 W punkcie (53) do AX ladowane sa 2 kolejne cyferki hasla (7 i 8).
 Potem sa xorowane z 9 cyferka i ah przechodzi do AL, po czym
 zawartosc AX jest zamieniana z CX. I skok przy CX=00.
 AX wyglada zatem tak:  AH AL
                        32 31
 I aby AH wyniosl po xorowaniu 00 to musi byc xorowany z ta sama
 wartoscia czyli 32h "2" a wiec 9 cyferka jest "2".
 Wychodzimy z SI zmieniamy 9 cyferke i "OK".
 Dochodzimy do momentu:

:0040120D A0AA314000              mov al, byte ptr [004031AA]  (59)
:00401212 3C41                    cmp al, 41                   (60)
:00401214 7C51                    jl 00401267                  (61)
:00401216 3C5A                    cmp al, 5A                   (62)
:00401218 7F4D                    jg 00401267                  (63)

 Do AL 7 cyferka hasla 31h "1" i jest sprawdzenie czy jest to 41 "A"
 jezeli nie to skok, ze zle ... No to wiemy, ze musi to byc "A".
 Wychodzimy z SI wpisujemy "A" i wracamy po nacisnieci "OK".
 Do nastepnego kawalka kodu:

:0040121A 33C0                    xor eax, eax                    (64)
:0040121C 33F6                    xor esi, esi                    (65)
:0040121E 33D2                    xor edx, edx                    (66)
:00401220 3C2D                    cmp al, 2D                      (67)
:00401222 740D                    je 00401231                     (68)
:00401224 8A86A4314000            mov al, byte ptr [esi+004031A4] (69)
:0040122A 46                      inc esi                         (70)
:0040122B 03D6                    add edx, esi                    (71)
:0040122D 03D0                    add edx, eax                    (72)
:0040122F EBEF                    jmp 00401220                    (73)

 I tak, czyszczenie rejestrow potem porownanie czy AL=2D "-", nastepnie
 do AL ladowana jest cyferka hasla, inkrementowane ESI (+1) i
 do EDX dodawana wartosc z ESI (ilosc przeczytanych bajtow) i potem
 do EDX dodawana jest zawartosc EAX (kolejna cyferka hasla).  Ta procka
 liczy sobie sume a jak napotka znak 2D "-" to przeskakuje do kolejnej
 czesci sprawdzania (juz ostatniej ;-P) ). A wiec wpiszmy sobie w kolejne
 jeszcze nie sprawdzane miejsce 10-te znaczek "-" i puscmy proga dalej,
 az dojdziemy do miejsca po wylkonaniu skoku z pod punktu (68):

:00401231 A1AE314000              mov eax, dword ptr [004031AE]   (74)
:00401236 33C2                    xor eax, edx                    (75)
:00401238 3D3D353039              cmp eax, 3930353D               (76)
:0040123D 7528                    jne 00401267                    (77)
:0040123F 8A15AD314000            mov dl, byte ptr [004031AD]     (78)
:00401245 3510353039              xor eax, 39303510               (79)
:0040124A 38C2                    cmp dl, al                      (80)
:0040124C 7519                    jne 00401267                    (81)

 W (74) do EAX ladowane sa ostatnie 4 znaki hasla ("1212").
 Potem sa one xorowane z suma (EDX) obliczona w poprzednim kawalku kodu i
 w punkcie (76) jest sprawdzenie czy wynik xorowania rowna sie 3930353Dh.
 I obliczamy:

 ? 3930353D^EDX (= 39303711h)

 Jako, ze znaczek 11h nie jest takim jak oczekiwalismy tzn.: nie wyglada
 zbyt ladnie i bedzie problem z wklepaniem go z klawiatury to trzeba zrobic
 tak aby suma wyszla troche inna i moze wtedy w wyniku xorowania otrzymamy
 porzadne literki ;-) ACII. Jako, ze suma jest liczona z pierwszych znaczkow
 do napotkania "-" to wlasnie je bedziemy musieli zmienic. Najlepiej, gdy
 zmienimy 8 i 9, gdyz pierwszych sie nie da. Zamienmy je na "ZZ".
 I po dotarciu do punktu (76) obliczmy sobie jakie powinny byc ostatnie 4
 znaki haselka:

 ? 3930353D^EDX (= 39303741h "907A")

 I teraz wyszly nam porzadne literki ;-) a wiec wpisujemy je jako 4 ostatnie
 tylko w odwrotnej kolejnosci (od tylu) i mamy gotowe rozwiazanie,
 ktorym jest:

 5117"3AZZ-A709

 Jeszcze innym jest 5117"3AAA-w709
 Sa jeszcze inne, jak bedziesz chcial to sam je znajdziesz.

 Jak czegos nie zrozumiales to napisz do mnie.

\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

Greets: AntonOne i ofcoz Zenek Jajko
e-mail: haxmen@poczta.onet.pl

 -haxmen-