    
                                   FFFFFFFFFFFF
     HTTP://WWW.UNDERGROUND.ORG.PL FFFFFFFFFF
       -----------------------     FFFFFFFFFFF
            C  R  A  C  K          FFFFFFFFFFFF
       ---------> 2 <---------     FFFFFFFFFFF
    FF
                                      Napisa: mNICH
                                      Data : 20.10.1998
                                      Miejsce: Bielsko-Biala

Yo! Oto moje drugie faq na temat Crackingu ;)
Tym razem zlamiemy zabezpieczenie w malutkim programiku pod
wiele mowiaca nazwa - "Crackme" (ver 1) napisanym przez Cruehead/MiB
Jesli pliczek nie jest dolaczony do faq to szukac na stronie 
domowej MiB - server.kibla.org/lusers/mib/
Programik ma dosc proste zabezpieczenie nazwa/kod czyli
kod jest kalkulowany na podstawie nazwy ;).
Podstawy opisalem w czesci pierwszej wiec nie ma po co pisac
tego drugi raz. Chociaz i tak jest to napisane najprosciej jak
umialem ;).

Co bedzie potrzebne :
tylko SoftICE dla W95 no i Crackme v1.0 ;)
przyda sie tez kartka i olowek.

Jesli: 
chcesz zadac pytanie/przeslac kase/masz jakies sugestie/
jestes szefem browaru/firmy computerowej to pisz na adres :
tomroy@kki.net.pl lub
tomroy@polbox.com lub
tomroy@friko6.onet.pl ;)

No wiec zaczynamy ;)

----------------------------------------------------------------------------
Na poczatek : przypuszczam ze zainstalowales S-ice'a (SoftICE).
Znasz ASM-a (hmmm...tego to chyba z tekstu nie mozna wywnioskowac ;))  ).
Masz jakiekolwiek pojecie (i tego tez nie ;) ).

1. Uruchamiamy Crackme.exe wchodzimy Help|Register wpisujemy
   dowolna NAZWE ponizej dowolny SERIAL   
   np. ja wypelnilem te pola tak : "tomroy" i "1234567"

2. Wchodzimy do s-ice wciskajac Ctrl+D (mozna ta kombinacje zmienic)
   ustawiamy Breakpoint na GetDlgItemTextA
   
         bpx getdlgitemtexta
   
   wychodzimy z s-ice naciskajac Ctrl+d lub F5 lub komenda x
   klikamy OK, teraz s-ice powinien sie pokazac.

3. UWAGA! - przerwanie zostalo spowodowane pierwszym polem tekstowym
   czyli pobraniem do pamieci NAZWY ("tomroy") nie SERIALA !
   naciskamy F11 aby wrocic do programu (poniewaz aktualnie jestesmy w miejscu
   skad zostala wywolana funkcja GetDlgItemTextA) - zobaczmy teraz 
   kilka pol wyzej od miejsca gdzie jestesmy - okno kodu przesuwamy
   Ctrl+'strzalka w gore' albo myszka (po prawej stronie jest przewijanie).
   
         PUSH       0B                         // nie wazne
         PUSH       0040218E                   // WAZNE !!!
         PUSH       000003E8                   // nie wazne
         PUSH       DWORD PTR [EBP+08]         // nie wazne
         CALL       USER32!GetDlgItemTextA     // miejsce wywolania funkcji
   
   Jestesmy teraz na jednej instrukcji ponizej wywolania funkcji.
   Co to jest stos to chyba wszyscy wiemy ;).
   wszystkie argumenty PUSH-y (ze tak powiem ;) ) sa argumentami wywolania
   GetDlgItemTextA. "Tlumaczac" to na C++ wyglada to tak :
   int GetDlgItemTextA(int dialoghandle,int controlid,char *buffer,int maxlen);
                       | DWORD PT...  | |  000003E8 | | 0040218E | |   0B   |
   Interesuje nas 3 argument czyli wskaznik do jakiegos lancucha znakow.
   Ten 3 argument to PUSH  0040218E !! Oczywiscie nie musisz pamietac
   ktory to PUSH wystarczy ze sobie wpiszesz
         
         d 0B                //nic
         d 0040218E          //Wow! nasza NAZWA !
         .......             //dalej nie musisz sprawdzac ;)
   
   UWAGA ! jest jeszcze takie cos : jesli nie jestes pewien
   w jakim miejscu w pamieci jest aktualnie nasz SERIAL lub NAZWA
   mozemy to sprawdzic tak:

         s 0 L FFFFFFFFFF "3459310"

   Ta komenda szuka w pamieci komorki z dana wartoscia ("3459310").
   0 to poczatkowy adres , L nie ma specjalnego znaczenia ale
   trzeba wpisac ;) , FFFFFFFFFF to koncowy adres (czyli przeszukiwannie
   od 0 do FFFFFFFFFF) , "3459310" to wartosc ktorej szukamy - ale
   uwazaj jesli twoj SERIAL jest np. taki "1234567" to S-ice
   prawdopodobnie znajdzie kilka/kilkanascie/kilkadziesiat/kil...
   miejsc w pamieci gdzie zawarta jest ta wartosc !!! wiec aby
   znalezc ta wlasciwa daj jakis "egzotyczny" SERIAL np. taki
   jaki dalem w przykladzie do komendy <s>. 

   Teraz za kazdym razem gdy program bedzie chcial pobrac
   nasza NAZWE odwola sie do komorki pamieci o adresie 0040218E !!
   Zapisujemy sobie adres tej komorki na kartce: nazwa - 0040218E
   
