==========================================================================
$                                                                        $
$                           TuToriaL by Tymon                            $
$                                 What:                                  $
$              Official AAoCG Trial CrackMe 2002 by DiViNE               $
$                                                                        $
==========================================================================

.AbOuT

Dobry  wszystkim.   Dzis  na   warsztat  idzie   AAoCG  Trial   CrackMe by
DiViNE. Wydaje  mi sie,  ze ma   ono dosyc  ciekawe zabezpiecznie, dlatego
chyba warto zapuscic sobie go pod softice. Do zrobienia mamy dwie rzeczy:

 1. keymaker
 2. patch ( do nag'a pokazujacego sie na poczatku )

Nic nowego, przynajmniej na pierwszy rzut oka :)

A i jeszcze jedno.  Ten tutek na pewno  nie zrobi z Ciebie  czlonka AAoCG.
Grupka ma juz nowe crackme, ponoc  o wiele trudniejsze ( choc sam  jeszcze
go nie widzialem, ale mam nadzieje, ze juz niedlugo ( jo DiViNE :)) ).

Oki, let's start.

TOOLS: SoftIce, IDA , decrypter for  yoda's Crypter ( 2 ostatnie tylko  do
       kg) moze jeszcze IceDump.

.StaRT

Oki, moze  zaczniemy od  keymaker'a, patcha  zostawimy sobie  na deser :).
Pierwsze oogledziny mowia nam, ze prog jest zacryptowany yoda's crypterem.
Do tego wlasnie bedzie potrzebny nam decrypter, by caly kodzik nam pieknie
wygladal pod IDA. Ja probowalem decryptowac to pod icedump'em, ale yoda ma
zabezpieczenie antydump, wiec z tego nici. Trzeba sciagnac decryptera.  Na
poczatku  uruchom sobie  icedump'a, bo  yoda nafaszerowany  jest plapkami
ANTY-SI ( dokladnie  nie wiem jakie,  bo nie chcialo  mi sie sprawdzac,  a
icedump skutecznie je wszystkie eliminuje  ). Wpisujemy jakies tam dane  i
lapiemy na  standart, czyli  getdlgitemtexta. Pozwole  sobie przytoczyc tu
wycinki z kodu IDY. Bedzie bardziej czytelnie.

                finit
                push    0FFh
                push    offset _name
                push    ID_EDIT
                push    hWnd     ; hWnd
                call    GetDlgItemTextA
                cmp     eax, 5
                jb      _za_malo_znakow
                push    0FFFFFFFBh

_agan:                                  ; CODE XREF: DialogProc+3E3j
                push    eax
                add     eax, eax
                imul    eax, eax
                rol     eax, 3
                xchg    al, ah
                mov     ebx, eax
                pop     eax
                imul    eax, ebx, 3DFCAh
                lea     esi, _name
                push    eax
                xor     ebx, ebx

_dalej:                                 ; CODE XREF: DialogProc+352j
                movzx   eax, byte ptr [esi]
                imul    eax, 4544h
                rol     eax, 4
                xchg    al, ah
                add     ebx, eax
                inc     esi
                cmp     byte ptr [esi], 0
                jnz     _dalej
                pop     eax
                add     eax, ebx
                push    eax
                xor     ebx, ebx
                lea     esi, _name

_dalej2:                                ; CODE XREF: DialogProc+373j
                movzx   eax, byte ptr [esi]
                xor     eax, 97A7h
                rol     eax, 41h
                xchg    al, ah
                add     ebx, eax
                inc     esi
                cmp     byte ptr [esi], 0
                jnz     _dalej2
                pop     eax
                add     eax, ebx
                lea     edi, _tabka
                mov     [edi], eax
                rol     eax, 3
                xor     eax, 140h
                lea     esi, _name
                push    eax
                sub     ebx, ebx

