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


                         CrackMe 5.0 by Kwasek [HTBteam] tutorial


        Cel     : CrackMe 5.0 by Kwasek [HTBteam]
        Czym    : SoftICE, IDA, Internet Exlorer :)
        Opis    : Crackme spakowane FSG v1.0, name/serial, zadnych anti-si,
                  zadnych junkow, zadnych anti-trace'ow. Piur kod :).

        notice  : ustaw sobie czcionke terminal 12 przy czytaniu tego tuta,

        Dzis opisze to jak udalo mi sie polamac calkiem fajnie zrobione crackme
        Kwaska, ktorego to te cechuje dobra znajomosc mnemonikow inteloskich oraz
        slaba wiedza na temat crypto :). No ale ktoz dobrze zna sie na krypografii
        w dzisiejszych czasach skoro juz kilka lat ani jednej osobie nie udalo
        sie znalezc (czy to matematycznie czy programowo) jednego hasha dla dwoch
        roznych wartosci pojechanych np. MD5 czy SHA-1. Hehe, mam fantazje co? :)
        No ale taka jest prawda, nie ma rzeczy niemozliwych na swiecie, a co za 
        tym idzie - kazdy algorytm mozna zlamac niekonwencjonalnie tzn. patrzac
        na niego z zupelnie innej strony niz podstawa teoretyczna na ktorej sie
        on opiera. Czekam wiec na jakiegos genialnego nieuka, ktory nie majac
        w ogole pojecia o kryptografii, kryptogramach itd. napisze sobie w domu
        keygena do TheBat! lamiac 1024-bitowy klucz RSA :). Swiat nauki nigdy nie
        niedocenial ludzi wyprzedzajacych powszechnie akceptowany sposob myslenia
        o 50 lat. Dobrym przykladem takiego czlowieka jest Albert Einstein, ktory
        swoja (mloda jeszcze) teoria wzglednosci niejednego uczonego powalil na
        kolana z kpiacego smiechu, ot tak wlasnie tworzyl sie swiat. Jesli wiec
        sadzicie, ze w matematyce tez juz wszystko zostalo odkryte i doskonale
        udowodnione to sie mylicie niezmiernie :). Mowie Wam, ze za jakis trafi
        sie kolejny Einstein, ktory wwali te cale crypto w maliny i Wasze duze
        inwestycje intelektualne w obecna kryptografie nadawac sie beda na jakis
        program w TV typu "Bajki Dziadka Kryptografa" ;). Niewiem skad u mnie ta
        dziwna niechec do tego pop* crypto, w kazdym razie pamietajcie, ze czasami
        celowo sciemniam zeby nastroj zbudowac (dziewczyny tego nie przeczytaja,
        hehe ;). Ok, nastroj mamy, wiedze tez.. czas wiec lamac crackme. Efezgie
        jest packerem, ktory w sumie nie przeszkadza w czasie lamania pod SoftICE
        ale ze wzgledu na to, ze w DataReskju sie rowniez postarali to wywalimy
        packera zeby moc listingowac kod (a troche tego bedzie). Sposob recznego
        unpacku fsg gdzies juz opisywalem wiec licze na to, ze masz crackmesa
        w IDA i widzisz to co ja widze:

loc_401198:
                pushad                                  ; wszystko co 32bitowe i uniwersalne
                                                        ; idzie na stos :)

                xor     eax, eax                        ; ustawianie parametru dla cpuid
                                                        ; 0 oznacza nazwe OEM procesora
                cpuid                                   ; get CPU Identificator

                xor     ebx, ecx                        ; cpuid zwroci dla kazdego
                sub     edx, ecx                        ; typu procesora inne
                mov     eax, ecx                        ; warosci w eax:ebx:ecx:edx
                shl     ecx, 2                          ; i tutaj maly mix tych
                rol     eax, 2                          ; czterech wartosci ze soba

                mov     esi, offset unk_403169          ; do esi adres bufora
                mov     [esi], eax                      ; w ktorym jest zapisywany
                mov     [esi+4], ebx                    ; wynik powyzszych operacji.
                mov     [esi+8], ecx                    ; bufor ten bedzie uzyty za
                mov     [esi+0Ch], edx                  ; chwile przy modifikacji name


                push    offset word_403B50              ; adres struktury SYSTEMTIME
                call    GetSystemTime                   ; pobierz aktulany czas systemowy

                mov     edi, offset unk_403336          ; tutaj crackme zapisze date
                mov     ax, ds:word_403B56              ; w formacie: dd.mm.yyyy
                mov     cl, 0Ah
                div     cl
                add     ax, 3030h
                mov     [edi], ax
                add     edi, 2
                mov     byte ptr [edi], 2Eh
                inc     edi
                mov     ax, ds:word_403B52
                mov     cl, 0Ah
                div     cl
                add     ax, 3030h
                mov     [edi], ax
                add     edi, 2
                mov     byte ptr [edi], 2Eh
                inc     edi
                xor     eax, eax
                xor     edx, edx
                mov     ax, ds:word_403B50
                mov     cx, 64h
                div     cx
                mov     cl, 0Ah
                div     cl
                add     ax, 3030h
                mov     [edi], ax
                add     edi, 2
                mov     ax, dx
                mov     cl, 0Ah
                div     cl
                add     ax, 3030h
                mov     [edi], ax
                add     edi, 2
                mov     byte ptr [edi], 0               ; marker konczacy string z data.
                                                        ; koniecznosc jego wystepowania
                                                        ; poddalbym jednak watpliwosci :).

                mov     edi, offset unk_403336          ; otrzymana wyzej data jest
                xor     dword ptr [edi], 12345678h      ; lekko modyfikowana tymi oto
                xor     dword ptr [edi+4], 12233445h    ; magicznymi wartosciami
                xor     word ptr [edi+8], 9090h         ; i na to samo miejsce zapisywana

                push    40h                             ; pobiera max 64-1 znaki name
                push    offset unk_403027               ; to adres name
                push    6Fh
                push    [ebp+hWnd]
                call    GetDlgItemTextA                 ; pobiera nasze imie

                push    40h                             ; pobiera max 64-1 znaki seriala
                push    offset unk_4030A7               ; adres wpisanego seriala
                push    70h
                push    [ebp+hWnd]
                call    GetDlgItemTextA                 ; pobiera serial

                cmp     eax, 10h
                jnz     loc_4013E4                      ; czy serial ma 16 znakow?
                                                        ; jesli nie, to zly serial.
                mov     ds:dword_40332E, eax            ; zapisz 16 do bufora
                                                        ; (i tak nie uzywany dalej ;)
                                                        ; 
                mov     ecx, 8                          ; ok, tutaj mamy do czynienia z
                mov     esi, offset unk_4030A7          ; procedura, ktora zamienia nasz
                mov     edi, offset unk_4030C8          ; 16 bajtowy serial ascii na swoja
                                                        ; 8 bitowa reprezentacje (2*DWORD)
                                                        ; np. znak 'A' zamieni na integer 0Ah
loc_401282:                                             ; wniosek z tego taki, ze znaki
                mov     al, [esi]                       ; seriala zawierja sie od A...F + 0...9
                sub     al, 30h                         ; (edit ma na stale flage UPPERCASE).
                cmp     al, 9                           ; czy to cyfra
                jbe     short loc_40128C                ; 
                sub     al, 7                           ; popraw na A-F
                                                        ; 
loc_40128C:                                             ; 
                inc     esi                             ; wskaz na nastepny znak seriala (ln)
                mov     ah, [esi]                       ; 
                sub     ah, 30h                         ; 
                cmp     ah, 9                           ; czy to cyfra
                jbe     short loc_40129A                ; 
                sub     ah, 7                           ; popraw na A-F
                                                        ; 
loc_40129A:                                             ; 
                inc     esi                             ; wskaz na nastepny znak seriala (hn)
                shl     al, 4                           ; 
                or      al, ah                          ; 
                mov     [edi], al                       ; zapisz przekonwertowany znak jako int.
                inc     edi                             ; 
                dec     ecx                             ; counter-1
                jnz     short loc_401282                ; 8iteracji * 2bajty = 16 bajtow
                                                        ; (zgadnijcie co mam z matmy ;)

                mov     eax, offset unk_403027          ; do eax adres z name

                sub     ebx, ebx                        ; \
                sub     ecx, ecx                        ;  > zerowanie rejestrow
                sub     edx, edx                        ; /

                                                        ; ecx posluzy jako wskaznik (pointer)
                                                        ; do danych o adresie eax