4. Teraz naciskamy F5 (aby wyjsc s s-ice i pozwolic programowi aby
   sie dalej wykonywal), pamietamy ze mamy ustawiony breakpoint 
   na GetDlgItemTextA i to ze program juz wczytal NAZWE. No wiec
   wychodzimy i ... znowu jestesmy w s-ice, teraz przerwanie spowodowal
   SERIAL (nie NAZWA). Postepujemy tak samo jak przy NAZWIE - 
   a) F11
   b) Przechodzimy (Ctrl+strz. w gore) kilka linii w gore ... znowu
      te PUSH-e ;) ...
         
         PUSH    0B 
         PUSH    0040217E
         PUSH    000003E9
         PUSH    DWORD PTR [EBP+08]
         CALL    USER32!GetDlgItemTextA

      sprawdzamy co sie kryje za argumentem (to jest adres) 
      drugiego PUSH-a czyli:
         
         d 0040217E

      wow! nasz SERIAL ;)
           
   c) zapisujemy sobie adres SERIALA na kartce 
      argument drugiego PUSH-a (jesli nie pamietasz ktory to
      komenda <d>): SERIAL - 0040217E

5. No, mamy teraz dwa adresy (zapisane na kartce) gdzie przechowywane
   sa nasze dane: NAZWA i SERIAL. Ustawmy sobie dwa breakpointy na odwolaniu
   do pamieci - komenda <bpm> : 
         
	 bpm 0040218E       //nazwa
         bpm 0040217E       //serial

   Teraz za kazdym razem gdy program bedzie chcial cos zrobic z naszymi
   danymi to siegnie do powyzszych adresow, a wtedy s-ice sie pojawi ;).
   Mozemy juz wylaczyc breakpoint na funkcji GetDlgItemTextA :
         
         bd 0

   Nie usuwamy go komenda <bc> bo gdy sie pomylimy podczas sledzenia kodu
   i bedziemy musieli od nowa wszystko robic to mozemy go 
   wtedy latwo wlaczyc komenda <be>.
   Zobaczmy teraz jakie mamy breakpointy komenda <bl>:
   
         bl
   
   Powinno nam sie pojawic takie cos:

         00) * BPX USER32!GetDlgItemTextA
         01)   BPMB #0030:0040218E RW DR2
         02)   BPMB #0030:0040217E RW DR2
    
   Tam gdzie gwiazdka to breakpoint wylaczony (nie usuniety!)

6. Wiemy juz jak mamy ustawione te breakpointy.
   Teraz pozwalamy programikowi wykonywac sie (Ctrl+d lub F5) 
   Dlugo sie na robi, bo oto znow jestesmy w s-ice.
   Patrzymy do okna komend (tam gdzie wpisujemy komendy):
   
         Break due to BPMB #0030:0040218E RW DR2

   Czyli - patrzymy na kartke z adresami - 0040218E - to przeciez
   nasza NAZWA ! acha... wiec teraz program pobral nasza NAZWE
   i bedzie cos z nia robil ! 