_dalej3:                                ; CODE XREF: DialogProc+3A2j
                movzx   eax, byte ptr [esi]
                shr     eax, 45h
                ror     eax, 4
                xchg    al, ah
                add     ebx, eax
                inc     esi
                cmp     byte ptr [esi], 0
                jnz     _dalej3
                xor     ebx, 45h
                rcl     ebx, 3
                pop     eax
                add     eax, ebx
                xchg    eax, ebx
                mov     [edi+4], ebx
                cmp     [ebp+var_4], 0FFFFFFFDh
                jz      _skacz
                push    ebx
                fild    [esp+0FFFFFFE8h+arg_10]
                mov     eax, [edi]
                push    eax
                fild    [esp+0FFFFFFECh+arg_C]
                lea     ebx, _name
                push    ebx
                call    lstrlenA
                push    eax
                mov     edx, eax

_II:                                    ; CODE XREF: DialogProc+3D9j
                movzx   ecx, byte ptr [ebx]
                sub     ecx, eax
                mov     [ebx], cl
                inc     ebx
                dec     edx
                jnz     _II

_skacz:                                 ; CODE XREF: DialogProc+3B5j
                add     [ebp+var_4], 2
                cmp     [ebp+var_4], 0FFFFFFFFh
                jnz     _agan
                fistp   dword ptr [edi+8]
                fistp   dword ptr [edi+0Ch]
                pop     eax
                push    0FFh
                push    offset _name
                push    ID_EDIT
                push    hWnd         ; hWnd
                call    GetDlgItemTextA              ; tu poraz drugi pobierany jest name
                mov     _tab2, eax
                lea     esi, _name
                lea     edi, _tabka
                add     edi, 8
                mov     eax, 76h

_dalej6:                                ; CODE XREF: DialogProc+460j
                lea     esi, _name
                add     edi, 8
                push    eax
                xor     eax, eax
                sub     ebx, ebx

_dalej4:                                ; CODE XREF: DialogProc+452j
                movzx   ecx, byte ptr [esi]
                add     ecx, ecx
                xor     ecx, 1A44h
                movzx   edx, byte ptr [esi+1]
                add     edx, edx
                xor     edx, 0DCAB1h
                imul    edx, ecx
                imul    ecx, edx
                add     eax, ecx
                add     ebx, edx
                add     esi, 2
                cmp     byte ptr [esi], 0
                jnz     _dalej4
                mov     [edi], eax
                mov     [edi+4], ebx
                call    _make
                pop     eax
                dec     eax
                jnz     _dalej6                 ; end :)


Hu... Troche to dlugawe. Ogolnie  cala ta procka, liczy sobie  960 bajtowa
tablice na podstawie podanego nicka ( _tabka ). Sam name jest tu pobierany
2 razy i mielony w kilku mniejszych prockach ( co doskonale widac w kodzie
). Nasz  nick musi  miec minimum  5 znakow.  Oki, zobaczmy  co dzieje  sie
dalej:

                push    9C4h
                push    offset serial
                push    65h
                push    [ebp+arg_0]
                call    j_GetDlgItemTextA       ; tu nic innego jak pobieranie s/n
                test    eax, eax
                jz      locret_40155B           ; czy sa jakies znaki
                mov     edi, offset serial
                mov     edx, offset dwordsn     ; miejsce na przekonwertowane znaki
                sub     edx, 4
                push    240h

_conv:                                  ; CODE XREF: sub_40105D+49Fj
                push    edx
                call    hexstr2dword            ; czyli '45C' = 45Ch
                pop     edx
                add     edx, 4
                mov     [edx], eax              ; zapisz
                dec     [ebp+var_10]
                jnz     short _conv             ; i tak caly pobrany s/n

Jak  juz  widac  tu  nie  dzieje  sie  nic  innego  jak  pobranie  s/n   i
przekonwertowanie go, w stylu hexstr2dword. Oki zobaczmy dalej:

                lea     eax, dwordsn
                lea     ecx, key
                push    78h

doall:                                  ; CODE XREF: sub_40105D+4BFj
                push    ecx
                push    eax
                call    TEA_decode
                add     eax, 8
                add     ecx, 8
                dec     [ebp+var_14]
                jnz     short doall

