
           ܲ   ߲      ߲ 
          ܲ     ۲      
                  ۲   
              ۲  ۲       
         ۲    ۲ ܲ  
          ߲   ߲       ߲   
                      -bHd-
                        +o cybult^2oo2


                           Crackme01 by _r00t_^CookieCrK tutorial


        Cel     : Crackme01 by _r00t_^CookieCrK
        Czym    : SI, IDA, opcjonalnie MASM do ponowanej kompilacji crackme
        Opis    : Crackme ma zabezpieczenie typu name/serial, nie jest spakowane, pisane
                  w TASM, autor pozwala obejsc patchem metody anti-si.

        notice: ustaw sobie czcionke terminal 12 przy czytaniu tego tuta

        
        Wczoraj jakos calkiem przypadkowo natknalem sie na to crackme, zapuscilem
        je sobie pod debuggera i zaczalem sledzic. Patrze, pobieranie textu przez
        SendMessageA (WM_GETTEXT), 

                push    offset _name
                push    11              ; wParam==ilosc textu do pobrania z edita
                push    WM_GETTEXT      ; Msg=wiadomosc jaka przesylamy do okna
                push    hWnd            ; hWnd=uchwyt okna z ktorgo pobieramy stringa
                call    SendMessageA

        potem male sprawdzenie dlugosci wprowadzonego nicka, w postaci:

                cmp     eax, 10
                ja      _bad
                cmp     eax, 4
                jb      _bad

        No wiec jak widac dlugosc name musi wynosic od 4-10 znakow. U mnie dla nicka 
        'cybult' eax po prawidlowym wywolaniu SenMessageA powinno wynosic 6. Patrze
        zatem co sie dzieje - cuda nie widy ;), w eax mam 0. Pomyslalem najpierw, ze
        to moze byc jakis anti-bpx albo jakis inny badziew, zapusciclem sie wiec do
        IDY zeby looknac na funkcje, calle, watki itd. ale nie znalazlem niczego co
        mogloby sie z tym wiazac, wiecej.. popatrzylem sobie jak leci obsluga dialogu
        a w szczegolnie WM_COMMAND, wszystko standardowo, 

                cmp     uMsg, WM_COMMAND
                jz      _wmcmmnd

        _wmcmmnd:
                cmp     wParam, 3001
                jz      _check_registration
                cmp     wParam, 3002
                jz      _about

        Tak wiec anti-bpx wykluczony, przejrzalem caly kod crackme i zaczalem sie
        sie smiac ;).. oczywiscie z kogo? z _r00ta_ ;).. sami zreszta popatrzcie,
        zaraz po GetModuleHandleA jest call, co w nim jest.. hmm moze jakies sprytne
        anti-si, o ktorym autor wspomina w about? hehe, nie.. ;)

        start           proc near

                push    0                       ; lpModuleName
                call    GetModuleHandleA

                mov     hInstance, eax

                call    PobierzUchwyty          ; <-- chodzi o to ;)

                push    0                       ; dwInitParam
                push    offset _DialogProc      ; lpDialogFunc
                push    0                       ; hWndParent
                push    67h                     ; lpTemplateName
                push    hInstance               ; hInstance
                call    DialogBoxParamA

                push    0                       ; uExitCode
                call    ExitProcess

        start           endp

        Od tej procedurki startuje program, pobiera hInstance (w sumie i tak nie jest
        to przydatne bo zawsze jesli standardowo kompilujemy proga pod tasmem/masmem
        to znajdzie sie tam wartosc ModuleBase=00400000h, a wiedzac o tym mozna usunac
        tego apisa jak i hInstance z sekcji .data i zawsze gdy zachodzi potrzeba
        wykorzystania hInstance (np. DialogBoxParamA, LoadIconA, etc.) mozna swobodnie
        machnac tam 'push 00400000h' zaoszczedzajac jeden import, ze nie wspomne juz
        o przyspieszeniu dzialania programu o te kilka tysieci :P cykli cpu). Ekm, no
        wiec wracajac do tematu, wchodzimy do tej procedury i widzimy cos takiego:

        PobierzUchwyty  proc

                push    1001                    ; identyfikator edita z nickiem
                push    dword ptr [ebp+8]       ; and what is it??? ;)
                call    GetDlgItem              ; pobierz uchwyt edita

                mov     hEdit1, eax             ; zapisz uchwyt do pozniejszego uzycia

                push    1002                    ; identyfikator edita z serialem nr1
                push    dword ptr [ebp+8]       ; eta szto??? ;)
                call    GetDlgItem              ; pobierz uchwyt edita

                mov     hEdit2, eax             ; j.w.

                push    1003                    ; identyfikator edita z serialem nr2
                push    dword ptr [ebp+8]       ; znowu to samo
                call    GetDlgItem              ; pobierz uchwyt edita

                mov     hEdit3, eax
                ret

        PobierzUchwyty  endp

        Ten kodzik jest "obrobiony" przez IDE, wartosci hex identyfikatorow kontrolek
        zamienilem na dec i looknalem w zasoby aby wiedziec ktora jest ktora. No coz,
        jesli umiesz programowac choc troche pod win32 i wiesz co nieco o APIsach to
        juz wszystko powinno byc zrozumiale. Na wszelki wypadek gdyby cos to machne
        tu rozpiske funkcji GetDlgItem, 

        HWND GetDlgItem(

        HWND hDlg,      // handle of dialog box
        int nIDDlgItem  // identifier of control
        );      

        Parameters

        hDlg
        Identifies the dialog box that contains the control. 

        nIDDlgItem
        Specifies the identifier of the control to be retrieved. 

        Return Values

        If the function succeeds, the return value is the window handle of the given
        control.

        If the function fails, the return value is NULL, indicating an invalid dialog
        box handle or a nonexistent control. 

        Skladnia High Level Language to: "invoke GetDlgItem, hDlg, nIDDlgItem"

        To jest tak proste, ze nie ma o czym mowic. Zwroc uwage na Return Values tej
        funkcji: jesli wszystko pojdzie ok i funkcja znajdzie dana kontrolka na
        danym oknie to w eax otrzymamy uchwyt do zadanego edita, jesli jednak jeden
        z parametrow tej funcji bedzie nieprawidlowy, to uchwytu nie otrzymamy ze
        wzgledu na to, ze Windows nie bedzie potrafil odnalezc tego czego szukamy.
        
        Przypomne jeszcze tylko do czego nam te "uchwyty". Sa one nizbedne jesli sie
        decydujemy na pobieranie textu przez SendMessageA - tam musimy podac uchwyt
        do okna, ktoremu wyslemy wiadomosc WM_GETTEXT. Co innego byloby gdyby text
        byl pobierany za pomoca np. GetDlgItemTextA, SendDlgItemMessageA - te apisy
        samodzielnie pobieraja sobie uchwyt do kontrolki.

        Zatem mamy tu do czynienia z GetDlgItem, problem tylko jest jeden.. skad
        Windows ma wiedziec gdzie jest okno na ktorym szuka tych trzech editow. A no
        parametr hDlg teoretycznie cos tam zawiera, mianowicie dword ptr [ebp+8] :).
        Wow, tylko co to ma byc?? Dword ptr [ebp+8] wzrokowo mowi mi, ze jest to
        globalne hWnd z callbacku DialogProc, 

        BOOL CALLBACK DialogProc(

        HWND hwndDlg,   // handle to dialog box                 ; czyli ebp+8
        UINT uMsg,      // message                              ; czyli ebp+0Ch
        WPARAM wParam,  // first message parameter              ; czyli ebp+10h  
        LPARAM lParam   // second message parameter             ; czyli ebp+14h 
        );

        na pewno sie nie myle, czyli wiemy, ze GetDlgItem nie zwroci zadnego uchwytu
        z tego powodu, ze hDlg jest uzyte poza callback-iem DialogProc, malo tego,
        jest uzyte przed DialogBoxParamA! Teraz co...lookam sobie na xref operands
        w IDA kazdego z uchwytow - moze sa gdzies indziej jeszcze modyfikowane.. nic
        z tego, hEdit1, hEdit2, hEdit3 zawsze beda mialy zerowy dupny uchwyt co nigdy
        nie doprowadzi do pobrania chocby jednego znaku name czy obu seriali.
        
        Wypadaloby mi tutaj zakonczyc opis tego crackme, ma ono celowo zle zakodowane
        pobieranie uchwytow do 3 editow, podejrzewam, ze _r00t_ zrobil to specjalnie
        i dobrze wie, ze tego programu zarejestrowac sie po prostu nie da. Co innego
        to pozwolenie na jakis patch, ale to i tak bez sensu, ja tak to widze..

        W zwiazku z tym, ze i tak normalnie nie uda nam sie uruchomic procedury
        sprawdzajacej wprowadzone dane rejestracyjne, spojrzmy na sucho co czekaloby
        nas gdyby tego calla wwalic do obslugi dialogu, a konkretniej w miejsce gdzie
        crackme realizuje swoje funkcje po otrzymaniu wiadomosci WM_INITDIALOG, zeby
        bylo smieszniej, to zrekomilowalem crackme.. 5 minut roboty ;)

        *********************************************************************************
                                                                                        .
        ; Crackme01 by _r00t_^CookieCrK - dezasemblacja
        ; 
        ; 19/20 lipca 2002
        ;
        ; cybult
        ; cybult@poczta.onet.pl
        ;
        ;
        ;                             MODEL
        ;
        .686
        .mmx
        .model flat, stdcall
        option casemap:none

        ;
        ;                            INCLUDES
        ;

                include \masm32\include\windows.inc
          
                include \masm32\include\advapi32.inc
                include \masm32\include\gdi32.inc
                include \masm32\include\user32.inc
                include \masm32\include\kernel32.inc
                include \masm32\include\comctl32.inc
                include \masm32\include\comdlg32.inc
                include \masm32\include\shell32.inc
                include \masm32\include\imagehlp.inc

                includelib \masm32\lib\imagehlp.lib
                includelib \masm32\lib\kernel32.lib
                includelib \masm32\lib\comctl32.lib
                includelib \masm32\lib\comdlg32.lib
                includelib \masm32\lib\gdi32.lib
                includelib \masm32\lib\user32.lib
                includelib \masm32\lib\shell32.lib
                includelib \masm32\lib\advapi32.lib

                        assume   fs:flat

        ;
        ;                              CONST
        ;
        .const

        ;
        ;                              DATA
        ;
        .data

        lpAboutText     db      '                   Crackme01 by _r00t_^CookieCrK'
                        db      13,10,13,10
                        db      'Patching is allowed only to pass '
                        db      'round ANTI-SI protection.',13,10,13,10
                        db      'Greetz for:',13,10
                        db      9,' CookieCrK',13,10
                        db      9,' #crackpl',13,10,13,10
                        db      '               Check our website for next '
                        db      'challenge :)',0
        lpCaption       db      'Crackme01',0
        lpGoodTxt       db      '      Yp, you did it!',0
        dword_4020F1    dd      0
                        db      4 dup(0)

        hInstance       dd      0
        hEdit1          dd      0
        hEdit2          dd      0
        hEdit3          dd      0
        hObject         dd      0
        _ilosc_serial1  dd      0
        _serial1        db      10 dup(0)
        _serial2        db      10 dup(0)
        _name           db      12 dup(0)
        _wazny_dword    dd      0
                        db      58 dup(0)
                        dd      23355E41h
                        dd      3B506F67h
                        dd      402D5026h
                        db      133 dup(0)
                        ;align 1000h

        ;
        ;                               CODE
        ;
        .code

        start:
                        push    0
                        call    GetModuleHandleA

                        mov     hInstance, eax

                        ;call   _Wez_Uchwyty

                        push    0
                        push    offset _DlgProc
                        push    0
                        push    103
                        push    hInstance
                        call    DialogBoxParamA

                        push    0
                        call    ExitProcess

        ;
        ;                             DIALOG MAIN
        ;
        _DlgProc        proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD

                        push    eax
                        push    ecx
                        push    edx
                        push    ebx
                        push    edi
                        push    esi

                        cmp     uMsg, WM_CLOSE
                        jz      _close
                        cmp     uMsg, WM_INITDIALOG
                        jz      _wm_initdialog
                        cmp     uMsg, WM_COMMAND
                        jz      _wm_command

        _ret:
                        pop     esi
                        pop     edi
                        pop     ebx
                        pop     edx
                        pop     ecx
                        pop     eax
                        ret

        ;
        ;   WM_CLOSE
        ;
        _close:
                        push    hObject
                        call    CloseHandle

                        push    0
                        push    hWnd
                        call    EndDialog

                        push    0
                        call    ExitProcess

        ;
        ; WM_INITDIALOG
        ;
        _wm_initdialog:
                        push    250
                        push    hInstance
                        call    LoadIconA

                        push    eax
                        push    0
                        push    80h
                        push    hWnd
                        call    SendMessageA

                        call    _Wez_Uchwyty                    ; <-- ten call tutaj czuje sie
                                                                ; duzo lepiej niz obok EP ;)
                        jmp     _ret

                        push    0
                        call    ExitProcess

        ;
        ;   WM_COMMAND
        ;
        _wm_command:
                        cmp     wParam, 3001
                        jz      _go
                        cmp     wParam, 3002
                        jz      _about
                        jmp     _ret

        ;
        ;       GO
        ;
        _go:
                        push    offset _name
                        push    11
                        push    WM_GETTEXT
                        push    hEdit1
                        call    SendMessageA

                        cmp     eax, 10
                        ja      _wroc

                        cmp     eax, 4
                        jb      _wroc

                        call    IloscNameMix

                        push    eax
                        xor     edx, edx
                        mov     eax, offset _name

        _rol_it:
                        mov     bl, byte ptr [eax]
                        rol     ebx, 16
                        add     edx, ebx
                        inc     eax
                        cmp     byte ptr [eax], 0
                        jnz     _rol_it

                        push    edx
                        push    offset _serial1
                        push    11
                        push    WM_GETTEXT
                        push    hEdit2
                        call    SendMessageA

                        cmp     eax, 10
                        jnz     _wroc

                        mov     _ilosc_serial1, eax
                        mov     edx, offset _serial1
                        call    MieszajSerial

                        pop     edx
                        xor     ebx, edx
                        mov     dword_4020F1, ebx
                        mov     _wazny_dword, 0

                        push    offset _serial2
                        push    11
                        push    WM_GETTEXT
                        push    hEdit3
                        call    SendMessageA

                        cmp     eax, 10
                        jnz     _wroc

                        mov     _ilosc_serial1, eax
                        mov     edx, offset _serial2
                        call    MieszajSerial

                        pop     eax
                        xor     ebx, eax
                        mov     eax, dword_4020F1
                        or      ebx, eax
                        rol     ebx, 2
                        mov     _wazny_dword, 0
                        sub     ebx, 3A7DEF7Dh
                        jz      _goodboy

        _wroc:
                        jmp     _ret

        ;
        ;     GOODBOY
        ;
        _goodboy:
                        push    0
                        push    offset lpCaption
                        push    offset lpGoodTxt
                        push    hWnd
                        call    MessageBoxA
                        jmp     _ret
        ;
        ;     ABOUT
        ;
        _about:
                        push    0
                        push    offset lpCaption
                        push    offset lpAboutText
                        push    hWnd
                        call    MessageBoxA
                        jmp     _ret

        _DlgProc        endp

        ;
        ; proc: MieszajSerial
        ;
        MieszajSerial   proc

                        xor     ebx, ebx
                        mov     esi, 1
                        mov     eax, edx

        _next_char:
                        mov     bl, byte ptr [eax]
                        cmp     bl, 0
                        jz      _koniec
                        cmp     bl, 30h
                        jb      _nie_cyfra
                        cmp     bl, 39h
                        ja      _nie_cyfra
                        call    Algo
                        inc     eax
                        jmp     _next_char

        _nie_cyfra:
                        xor     ebx, ebx
                        ret

        _koniec:
                        mov     ebx, _wazny_dword
                        ret

        MieszajSerial   endp

        ;
        ; proc: Algo
        ;
        Algo            proc

                        push    eax
                        and     ebx, 15
                        mov     eax, ebx
                        mov     ecx, _ilosc_serial1
                        sub     ecx, esi
                        jcxz    _ecx_zero

        @loop:
                        mov     edx, 10
                        imul    edx
                        dec     ecx
                        jcxz    _ecx_zero
                        jmp     @loop

        _ecx_zero:
                        add     _wazny_dword, eax
                        inc     esi
                        pop     eax
                        ret

        Algo            endp

        ;
        ; proc: IloscNameMix
        ;
        IloscNameMix    proc

                        sub     eax, 1
                        mov     ecx, eax
                        mov     eax, 1
                        mov     ebx, 2

        @loopek:
                        mul     ebx
                        inc     ebx
                        loop    @loopek
                        not     eax
                        ret

        IloscNameMix    endp

        ;
        ; proc: _Wez_Uchwyty
        ;
        _Wez_Uchwyty    proc

                        push    1001
                        push    dword ptr [ebp+8]
                        call    GetDlgItem

                        mov     hEdit1, eax

                        push    1002
                        push    dword ptr [ebp+8]
                        call    GetDlgItem

                        mov     hEdit2, eax

                        push    1003
                        push    dword ptr [ebp+8]
                        call    GetDlgItem

                        mov     hEdit3, eax
                        ret

        _Wez_Uchwyty    endp

        end start

                                                                                        .
        *********************************************************************************

        Gotowe do ponownej rekompilacji, just copy/paste ;).. tak naprawde chodzilo mi o
        to, zeby "naprawic" crackme i looknac jakie ma algo sprawdzajace serial. W sumie
        widac wszystko pod disassemblerem, ale co to przyjemnosc sledzic kod w IDA czy
        we W32Dasm.. ponadto mozesz sobie postawic gdziekolwiek chcesz INT 3 i jechac F10
        zeby zobaczyc co tam _r00t_ zamierzyl sobie "udziewiczyc" na wieki ;)

        Procedura jest uatfa jesli sie lubi wszystko brutem ciagnac, :).. mimo, ze
        mamy "odgadnac" 2 seriale, ktore maja po 10 znakow nie jest tak zle.. niech nas
        pocieszy charset - 30h, 31h, 32h, 33h, 34h, 35h, 36h, 37h, 38h, 39h.

        Same cyferki, proponuje zalozyc sobie najpierw jakis badziewny serial1, a potem
        znalezc serial2, ktory po modyfikacji jeszcze z tym pierwszym i name da nam
        wartosc hash-owana 3A7DEF7Dh. Mi szkoda pradu i nowego procesora, ktory mimo, ze
        zostal kupiony  spcjalnie do takich 'brutalnych zadan', tym razem bedzie mial
        wolne.. Oczywiscie szukac mozecie serialika losowo uwzgledniajac charset ofkoz.
        Czasami zlamania takiego "kolosa bitowego" daje spora satysfakcje.. 

        Ja ostatecznie cos takiego sklecilem, pfff nawet nie chce mi sie tego uwaznie
        zweryfikowac i optymalizowac, powinno dzialac od warunkiem, ze uda sie w jakis
        magicznie intuicyjny :) sposob wymyslic ten serial1, dla ktorego bedzie w ogole
        serial2 istnial ;).. Musi on miec 10 znakow z zakresu 30h-39h, strzelajta.. ;)

        *********************************************************************************
                                                                                        .
        ; 23 lipca 2002
        ; brute do crackme1 root'a
        ;
        ; kod by cybult, nie oddaje pieniedzy za spalone procki, rozdzielnie pradu,
        ; przepalone z przegrzania druty trakcji wysokiego napiecia, wybuchy w
        ; elektrowni itd.

        .686
        .model flat,stdcall

        include \masm32\include\kernel32.inc
        includelib \masm32\lib\kernel32.lib

        .data

        _wazny_dword    dd      ?, 10 dup (0)
        _serial1        db      '0198320020',30 dup (0)
        dword_4020F1    dd      ?, 10 dup (0)

        ; wszystkie dane wyliczone na 'cybult', jesli chcesz szukac na swoj
        ; nick to zamien wszystkie magic wartosci wyliczone z mojej ksywy

        .code

        start:
                        int     3                               ; debugee here ;)
        _brut:
                        mov     esi, offset _serial1

                        cmp     byte ptr [esi], 39h
                        jnz     _dalej1

                        cmp     byte ptr [esi+1], 39h
                        jnz     _dalej2

                        cmp     byte ptr [esi+2], 39h
                        jnz     _dalej3

                        cmp     byte ptr [esi+3], 39h
                        jnz     _dalej4

                        cmp     byte ptr [esi+4], 39h
                        jnz     _dalej5

                        cmp     byte ptr [esi+5], 39h
                        jnz      _dalej6

                        cmp     byte ptr [esi+6], 39h
                        jnz      _dalej7

                        cmp     byte ptr [esi+7], 39h
                        jnz      _dalej8

                        cmp     byte ptr [esi+8], 39h
                        jnz      _dalej9

                        cmp     byte ptr [esi+9], 39h
                        jz      _niema

                        inc     byte ptr [esi+9]
                        mov     byte ptr [esi+8], 30h
        _dalej9:
                        inc     byte ptr [esi+8]
                        mov     byte ptr [esi+7], 30h
        _dalej8:
                        inc     byte ptr [esi+7]
                        mov     byte ptr [esi+6], 30h
        _dalej7:
                        inc     byte ptr [esi+6]
                        mov     byte ptr [esi+5], 30h
        _dalej6:
                        inc     byte ptr [esi+5]
                        mov     byte ptr [esi+4], 30h
        _dalej5:
                        inc     byte ptr [esi+4]
                        mov     byte ptr [esi+3], 30h
        _dalej4:
                        inc     byte ptr [esi+3]
                        mov     byte ptr [esi+2], 30h
        _dalej3:
                        inc     byte ptr [esi+2]
                        mov     byte ptr [esi+1], 30h
        _dalej2:
                        inc     byte ptr [esi+1]
                        mov     byte ptr [esi], 30h
        _dalej1:
                        inc     byte ptr [esi]

                        mov     eax, esi

                        sub     ebx, ebx
                        mov     esi, 1
        _next_char:
                        mov     bl, byte ptr [eax]
                        test    bl, bl
                        jz      _koniec

                        push    eax
                        and     ebx, 0Fh
                        mov     eax, ebx
                        mov     ecx, 0Ah
                        sub     ecx, esi
                        jz      _ecx_zero
        @loop:
                        mov     edx, 10
                        imul    edx
                        dec     ecx
                        jnz     @loop
        _ecx_zero:
                        add     _wazny_dword, eax
                        inc     esi
                        pop     eax
                        inc     eax
                        jmp     _next_char
        _koniec:
                        mov     ebx, _wazny_dword

                        xor     ebx, 0293021Fh
                        mov     dword_4020F1, ebx

                        mov     ebx, 0B669FFFDh
                        mov     eax, dword_4020F1
                        or      ebx, eax
                        sub     ebx, 4E9F7BDFh
                        mov     _wazny_dword, 0
                        jnz     _brut

                        int     3
        _niema:
                        int     3
                        invoke  Exitprocess, -1
        end start
                                                                                        .
        *********************************************************************************


        I to byloby wszystko na temat tego "zabezpieczonego" crackme, podsumowujac musze
        wam powiedziec, ze w zyciu nie spotkalem sie z takim pomyslem na zrobienie czegos
        nielamliwego ;).Przyszedl mi pomysl w zwiazku z tym na nowe crackme, look at that:

                crackme by best wymiatacz
                rullez: no patching, just register it
                 skill: easy
                greets: all ppl from a to z

        ;--------------------------------------------------------------------------------
        Entrypoint:
                        sub     eax, eax
                        xchg    eax, eax                ; nop ;)
                        sub     eax, eax
                        jnz     _cracked

                        invoke  MessageBoxA, eax, addr lpFailed, eax, eax
                        jmp     _exit
        _cracked:
                        invoke  MessageBoxA, eax, addr lpSuccess, eax, eax
                        jmp     $+2
        _exit:
                        invoke  ExitWindowsEx, EWX_FORCE, eax
        ;--------------------------------------------------------------------------------

                PS. Czekam na solucje ;)


        pozdrawiam tomkola, kwaska, witka g, cyberboba, shielda, tnb!, virsa, hintusa.

        23/24 lipca 2002

        cybult
        cybult@poczta.onet.pl