7. Zobaczmy teraz gdzie sie znalezlismy :

         0137:00401383  MOV      AL,[ESI]       (1)  <------|-|
         0137:00401385  TEST     AL,AL          (2)         | |
         0137:00401387  JZ       0040139C       (3)         | |
         0137:00401389  CMP      AL,41          (4)         | |
         0137:0040138B  JB       004013AC       (5)         | |
         0137:0040138D  CMP      AL,5A          (6)         | |- petle
         0137:0040138F  JAE      00401394       (7)         | |
         0137:00401391  INC      ESI            (8)         | |
         0137:00401392  JMP      00401383       (9)  <------| |
         0137:00401394  CALL     004013D2       (10)          |
         0137:00401399  INC      ESI            (11)          |
         0137:00401391  JMP      00401383       (12) <--------|
                  
   Liczba przed dwukropkiem (0137 - segment) moze byc inna na twoim
   komputerze!
   Jestesmy w linijce (2), program odwolal sie do naszej NAZWY
   w linijce ponad ta na ktorej jestesmy, czyli w linii nr. (1).
   instrukcja (1) "wklada" bajt wskazywany przez [ESI] do nizszej
   polowki rejestru AX czyli AL. Uwaga! przypomnienie : to co
   sie znajduje w AL znajduje sie takze w AX czy EAX !!! 
   Zobaczmy wiec co kryje sie pod ESI ?
         
         d esi
    
   spojzcie na okno danych - co widzimy ? - nasza NAZWE ! ... tzn. ze 
   w ESI jest adres naszej NAZWY !
   Spojzmy na powyzszy kawalek kodu jeszcze raz tyle ze calosciowo.
   Mozna latwo zobaczyc ze jest to najzwyklejsza petla!
   Zanim dalej bedziecie czytac sprobojcie sami zorientowac sie
   co jest robione przy kazdym obiegu petli ??????
   ........
   ........
   No wiec wiecie ? ... dla tych co jeszcze nie wiedza :
   Linijka (2) sprawdza czy w rejestrze AL jest wartosc (w AL jest wartosc
   kolejnego znaku w naszej NAZWIE - pamietamy ze adres naszej NAZWY jest
   w ESI - a jak widac przy kazdym obiegu petli wartosc ESI jest 
   inkrementowana ( ESI:=ESI+1 ) czyli co kazdy obieg w AL jest wartosc 
   kolejnego znaku!) wieksza od 0 (od NULL)        
   Jezeli jest NULL (to znaczy koniec stringu - naszej NAZWY) petla jest 
   konczona i wykonywana jest nastepna instrukcja za petla.
   Koniec petli powoduje skok za petle czyli linijka (3) (JZ-skok jesli zero).
   No a teraz zobaczmy na instrukcje (4) ... dlaczego rejestr AL jest
   porownywany z wartoscia 41 ??? heh... zobaczcie na tablice kodow ASCII
   co to jest 41 ??? ... jest to kod hexadecymalny litery 'A' ! ... czyli
   kazdy znak jest porownywany z litera 'A'... jezeli znak (wartosc hex)
   jest mniejszy od 'A' czyli znak jest jakas cyfra albo znaczkiem (nie
   litera!) programik skacze (5) (JB - skok jesli ponizej) pod adres
   004013AC ... zobaczmy co jest pod tym adresem - jest tam kilka 
   PUSH-y i CALL jesli przejdziemy przez ten CALL (F10) to program
   sie konczy i program wyswietla komunikat ze wprowadzilismy 
   zle haslo !. Jaki z tego wniosek ? - kazdy znak musi byc litera! 
   (no... kazdym znakiem "wiekszym" od 'A' ;) ).
   No dobra co dalej ? ... patrzymy na linijke (6) ... ooo! znowu
   AL jest porownywane z jakas wartoscia - 5A ... znowu zerkamy
   do tablicy ASCII - co to jest 5A ? ... To jest 'Z' !
   Co tu jest robione ? - porownywane jest AL z 5A i jesli wieksze
   to skok (7) (JAE - skok gdy powyzej lub rowne) do 00401394 ...
   mozemy przyjac ze skok nastapi gdy znak jest mala litera !!!
   skok jest do linijki (10). Za chwilke przeanalizujemy ten CALL.
   Ale teraz jeszcze co gdy warunek nie jest spelniony - 
   czyli znak jest duza litera. 
   jezeli nie spelniony to program przechodzi do linijki (8)
   co tu jest robione ? -
   ESI jest inkrementowane, czyli powiekszone o 1 (ESI:=ESI+1)
   tzn. ze ESI pokazuje teraz na kolejny znak w naszej NAZWIE !!!.
   W linijce (9) nastepuje skok do poczatku petli - i wszystko od nowa ;).
   A teraz co sie dzieje jesli warunek w (7) jest spelniony 
   (czyli gdy aktualnie analizowany znak w NAZWIE jest mala litera) 
   i nastepuje
   skok do (10) czyli do CALL-a.
   Aby to zrozumiec musimy wejsc do wnetrza tej funkcji (wywolanej CALL-em).
   Naciskamy pare razy F10 az podswietli nam sie linia z CALL-em (10).
   Teraz naciskamy F8 ... i jestesmy wewnatrz funkcji !
   
         RET                      //nie wazne
         SUB        AL,20         (13)
         MOV        [ESI],AL      (14)
         RET                      (15)

   Powinienes sie domyslic co tu sie dzieje! ...
   no wiec tak : od wartosci rejestru AL odejmowana jest wartosc 20 -
   linijka (13) po co ??? ... przypuscmy ze aktualnie 
   analizowany znak (w AL) to 'k' (jeden ze znakow w twojej NAZWIE), 
   co sie stanie jesli od 'k' ('k'= 6B) odejmiemy 20 
   (oczywiscie 20h tzn. 20 hexadecymalnie) - 6B-20=4B a 4B='K' , 
   nastepnie wartosc w AL (linijka (14)) jest podstawiana do [ESI], czyli 
   oryginalna wartosc tam zapisana zostaje zamieniona
   wartoscia 'K' , a co bylo przedtem w [ESI] ??? ... oczywiscie
   'k' ... wiec to co robi ta funkcja to zamienia wszystkie male litery 
   w naszej NAZWIE na duze !!!
   No i (15) to wyjscie z funkcji i powrot do miejsca z kad zostala wywolana.
   Po wyjsciu z funkcji jestesmy w linii (11), czyli instrukcja INC ESI -
   oczywiscie inkrementuje ona ESI (ESI:=ESI+1) teraz ESI pokazuje, 
   na nastepny znak w naszej NAZWIE. 
   no i (12) to skok znowu do poczatku petli. Petla jest dotad powtarzana
   dopoki ESI nie pokazuje na NULL, wiec jesli wartoscia komorki o adresie
   ESI jest NULL (koniec stringu - naszej NAZWY) petla zostaje przerwana
   i przenosimy sie do 0040139C (JZ 0040139C).
   I tyle tlumaczenia z powodu jednej krotkiej operacji na stringu,
   tzn. zamienienia kazdej litery w NAZWIE z malej na duza ;).
   Uffff ! ale namieszalem ;) ... ale mam nadzieje ze zrozumiales ...
   jesli nie to sie nie przejmuj tylko przeczytaj powoli jeszcze raz ;). 
   Ta operacja jest czesto wykorzystywana w zabezpieczeniach typu 
   nazwa-kod.