Tu chyba  jest cale  serce crackme.  W tym  miejscu cala  przekonwertowana
nasza tablica z  s/n przechodzi przez  algorytm TEA_decode. Jako  klucz do
TEA, urzyto samych 0. Zgadnijcie co bedzie dalej :)

                lea     esi, dwordsn
                xor     eax, eax
                mov     dword_4055A4, ecx
                push    3C0h
                push    offset _tabka           ; tablica z name
                push    offset dwordsn          ; tablica z TEA_decode(serial)
                call    sub_402765              ; cmp ... :)
                test    eax, eax
                jnz     short locret_40155B     ; jezeli oki, to good cracker ...

Jak widac nie mamy tu nic trudnego. Cale crackme ogranicza sie do:

 TEA_decode(serial) = MIX(name)

So rozwiazaniem bedzie:

 sn = TEA_encode( MIX (name) ).

So, teraz  musimy przepuscic  cala tablice  z name  ( 960  bajtow )  przez
algorytm TEA_encode (  oczywiscie po 8  bajtow ), a  nastepnie kazdy dword
przekonwertowac na  hexstring. I  to juz  koniec. Wystarczy  teraz napisac
proga i mamy sn. Wlasciwie to najlepjej napisac od razu keygena. Ogranicza
sie to tylko do  copy & paste :)  no i do napisania  procki deszyfrujacej.
Mam nadzieje, ze do tutka  bedzie dolaczone zrodelko kg, wiec  nie powinno
byc problemu.

Oki, obiad sie  skonczyl, a ja  nie jestem najedzony  :) Mam nadzieje,  ze
deser cos zmieni :)

 PATCH

Kilka minut i  wiemy, ze okienko  wyskakujace na poczatku  jest wywolywane
przez  api  DialogBoxParamA.  Nic   wiec  prostszego  jak  podstawic   pod
pierwszego push'a z argumentami  do funkcji jmp'a przeskakujacego  cale to
okienko.  Jedynym  problemem  jest  tu yoda's  crypter.  Ja  widze  tu dwa
rozwiazania:

 1. Inline patching
 2. Reversing yoda's crypter

Ja, poniewaz nie jestem jeszcze najedzony, wybieram punkt 2 :). Jak chcesz
mozesz zrobic sobie inline patch'a.  Jest do tego wiele programow,  m. in.
Inline Patcher by  Kwasek, ale wiele  razy bylo to  juz opisywane, dlatego
wlasnie wybierama punkt drugi. So szykujcie softice loadera, jak sie okaze
to tez jest bardzo proste. Let's go!

Lapiemy okienko na api DialogBoxParamA i spisujemy sobie offset pierwszego
push'a.  Jest  to  40101E.  Oki  teraz  ladujemy  crackme  z  loadera.  Ja
znalazlem takie o to ciekawe miejsce w kodzie ( 2*F12 ).

017F:00417324  53                  PUSH      EBX
017F:00417325  FF9573274000        CALL      [EBP+00402773]
017F:0041732B  96                  XCHG      EAX,ESI    
017F:0041732C  50                  PUSH      EAX
017F:0041732D  57                  PUSH      EDI
017F:0041732E  FF95A0274000        CALL      [EBP+004027A0]
017F:00417334  58                  POP       EAX 
017F:00417335  8B8564254000        MOV       EAX,[EBP+00402564]                 
017F:0041733B  BB01000000          MOV       EBX,00000001 
017F:00417340  E808000000          CALL      0041734D           <-- decryptowanie kodu
017F:00417345  8D85A3214000        LEA       EAX,[EBP+004021A3]                 
017F:0041734B  50                  PUSH      EAX           
017F:0041734C  C3                  RET

So,  chyba warto  zajrzec do  tego call'a.  Pelno w  nim junkow,  dlatego
przedstawie 'odjunkowany' juz kodzik :)