loc_4012B1:
                mov     dl, [ecx+eax]                   ; w dl kolejno znajda sie znaki name
                cmp     dl, 0                           ; czy to juz koniec stringu?
                jz      short loc_4012C9                ; jesli tak to koniec procki
                inc     ecx                             ; ptr+1
                add     ebx, edx                        ; * jak widac tworzona jest
                xor     ebx, ecx                        ; * tutaj pewna unikalna
                neg     ebx                             ; * wartosc dla kazdego imienia,
                bswap   ebx                             ; * zalezna od znakow z jakich sie
                bswap   edx                             ; * sklada, ich kolejnosci oraz ilosci.
                lea     ebx, [ebx+edx*4]                ; ebx= ebx+edx*4 (np. ebx=5+4*4=21)
                jmp     short loc_4012B1                ; nastepna petla

                                                        ; ebx i edx sa wynikami z tego co
                                                        ; sie wyzej dzialo
loc_4012C9:
                mov     edi, offset unk_403336          ; do edi adres z nasza zmodyfikowana
                                                        ; wczesniej data

                add     ebx, edx                        ; x1+x2
                sub     ebx, ecx                        ; k1=(x1+x2) - ilosc znakow w name
                xor     ebx, [edi]                      ; k1^t1
                add     ebx, [edi+4]                    ; (k1^t1)
                sub     bx, [edi+8]                     ; (k1^t1)-t2

                                                        ; bardzo istotna wartoscia jest
                                                        ; to co siedzi w (e)bx na koncu.

                xor     edi, edi                        ; edi - ptr i posrednio licznik
                mov     eax, offset unk_403742          ; eax - adres tablicy ;)
                mov     edx, offset unk_403342          ; edx - adres bufora

loc_4012E7:
                push    ebx                             ; zapamietaj ebx

                and     ebx, 0FFh                       ; zniszcz 24 bajty zaczynajac od MSB
                                                        ; a reszte zostaw (tylko bl ocaleje)

                lea     ebx, ds:0[ebx*4]                ; lea ebx,[ebx*4+00000000]
                                                        ; czyli po prostu ebx*4
                mov     ecx, [ebx+eax]                  ; mov ecx, dword ptr [_tablica+ebx]
                mov     [edi+edx], ecx                  ; umiesc dworda w buforze
                add     edi, 4                          ; ptr+4
                cmp     edi, 300h                       ; czy juz 300/4 razy powtorzono?
                jz      short loc_401312                ; jezeli tak to koniec tworzenia tablicy

                pop     ebx                             ; przywroc wartosc z ebx
                rol     ebx, 2                          ; i zmodyfikuj tu
                add     ebx, 18877665h                  ; i tu
                jmp     short loc_4012E7                ; skocz znowu

                                                        ; to co sie dzieje powyzej mozna
                                                        ; okreslic jako tworzenie tablicy
                                                        ; dwordow na podstawie istniejacej
                                                        ; (stalej) juz innej tablicy i
                                                        ; wartosci ebx (magic z name).
                                                        ; jak sie za chwile okaze, bedzie
                                                        ; to tablica z kodem, ktory sie
                                                        ; wykona, zupelnie jak w wirusach
                                                        ; polimorficznych, trzeba miec
                                                        ; do tego niezla wiedze o opcodach
                                                        ; albo tate, ktory pracuje w intelu :).