7. No wiec jestesmy teraz przy 0040139C.
   Zobaczmy co my tu mamy:
       
         POP     ESI
         CALL    004013C2
            
   Pierwsza instrukcja sciaga ze stosu jakas wartosc i wklada ja do
   ESI ... po co? ... zobacz
   jaka jest instrukcja zaraz przed nasza dlugo analizowana petla
   powiekszajaca litery - PUSH ESI - wiec teraz jest - POP ESI -
   wiec sciagamy ze stosu adres naszej NAZWY ! 
   Zaraz potem jest wywolywana funkcja 004013C2 - musimy
   zagladnac do jej wnetrza :

         0137:004013C1  RET                      //nie wazne
         0137:004013C2  XOR     EDI,EDI          (16) 
         0137:004013C4  XOR     EBX,EBX          (17)
         0137:004013C6  MOV     BL,[ESI]         (18) <---|
         0137:004013C8  TEST    BL,BL            (19)     |
         0137:004013CA  JZ      004013D1         (20)     |- petla
         0137:004013CC  ADD     EDI,EBX          (21)     |
         0137:004013CE  INC     ESI              (22)     |
         0137:004013CF  JMP     004013C6         (23) <---|
         0137:004013D1  RET                      (24)

   hmmm... moze teraz odgadles co robi ta funkcja ;) ??? ... jak nie
   to ja teraz przeanalizujemy.
   Najpierw instrukcje (16) i (17) heh... powinienes wiedziec co
   one robia ;). XOR jest bardzo czesto stosowana instrukcja przy
   roznych zabezpieczeniach !!!. Jest to tzw. wykluczajaca sie alternatywa
   ... nie przerazaj sie nazwa ;) ... o co tu chodzi ? ... to jest tak :
   porownywane sa bity z pierwszego operandu i drugiego jesli sa przeciwne
   (1 i 0) to w wyniku bit ma wartosc 1, w przeciwnym przypadku ma 0.
   Wynik zapisywany jest w operandzie pierwszym !
   oto tabelka ktora pamietamy z matmy:

         a | b |  c
         ==========
         1 | 1 |  0
         0 | 1 |  1
         1 | 0 |  1
         0 | 0 |  0 

   No dobra ale mogles pomyslec po co sa porownywane te same rejestry ???
   Odp. : w wyniku tych dwoch instrukcji zerowane sa rejestry EDI i EBX
   dlaczego? pomysl ... poniewaz gdy XOR-owane sa dwa te same rejestry,
   to maja one w sobie wartosci z takim samym rozstawieniem bitow !
   wiec nigdy zaden wynik XOR-owania bitow nie bedzie mial wartosci 1 !!!
   i w rezultacie EDI i EBX zostana wyzerowane !!!   
   Nastepna jest linijka (18), co robi?
   wklada do BL wartosc wskazywana w ESI ... a co my mamy w ESI ???
   pamietasz ze zaraz przed wywolaniem funkcji w ktorej teraz jestesmy
   program sciagnal ze stosu wartosc i wlozyl ja do ESI ! na a co
   bylo z kolei na stosie ??? - byl tam wskaznik do stringu z nasza
   NAZWA !. Z tego wniosek - co robi instrukcja? - bierze pierwszy
   znak z naszej NAZWY i wklada go do dolnej polowki rejestru EBX
   czyli BL !. Linijka (19) - Tutaj sprawdzane jest czy w BL jest
   jakas wartosc rozna od 0 (od NULL), jezeli nie ma to znaczy ze
   jest to koniec naszej NAZWY (kazdy string konczy sie znakiem NULL !!!)
   - nastepuje skok (JZ-skok jesli rowne 0) (linijka (20)) 
   do (24), a jest to powrot do miejsca wywolania funkcji (RET). 
   Natomiast gdy wartosc w BL jest rozna od zera to nie nastapi
   skok ! - zostanie wykonana instrukcja (21), a teraz co ona robi :
   Jak pamietamy EDI i EBX zostaly wyzerowane ... teraz przy kazdym
   obiegu petli do BL (dolna czesc EBX) zaladowana zostaje wartosc 
   kolejnego znaku z naszej NAZWY. Zmierzam do tego iz, przy
   kazdym obiegu petli do wartosci trzymanej w EDI zostaje dodana
   wartosc kolejnego znaku z naszej NAZWY !!! w linijce (22) inkrementowane
   jest ESI (wskaznik przestawiany jest na nastepny znak), no i przez
   linijke (23) petla przebiega znowu ;).    
   Gdy przejdziemy przez cala NAZWE to wykonywana jest instrukcja (24)
   i powrot do miejsca wywolania funkcji. Co jest efektem calej 
   tej funkcji ??? ... to ze teraz w EDI siedzi suma wszystkich
   znakow (ich wartosci hexadecymalnych) naszej NAZWY !!!!!
   SHIT !!! znowu niezle namieszalem ... niestety nie jestem uzdolniony
   polonistycznie ... SORRY ! ;))