017F:004173D1  AC                  LODSB                ; czytaj bait z [edi]
017F:004173D2  02C1                ADD       AL,CL   
017F:004173D8  04D0                ADD       AL,D0   
017F:004173DA  2AC1                SUB       AL,CL            
017F:004173DF  C0C883              ROR       AL,83   
017F:004173E2  C0C8E4              ROR       AL,E4   
017F:004173E5  F9                  STC               
017F:004173E6  2AC1                SUB       AL,CL   
017F:004173E8  3466                XOR       AL,66   
017F:004173EA  F8                  CLC               
017F:004173EB  049E                ADD       AL,9E   
017F:004173ED  C0C0B9              ROL       AL,B9   
017F:004173F3  045E                ADD       AL,5E   
017F:004173F5  F8                  CLC               
017F:004173F6  F8                  CLC               
017F:004173F8  0425                ADD       AL,25   
017F:004173FA  C0C03E              ROL       AL,3E   
017F:00417400  02C1                ADD       AL,CL   
017F:00417402  AA                  STOSB                ; zapisz w poprzednie miejsce
017F:00417403  E2CC                LOOP      004173D1   ; i tak wszystko

Jak  widac  to nie  jest  trudne cryptowanie.  Pobierany  jest kazdy  bajt
naszego proga, potem przechodzi on ta  procke i zapisywany jest w to  samo
miejsce. Warto  jeszcze dodac,  ze w  ecx jest  numer ilosci instrukcji do
decryptowania, minus  te juz  odcryptowane,  co   mozna  sie  domyslec  po
instrukcji loop. Oki, jak widac wszystko odwracalne i przyjemne dla oka :)
Warto  sie jeszcze  dowiedziec jaki numer  jest w ecx,  gdy przerabiane sa
instrukcje  z offsetu,  gdzie  mamy podstawic  swoje instrukcje asm.   So,
gdy  juz  bedziemy w  petli  loop  zakladamy   bpm   na 40101E   (  offset
miejsca   w  ktorym bedziemy  patchowali  ),  F5   i   juz sice   nam  sie
zatrzymal. Nasze ecx=1BE2h,  warto  jeszcze   spisac    orginalne    baity
(   te    przed decryptowaniem  )    bysmy wiedzieli,  gdzie patchowac   w
hexeditorze.  Te bajty  to:  CC BC   CB 64  5D.   My  podmienimy tylko   2
pierwsze,   bo  postac instrukcji  jaka  musimy wstawic,    by  wywalic to
okienko  to EB 14  (  czyli skok przeskakujacy  dialogbox'a ). Co w  takim
razie  trzeba  teraz  zrobic? To  proste,  odwrocic  procke decryptowania,
zacryptowac  nasze  bajty  i   wstawic  pod  orginaly.  Easy...  Odwrocona
procka to:

        sub     al, cl
        ror     al, 3Eh
        sub     al, 25h
        sub     al, 5Eh
        ror     al, 0B9h
        sub     al, 9Eh
        xor     al, 66h
        add     al, cl
        rol     al, 0E4h
        rol     al, 83h
        add     al, cl
        sub     al, 0D0h
        sub     al, cl

Wystarczy teraz podstawic sobie za eax = EB, a za ecx = 1BE2, a za  drugim
razem  eax =  14, a  ecx= 1BE1.  Z tego  wynika nam,  ze nasze  bajty po
zacryptowaniu  wynosza:  4B  D0.  Szukamy  wiec  w  hexeditorze  miejsca z
orginalnymi bajtami ( CC BC CB 64 5D ) i wstawiamy w pierwsze 2 miejsca 4B
D0. Oki, zapisujemy, uruchamiamy i  ... klapa. Prog sie nie  uruchamia. No
tak DiViNE zacryptowal proga  z opcja 'Exit in  the case of bad  CRC'. So,
musimy   poszukac  tego   miejsca.  W   softice,  po   wyjsciu  z   call'a
odpowiedzialnego za decryptowanie naciskamy F12 i po kilku minutach wiemy,
ze skok odpowiedzialny za CRC jest w tym kawalku kodu:

017F:0041745C  0BC0                OR        EAX,EAX
017F:0041745E  740D                JZ        0041746D
017F:00417460  3B85CE274000        CMP       EAX,[EBP+004027CE]
017F:00417466  7405                JZ        0041746D           ; ten skok musi sie odbyc
017F:00417468  E9AF010000          JMP       0041761C           ; bo inaczej exit :)