loc_401312:
                pop     ebx                             ; przywraca ebx z procedury wczesniej

                mov     byte ptr [edi+edx], 0C3h        ; ustaw "ret" czyli powrot
                                                        ; do procedury z call'a

                mov     edi, offset unk_403336          ; do edi jeszcze raz ta data
                mov     eax, [edi]                      ; modyfikacja z eax
                mov     ecx, [edi+4]                    ; z ecx
                mov     edx, [edi+8]                    ; i z edx

                mov     edi, offset unk_403342          ; bufor, tyle ze zmodyfikowany w tak
                                                        ; sprytny sposob, ze zawiera kod

                call    edi                             ; ktory tutaj sie pieknie wykona :)

                                                        ; niewiem czy Kwasek jest tak dobry
                                                        ; ze przeanalizowal wszystkie wyniki
                                                        ; ebx z liczania crc name, (a sadze
                                                        ; ze ich ilosc tych wynikow jest
                                                        ; raczej okreslona i zakres opcodow
                                                        ; waski) ale modifikowane sa wszystkie
                                                        ; cztery rejestry: eax, ebx, ecx, edx
                                                        ; ktore z koleji szyfruja name w taki
                                                        ; sposob, ze zawsze ma ono dlugosc
                                                        ; 128bitow (4*32).

                mov     edi, offset unk_403027          ; wlasnie tutaj 
                add     [edi], ecx                      ; nastepuje ta
                sub     [edi+4], eax                    ; modyfikacja.
                add     [edi+8], edx                    ; 
                xor     [edi+0Ch], ebx                  ; 

                mov     byte ptr [edi+10h], 0           ; zakonczenie ciagu bajtow (juz nie
                                                        ; ascii zero terminated !!) zerem.

                mov     esi, edi                        ; dla zabawy
                mov     ebx, [edi+8]                    ; tutaj rowniez
                xor     [esi], ebx                      ; maly mix
                xor     [edi+8], ebx                    ; ale efekt tan
                mov     ebx, [edi+0Ch]                  ; sam co kilka
                xor     [esi+4], ebx                    ; linijek wyzej
                xor     [edi+0Ch], ebx                  ; z tym, ze name ma w tym miejscu
							; zawsze 64 bity dlugosci.

                                                        ; teraz czas na zabawe w crypto,
                                                        ; raczej banal, nizej szczegoly:

                push    offset aCrackme5_0ByKw          ; db 'CrackMe 5.0 by Kwasek [HTBteam]',0
                call    sub_4017B1                      ; NewDES SetDecryptKey

                push    offset unk_4030C8               ; DataInput
                push    offset unk_403067               ; DataOutput
                call    sub_4015E3                      ; NewDES Crypt

                call    sub_401829                      ; NewDES Clear

                push    2Fh                             ; 47
                push    offset aGratulujeWprow          ; db 'Gratuluje :) Wprowadzony..."
                call    sub_40183F                      ; RC4 SetKey

                push    8                               ;
                push    offset unk_403067               ; 
                call    sub_401893                      ; RC4 Crypt

                push    offset unk_403067               ; co ma zaszyfrowac
                push    offset a__Htbteam_              ; ..::[HTBteam]::. (klucz 16 bajtow)
                call    sub_4018E6                      ; TEA Decrypt

                mov     esi, offset unk_403027          ; nasze name zmodyfikowane
                mov     edi, offset unk_403067          ; wynik deszyfroania s/n
                call    sub_4015C8                      ; porownaj te dwa ciagi

                test    eax, eax                        ; jesli sa takie same
                jnz     short loc_4013D1                ; to zlamalismy crackme

                mov     edi, offset unk_403027          ; w innym wypadku crackme
                mov     esi, offset unk_4030E9          ; sprzata po sobie i wraca
                mov     ecx, 40h                        ; do callbacku Dialog.
                repe movsb                              ; 
                mov     edi, offset unk_403067          ; 
                mov     esi, offset unk_4030E9          ; 
                mov     ecx, 40h                        ; 
                repe movsb                              ; 
                popad                                   ; przywraca wszystko co 32bitowe i                                                               ; uniwersalne ze stosu :)
                leave                                   ; 
                retn    10h                             ;

        
        Kilka slow komentarza: NewDES, RC4, TEA to _stosunkowo_ slabe algorytmy, ktorych
        mimo wszystko brutem ciagnac nie radze ;). Autor crackmesa wykorzystal tutaj
        dwie asmowe implementacje Witka Gdorfa, TEA zas jest zmodyfikowana i naprawde
        pojecia nie mam skad Kwasek ja wydobyl ;), anyway, wystarczy mala wiedza o
        tym algorytmie zeby prawidlowo przeksztalcic procke szyfrujaca.

        W oryginale:
                _
        delta=(V5 -1) * 2^31 lub inaczej sqr(5) -1 * 2^31 = 2654435769d = 9E3779B9h
                _
        gdzie: V  to pierwiastek, a znak ^ to potegowanie

        A oto implementacja TEA w C: (nawet nie wiem skad ja mam)

        v = dane szyfrowane/deszyfrowane
        k = klucz
        n = ilosc rund (zwykle 32)

        //* Szyfrowanie TEA

        void Encrypt(long *v,long *k,long n)
        {
           long       y=v[0],z=v[1],sum=0,delta=0x9E3779B9;
              while(n-->0)
              {
                sum += delta;
                y += (z << 4)+k[0] ^ z+sum ^ (z >> 5)+k[1];
                z += (y << 4)+k[2] ^ y+sum ^ (y >> 5)+k[3];
              }
              v[0]=y;
              v[1]=z;
        gamma = gamma - delta
        }


        //* Deszyfrowanie TEA

        void Decrypt(long *v,long *k,long n)
        {
        gamma = gamma + delta
           long       y=v[0],z=v[1],sum=0,delta=0x9E3779B9;
              sum = (delta*n)
              while(n-->0)
              {
                z -= (y << 4)+k[2] ^ y+sum ^ (y >> 5)+k[3];
                y -= (z << 4)+k[0] ^ z+sum ^ (z >> 5)+k[1];
                sum -= delta;
              }
        
           v[0]=y;
           v[1]=z;
        }

        Ble, wszyscy wiedza o co chodzi, szukamy gamma z decrypt, tak sie sklada,
        ze gamma==delta, czyli w przy szyfracji uzyjemy gamma==0. TEA wiec juz
        omowiona, pozostaje tylko sciagnac sobie z sieci jakies implementacje
        NewDES i RC4 i mamy keygena. Warto zadbac o solidne czyszczenie bufferow
        uzwanych przez poszczegolne procedury ze wzgledu na dosyc duzy zakres
        uzywanej pamieci. Z odwroceniem calej tej imprezy problemu nie powinno
        raczej byc, kazdy algorytm jest uzyty jako modul wiec jesli w crackme
        oryginalnie jest:

        ;-----------------------------------------------------------------------
        01. cpuid -> save to buff
        02. data (time)  -> convert to ascii -> xoruj do buffera
        03. pobierz NAME
        04. pobieraz SERIAL
        05. serial -> dwords
        06. name   -> sumka ze znakow + sumka z time
        07. DEKODOWANIE opcodow
        08. modyfikacja rejestrow powstalymi opcodami
        09. xor NAME (16znakow) z wynikiem mixu opcodami
        11. DES setkey (key: CrackMe 5.0 by Kwasek [HTBteam])
        12. DES crypt  (serial -> DataOutput)
        12. RC4 setkey (pass: Gratuluje :) Wprowadzony serial jest..)
        13. RC4 crypt  (DataOutput 8 znakow)
        14. TEA ("..::[HTBteam]::.") -> DataOutput

        if *xor NAME* == DataOutput then GOOD SERIAL
        ;-----------------------------------------------------------------------

        ..to aby uzyskac dla swojego nicka poprawny serial trzeba:
        - przeprowadzic dokladnie te same operacje na name co wyzej
        - zaszyfrowac zmodyfikowany name w odwrotnej kolejnosci niz to jest w
          crackme uzyskujac w ten sposob valid serial, czyli:

        ;-----------------------------------------------------------------------
        01. TEA Crypt
        02. RC4 Crypt
        03. NewDES Crypt
        ;-----------------------------------------------------------------------

        Moze i wyglada to jakos strasznie ale tak naprawde jest dziecinnie latwe
        i nie koniecznie trzeba sie znac na tych cipherach zeby cokolwiek tutaj
        zdzialac. Wystarczy umiec includowac algorytmy szyfrujace ;). Staralem
        sie pokazac te etapy w punktach wiec nawet blondynka powinna zajarzyc co
        i jak, btw:

        Supermarket, dosyc spora kolejka, dzwoni komorka, odbiera blondynka:
        - Halo?.. Aaa to Ty kochanie... a skad wiedziales ze jestem w markecie?

        No wiec blondynki moze wykluczmy ;), keygen zalaczony.


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

        31 sierpnia 2002

        cybult
        cybult@poczta.onet.pl