8. Po tej funkcji ktora omowilem powyzej sa te oto instrukcje :
         
         XOR     EDI,00005678        (25)
         MOV     EAX,EDI             (26)
 
   No a co jest teraz robione ??? ...
   Jak pamietamy w EDI siedzi suma wszystkich znakow naszej NAZWY
   (juz po powiekszeniu wszystkich liter !!!), teraz ta suma
   jest XOR-owana z wartoscia 00005678 w linijce (25), nastepnie
   ta zXOR-owana wartosc idzie do EAX - linijka (26). 
   np. dla mojej NAZWY "tomroy", sa takie wartosci : 
   suma liter ("tomroy" zostal oczywiscie zamieniony na "TOMROY" !!!)
   to : 000001EA natomiast po zXOR-owaniu z 00005678 w EAX mam
   cos takiego : 00005792 (u ciebie zobacz w lewym gornym rogu - w oknie
   rejestrow - na wartosc rejestru EAX (cos takiego - EAX=xxxxxxxx))
   |------------------------------------------------------------------|
   |teraz zapisz sobie ta wartosc na kartce (ta po zXOR-owaniu) !!!!! |
   |------------------------------------------------------------------|
9. Tym sposobem przeszlismy przez czesc programu gdzie odbywa
   sie manipulacja na NAZWIE (nie na KODZIE) heh... mysleliscie
   ze to koniec ??? ooo ... to musze was rozczarowac ;))     

10.Naciskamy teraz F5 lub Ctrl+d ... znowu pojawil sie s-ice
   w oknie komend widzimy co spowodowalo przerwanie wykonywania programu :
              
         Break due to BPMB #0030:0040217E RW DR2

   Zerknijmy na nasza kartke z adresami : adres 0040217E to
   adres w pamieci gdzie przechowywany jest nasz SERIAL !
   Jak chcesz mozemy sprawdzic:
         
         d 0040217E

   Oczywiscie w oknie danych otrzymamy nasz SERIAL ! 
   No dobra przechodzimy teraz do kolejnej analizy kodu .... hmmmm
   zobaczmy gdzie sie teraz znalezlismy (UWAGA ! musimy sobie
   uzmyslowic ze jestesmy teraz WEWNATRZ jakiejs funkcji !!!
   wskazuje na to instrukcja RET kilka/kilkanascie linijek nizej -
   bedzie nam to potrzebne do pozniejszej analizy !!! - wiec
   to sobie zapamietaj !!!):
         
         0137:004013E2  MOV     AL,0A        <----|
         0137:004013E4  MOV     BL,[ESI]          |
         0137:004013E6  TEST    BL,BL             |
         0137:004013E8  JZ      004013F5          |
         0137:004013EA  SUB     BL,30             |- petla
         0137:004013ED  IMUL    EDI,EAX           |
         0137:004013F0  ADD     EDI,EBX           |
         0137:004013F2  INC     ESI               |
         0137:004013F3  JMP     004013E2     <----|

   No, a teraz powiem wam tylko ze powyzszy kawalek kodu
   zamienia nasz SERIAL z liczby dziesietnej np. moj "1234567"
   na hexadecymalna (szesnastkowa) - w moim przypadku - "0012D687"
   I wynik umieszcza w EDI ! ale wiecej wam nie powiem i SAMI
   musicie dojsc do tego jak to jest robione ... nie bede
   przeciez podawal wam wszystkiego na tacy !!! ;)).