So, wystarczy podmienic 7405 na EB05. No tak, ale yoda's crypter jest  tak
zrobiony,  ze  czesc kodu  yody  jest takze  zacryptowana.  Jak mozna  sie
domyslec, ta czesc niezacryptowna  jest umieszczona na poczatku  programu.
So, looknijmy:

017F:0041707A  AC                  LODSB
017F:0041707B  F8                  CLC
017F:00417083  04D0                ADD       AL,D0   
017F:00417085  2AC1                SUB       AL,CL   
017F:0041708A  C0C883              ROR       AL,83   
017F:0041708D  C0C8E4              ROR       AL,E4   
017F:00417090  F9                  STC               
017F:00417091  2AC1                SUB       AL,CL   
017F:00417093  3466                XOR       AL,66   
017F:00417095  F8                  CLC               
017F:00417096  049E                ADD       AL,9E   
017F:00417098  C0C0B9              ROL       AL,B9   
017F:0041709E  045E                ADD       AL,5E   
017F:004170A0  F8                  CLC               
017F:004170A1  F8                  CLC               
017F:004170A3  0425                ADD       AL,25   
017F:004170A5  C0C03E              ROL       AL,3E   
017F:004170A8  EB01                JMP       004170AB
017F:004170AB  AA                  STOSB             
017F:004170AC  E2CC                LOOP      0041707A

Oczywiscie troche  ten kod  'odjunkowalem'. Jak  widac to  jest to samo co
wczesniej  z  ta  mala  roznica, ze  pominieta  jest  pierwsza  i ostatnia
instrukcja decryptowania.  Wiec prawie  to samo.  Jak jestesmy  w petli to
zakladamy  bpm  417466 (  offset  naszego skoku  )  i spisujemy  ecx  oraz
orginalne  instrukcje. Co  potem? Przepuszczamy  'EB' przez  nasza procke
cryptujaca, z taka roznica, ze obcinamy pierwsza i ostatnia instrukcje:

        ror     al, 3Eh
        sub     al, 25h
        sub     al, 5Eh
        ror     al, 0B9h
        sub     al, 9Eh
        xor     al, 66h
        add     al, cl
        rol     al, 0E4h
        rol     al, 83h
        add     al, cl
        sub     al, 0D0h

Otrzymany wynik to: E3. Teraz szukamy w exe'ku orginalnych istrukcji (  4C
F9 DA 9C 70  ) i nadpisujemy pierwsza  z nich. Teraz wszystko  powinno juz
dzialac. Uruchamiamy proga i nie  ma juz zadego obrzydliwego nag'a.  Joop,
scracowane :) Spisz sobie jeszcze  poszczegole offsety z hexeditora i  juz
mozesz zrobic cracka.

.eNd

Oki, next crackme pokonane. Mi  osobiscie deser smakowal bardziej niz  sam
obiad  :) Wedlug  mnie pozycja  warta uwagi,  choc wlasciwie  cala procka
sprawdzajaca s/n byla  bardzo prosta. Oki,  chyba koniec tego  smecenia bo
wlasnie wyszlo, ze mam juz  17466 znakow :).  Pozdrowienia dla  wszystkich
ludzi lubiacych ostrzejsze granie i dla wszystkich lubiacych karmic  swoje
uszy Acid Drinkers,  KN, Marilyn'em Manson'em,  Therion'em itd. Jak  masz
jakies uwagi to mailto: Tymon_crk@wp.pl. See ya!

.Ps

www.witeg.prv.pl        // tutaj mozesz znalezc implementacje TEA w asm

.ThaNX to [a..z]:

 ged_ * hauer * Kwasek * snatch * ToMKoL * ved * veneta * WiteG * zakonna
 all from AAoCG & HTBTeam