11.To wy sie zastanawiajcie nad powyzszym kodem ... a ja
   przejde no nastepnych instrukcji :

         XOR    EDI,00001234      (27)
         MOV    EBX,EDI           (28)

   Heh ... co my tu mamy ? ... w linijce (27) mamy XOR-owanie ...
   ale czego z czym ??? ... tak, tak, zgadles ! ... w EDI mamy
   przeciez wartosc hexadecymalna naszego SERIALA , a wiec
   ta wartosc jest XOR-owana z taka smieszna liczba jak 00001234,
   i wynik umieszczany jest z powrotem w EDI !!! No a w linijce
   (28) widzimy dobrze nam znana instrukcje MOV, co ona robi ? ...
   jak sie juz pewnie domysliles przenosi (kopiuje) nasz 
   zhexadecymalizowany (ze tak powiem ;) ) i zXOR-owany SERIAL
   do rejestru EBX !!! Dla mojego SERIALA ("1234567") aktualna
   wartosc w rejestrze EBX (i EDI) to 012C4B3 !!!    
   
12.przechodzimy pare linijek dalej (F10) (UWAGA! przeszlismy
   przez instrukcje RET tzn. ze wyszlismy wlasnie z funkcji !!!)
   az do ujzenia ponizszego
   kodu :
         
         POP     EAX            (29)
         CMP     EAX,EBX        (30)
         JZ      0040124C       (31)
         CALL    00401362       (32)

   Eh ... tym razem nie zostawie was na lodzie i razem 
   przeanalizujemy powyzszy kod ;). No wiec tak ...
   w linijce (29) jest instrukcja sciagajaca COS ze stosu
   i wkladajaca TO do EAX ... no tak, ale co my mamy na stosie ???
   odp. i teraz wlasnie ma znaczenie to ze bylismy przed chwila 
   w funkcji - nie widzielismy tam zadnych PUSH-y !!! ... 
   Zobaczmy na chwile na linijki powyzej linii (29) :

         PUSH     EAX           (a1)
         PUSH     0040217E      (a2)
         CALL     004013D8      (a3)
         ADD      ESP,04        (a4)

   Od razu powiem ze instrukcja (a3) to wlasnie wywolanie 
   tej funkcji o ktorej ostatnio tak duzo mowie !!!
   w linijce (a1), to co jest w rejestrze EAX jest wkladane
   na stos ... a teraz wazne pytanie co my do cholery mamy
   w tym EAX ??? Odp. pamietasz jak kazalem Ci zapisac
   na kartce wynik kilku operacji na naszej NAZWIE (np. dla
   mnie to bylo : 00005792) ??? to wlasnie siedzi w EAX (przed
   wywolaniem funkcji (a3)) ... heh ... a wiec wartosc EAX nie
   zmienila sie od czasu ostatniej operacji na NAZWIE ! 
   Bo chyba widzisz ze w tej funkcji ktora kazalem
   Ci samemu przeanalizowac jest jakas operacja zwiazana z EAX.
   Ta funkcja to oczywiscie (a3) (jej adres to argument CALL-a).
   A wiec wiemy ze w linijce (a1) na stos jest kladziony wynik
   operacji na naszej nazwie (00005792) !!! a teraz co w linijce
   (a2) ??? - no pewnie wiesz czego to jest adres (argument PUSH-a)?
   jesli jeszcze nie to zobacz na kartke ... albo sprawdz :

         d ds:0040217E

   (DS-data segment) nie musielismy pisac "ds:" ale dla pewnosci
   lepiej napisac ;). Heh ... no i co wam wyszlo ... oczywiscie
   nasz SERIAL ! Jak teraz wyglada stos ??

         |--------------------------|
         |        nasz SERIAL       | //1234567
         |--------------------------|
         | wynik operacji na NAZWIE | //00005792
         |--------------------------|

   Z tego wynika ze na samej gorze stosu znajduje sie nasz SERIAL !!!
   No potem wywolanie funkcji (a3) (ta ktora kazalem Ci przeanalizowac) -
   to juz znamy ;). A teraz co jest robione w (a4) ???
   Chyba wiemy ze ESP (stack pointer) to wskaznik stosu ! 
   przed instrukcja (a4)
   ESP pokazuje na poczatek stosu (nasz SERIAL) ale po dodaniu
   do niego 04, na co pokazuje ??? ... oczywiscie na wynik 
   operacji na NAZWIE (dla mnie - 00005792) !!!
   OK. rozumiesz ? ... to przechodzimy dalej.

   Przechodzimy z powrotem do analizy linijek (29)(30)(31)i(32) :
   w linijce (29) jest sciagana wartosc
   ze stosu i wkladana do EAX... teraz juz wiemy co sciagamy -
   jest to koncowy wynik operacji na NAZWIE (00005792) 
   bo przeciez program przestawil ESP !!!
   Natomiast linijka (30) to jakies porownanie ... ale czego
   z czym ? ... juz wiemy co mamy w EAX ... a co w EBX ??? -
   Zobacz na linijke (28) !!! A wiec w EBX mamy koncowy
   wynik wszystkich operacji na SERIALU ! ...
   podsumujmy - W rejestrze EAX mamy koncowy wynik wszystkich
   operacji na NAZWIE, a w EBX mamy tez koncowy wynik tyle ze
   na SERIALU, te dwie wartosci sa porownywane (30) i 
   jesli sa rowne to nastepuje skok (31) (JZ-skok jesli zero, instrukcja 
   CMP ustawia flage (bit - 1) Z, jesli argumenty sa rowne!) w
   przeciwnym wypadku wykonywany jest CALL (32) ... powiedzmy
   najpierw co robi ta funkcja kryjaca sie pod CALL-em - wypisuje
   ona informacje ze wprowadziles zly SERIAL !!! hmmm ... zastanowmy
   sie jak obejsc ten CALL .... hehe to proste wystarczy zamienic
   JZ 0040124C na JNZ 0040124C albo cos podobnego ... ale nie
   o to tu chodzi, poniewaz autor zastrzegl ze patche nie
   sa dozwolone !!! wiec musimy odgadnac prawidlowy SERIAL
   na podstawie naszej NAZWY, nie mozemy zmieniac kodu programu ;).
   
   Jezeli EBX jest rowne EAX to
   wprowadzilismy poprawny kod !!! Tzn. ze jezeli nasz SERIAL
   po zamienieniu go na liczbe haxadecymalna i zXOR-owaniu go
   z 00001234 - jest rowny - sumie wszystkich liter naszej NAZWY po 
   przeksztalceniu kazdej litery z malej na wielka, a potem 
   zXOR-owaniu tej sumy z liczba 00005678 - to wprowadzilismy
   poprawny SERIAL !!!!!! hmmm.... to zastanowmy sie taraz
   jak wyliczyc ten prawidlowy SERIAL - do tego musze przypomniec
   jak dziala XOR : UWAGA! teraz uwazac ... XOR jest czesto
   stosowany przez programistow do oprogramowania zabezpieczen
   w programach, poniewaz cechuje go tzw. odwrotnosc tzn.
   jezeli :     
         
         a XOR b = c   np.     a= 10011101
                               b= 10110000
                                  --------
                               c= 00101101

   to wedlug tabeli prawdy (podalem ja wczesniej) :

         c XOR b = a           c= 00101101
                               b= 10110000
                                  --------
                               a= 10011101
 
         c XOR a = b           c= 00101101
                               a= 10011101
                                  --------
                               b= 10110000

   Jest to BARDZO wazna zaleznosc !!!
   
13.Teraz juz latwo wykalkulujemy nasz (prawidlowy) SERIAL !
   Pomysl ! co musisz teraz zrobic aby otrzymac ten upragniony
   SERIAL ??? ... heh ... prawidlowym SERIALEM jest ten ktory
   po zamienieniu na liczbe hexadecymalna i zXOR-owaniu jej
   z 00001234 da nam wynik koncowej operacji na naszej NAZWIE
   (dla mnie - dla "tomroy" - 00005792) !!! czyli pamietajac
   ze instrukcje XOR cechuje odwrotnosc, SERIAL mozemy
   obliczyc tak: hmmm...jak by to wyjasnic - Poprostu Musimy 
   !----------------------------------------------------------------!
   !Odwrocic operacje ktore zostaly wykonane na naszym SERIALU,     !
   !(tylko teraz SERIALEM prawidlowym jest 00005792 - a dokladniej  !
   !mowiac jest to jakby wartosc prawidlowego                       !
   !SERIALA po wykonaniu na nim operacji                            !
   !przeksztalcenia na liczbe HEXadecymalna i zXORowaniu z 00001234)!
   !czyli najpierw odXOR-owac (wartosc 00005792) z 00001234,        !
   !otrzymamy hexadecymalna                                         !
   !reprezentacje prawidlowego kodu, a potem zwyczajnie zamienic    !
   !wynik ktory otrzymalismy na jego decymalna (dziesietna)         !
   !reprezentacje !!!!!!!!!!!                                       !
   !----------------------------------------------------------------!
   XOR-ujemy otrzymana wartosc operacji na NAZWIE
   (00005792) (EAX) z wartoscia ktora zostala zXOR-owana z
   hexadecymalna reprezentacja naszego SERIALA, czyli 00001234 !!!
   W S-ice robimy to tak :

         ? 00005792 ^ 00001234

   Znaczek ^ oznacza XOR-owanie.
   ? - ta komenda jest uzywana do roznych celow (jest dosc przydatna)
   Oczywiscie zamiast mojej wartosci - 00005792 wpisz swoja 
   (Ta co Ci kazalem bezwzglednie zapisac na kartce, nawet
   ujalem ja w ramke, ale praktycznie to mozesz ja teraz zobaczyc
   w oknie rejestrow pod rejestrem EAX=xxxxxxxx)
   hmmm... co otrzymalismy (w oknie komend) ??? - takie cos :
   
         000045A6  0000017830  "E~"
            HEX        DEC     ASCII

   Ale co nam to dalo ? ... Tam gdzie jest pod spodem HEX, to
   jest prawidlowy SERIAL w postaci hexadecymalnej !!! teraz
   powinnismy zamienic ta wartosc na dziesietna ale ...
   S-ice zrobil juz to za nas !!! i tam gdzie mamy pod
   spodem DEC to jest POPRAWNY SERIAL - Dla mnie :

          |------------|
          | 0000017830 |
          |------------|

   HURRA !!! ... mamy nasz upragniony SERIAL, teraz mozemy
   opuscic zera (te 5 na poczatku), zapisac go na kartce,
   wyjsc z S-ice (przedtem wylaczyc wszystkie Breakpointy),
   i wpisac do pola z NAZWA - nasza NAZWE no i nasz SERIAL
   wykalkulowany na podstawie NAZWY, czyli dla mnie :
   
          tomroy i 17830

   Klikamy OK ... i otrzymamy komunikat "Great work mate!" 
   (Swietna robota !!!) ;)) ....
   hehe tzn. ze wreszcie dobrnelismy do konca ;)))))))))
   Mozecie taraz isc na Pivo i oblac swoj pierwszy
   zlamany program ;)). 

Podsumowanie :

   hmmm ... jakby sie teraz na to wszystko papatrzec to
   wyglada to strasznie skomplikowanie - ale to jest
   naprawde bardzo proste ... zlamanie tego programiku
   zajelo mi okolo 15-20 min. - Wam jak macie opis to
   wystarczy 3-4 min ;).
   Co? ... Jeszcze nie jestescie przekonani, ze to bardzo proste ???
   to zrobmy krotkie podsumowanie z planem :

   1. Uruchamimy Crackme wpisujemy NAZWE i SERIAL
   2. Wchodzimy do S-ice (Ctrl+d)
   2. Ustawiamy breakpoint (bpx) na GetDlgItemTextA
   3. Wychodzimy z S-ice ... OK ... i znowu jestesmy w S-ice
   4. Ustawiamy breakpointy (bpm) na 0040218E i 0040217E 
   5. Naciskamy F5 ... ogladamy kod ... acha, program zamienia
      kazda mala litere w naszej NAZWIE na duza.
   6. Potem widzimy ze program sumuje kazda litere z naszej
      NAZWY (jej hexadecymalny kod i to gdy jest juz duza litera!!!)
   7. Ta suma jest XOR-owana z 00005678
   8. Wynik tego XOR-owania idzie do EAX - ale my i tak 
      zapisujemy ta liczbe na kartce !
   9. Potem nasz SERIAL jest zamieniany na liczbe Haxadecymalna
  10. Ten hexadecymalny SERIAL jest XOR-owany z 00001234
  11. Wynik XOR-owania SERIALA idzie do EBX
  12. Te dwa wyniki (EAX i EBX) sa porownywane, jesli pasuja
      to zanczy ze nasz SERIAL byl prawidlowy
  13. Korzystajac z wlasnosci instrukcji XOR, odXOR-owujemy
      to co jest w EAX z 00001234 i otrzymujemy szesnastkowa
      reprezentacje poprawnego SERIALA, od razu S-ice pokazuje nam
      ta wartosc jako dziesietna i ... otrzymujemy wlasciwy SERIAL !!!

   I co? ... prawda ze proste ;))
   Jesli jeszcze czegos nie kapujesz to znasz moj adres ... mozesz
   zapytac ;).
   Teraz sprobuj sciagnac CrackMe v2.0 (na stronie MiB-a) 
   i sproboj zarejestrowac,
   ma tez bardzo proste zabezpieczenie ... tyle ze nie
   nazwa/kod ale sam numer rejestracyjny, mam nadzieje
   ze nie bedziesz mial zbyt duzo klopotu z tamtym
   zabezpieczeniem ;))  
   POWODZENIA !!!   

----------------------------------------------------------------------------
Linki (UWAGA! wszystkie strony po angielsku!) :

Lord Caligo - cracking.home.ml.org/      Duzy zbior roznych narzedzi
                                         i innego crackerskiego stuffu
                                   
MiB - server.kibla.org/lusers/mib/       Kilka dobrych FAQ i
                                         kilka dobrych programikow Crackme
                                         wraz z rozwiazaniami

+Fravia - fravia.org/      bardzo dobra strona czlonka +HCU
                           bardzo duzo opisow zlaman

ASM tutorials - www.la-online.com/assembly.htm      Duzo faq dotyczacych ASM-a

+Greythorne - home.sol.no/reopsahl/files/assem.htm    ciekawa strona 
                                                      o Crackingu i ASM

Reszte poszukaj - jest troche linkow na powyzszych stronach,
jesli znasz jakas polska strone crackerska, a moze sam zakladasz,
bo przydala by sie strona z najnowszymi narzedziami i dobrym transferem ;). 
oczywiscie Mail me !!!