/*****************************************
*    dATE: 08.01.2005                    *
*    tYPE: Tutorial                      *
*      bY: ManSun                        *
*--------------------------------------- *
* pROGRAM: Crackme v1.0 by _Sage_        *
*     uRL: www.crackmes.prv.pl           *
*   tOOLS: SoftICE  (debug)              *
*          IDA      (recompilation)      *
*          MASM32   (keygen)             *          
*   lEVEL: Warrior                       *
*----------------------------------------*
*    iNFO: Hasing Name & Junks           *
*****************************************/ 


>>>[Wstep]<<<
Witam! Ostatnio szukalem jakiegos prostego crackmesa do pukniecia aby  sprawdzic
czy jeszcze cos pamietam czy juz wogole nie potrafie nic zlamac ;). A wiec wlaze
na http://www.crackmes.prv.pl no i jak zwykle wszystko z  aktualizacji  od  razu
polamane (btw. bardzo dziwny zbieg okolicznosci) no ale nic popatrzmy  do dzialu
Uncracked hmm troszke tego jest nikt sie za to nie bierze bo  teraz  modne  jest 
crypto a wiec zassalem Crackme v1.0 by _Sage_ na probe. Rozmiar calkiem  maly  w 
dodatku  nie jest  packniete w About pisze ze wydane 2004-01-01 no to jakby mial
to  ktos  zlamac  to  chyba  dawno  by juz to zrobil wiec do dziela nasz cel to:

"Your task is to make a keygen" -no czyli tak naprawde jest to KeygenMe
Level: Warrior -strach sie bac, ciekawe czy dam rade no ale moze cos zawojuje ;)


>>>[DummyOpcodes & Anty-tools]<<<
Crackme  lapie sie na  bpx GetDlgItemTextA tym API pobierane jest zarowno Name i
Serial. Zaraz po pobraniu Name pod adresem 004010D7 i w dalszym sledzeniu  zycie
beda nam uprzykrzac dwa rodzaje DummyOpcodes lub jak kto woli junkow. Nie ma  co
sie nad nimi dlugo rozwodzic tylko trzeba je ladnie zapatchowac.

[1]
W crackme wystepuje 14 razy mala "skakanka" (junk) ktora troszke  zaciemnia  kod
i ma na celu  utrudnienie  analizy  crackmeska, a  wyglada ona mniej wiecej tak:

00401884 E8 1E 00 00 00       call    004018A7       ;---                (START)
00401889 EB 17                jmp     004018A2       ;<-|--------+---
0040188B E8 08 00 00 00       call    00401898       ;<-|--+---  |  |
00401890 61                   popa                   ;  |  |  |  |  |
00401891 35                   db 35h                 ;  |  |  |  |  |
00401892 3C                   db 3Ch                 ;  |  |  |  |  |
00401893 E8 1B 00 00 00       call    004018B3       ;<-|--|--|--|--|-----+->-
00401898 EB EF                jmp     00401889       ;<-|--|--+--|  |     |  |
0040189A C9                   leave                  ;  |  |        |     |  |
0040189B E8 12 00 00 00       call    004018AE       ;  |  |        |     |  |
004018A0 C3                   retn                   ;  |  |        |     |  |
004018A1 43                   inc     ebx            ;  |  |        |     |  |
004018A2 EB 0A                jmp     004018AE       ;<-|--|--------+->-  |  |
004018A4 0F C1 D0             xadd    eax, edx       ;  |  |           |  |  |
004018A7 E8 DF FF FF FF       call    0040188B       ;<-+---           |  |  |
004018AC 76 05                jbe     004018B3       ;                 |  |  |
004018AE E8 E0 FF FF FF       call    00401893       ;<----------------+->-  |
004018B3 83 C4 14             add     esp, 14h       ;<----------------------+ 
                                                          (END wyrownanie stosu)

Usuniecie tego junka chyba nikomu nie sprawi trudnosci wystarczy spisac
wszystkie  bajty  w jakims  hexedytorze uzyc opcji 'Replace' ze zamiana na NOP'y
(opcod 90) czyli:
(Uwaga techniczna: W "Hiew" mozna zamienic jednoczesnie 20 bajtow,
w "HexWorkshop" 32 bajty. Tak wiec bedzie  trzeba  zrobic to na  kilka razy  lub
uzyc jakiegos odsyfiacza)

Find:    E81E000000EB17E80800000061353CE81B000000EBEFC9E812000000C343EB0A
         0FC1D0E8DFFFFFFF7605E8E0FFFFFF83C414
Replace: 9090909090909090909090909090909090909090909090909090909090909090
         909090909090909090909090909090909090

lub na poczatku junka postawic  skok  ktory go  przeskoczy, a  dodatkowo  reszte
wynopowac (wtedy nie bedziemy musieli wykonywac NOPow podczas sledzenia):

Find:    E81E000000EB17E80800000061353CE81B000000EBEFC9E812000000C343EB0A
         0FC1D0E8DFFFFFFF7605E8E0FFFFFF83C414
Replace: EB30909090909090909090909090909090909090909090909090909090909090
         909090909090909090909090909090909090

Sygnatura wyNOPowania do "ShitHunter'a2" by Lilith
(ktory mozna pobrac z http://ict.xt.pl)

[Sage_01]
JunkSize=0x32
Junk=E8 1E 00 00 00 EB 17 E8 08 00 00 00 61 35 3C E8 1B 00 00 00 EB EF C9 E8 12 
00 00 00 C3 43 EB 0A 0F C1 D0 E8 DF FF FF FF 76 05 E8 E0 FF FF FF 83 C4 14
FillWithSize=0x1
FillWith=90

[2]
Kolejny junk w crackme wystepujacy 6 razy i jest w stylu:

          call   label_1     ;---
          db     _junkcode   ;  |
label_1:  add    esp, 4      ;<-+

jego sygnaturka to:

[CALL_01]
JunkSize=0x9
Junk=E8 01 00 00 00 ?? 83 C4 04
FillWithSize=0x1
FillWith=90

[3]
Crackme  po  pobraniu  Name  wyszukuje  poprzez  nazwe  okna Wdasma i jesli jest 
otwarty to probuje go zamknac. Funkcja szuka okna o nazwie:
'URSoft W32Dasm Ver 8.9 Program Disassembler/Debugger'
Ciekawe czy jeszcze ktos uzywa "W32dasm" skoro lepszym narzedziem jest 
"IDA" i "OllyDbg", a nawet jakby ktos go uzywal to i tak wszyscy  juz dawno maja
go spatchowanego przed tego typu trickami.
(BTW: Nie wiem czy  tutaj  czasem  nie  ma  pomylki  bo ja  mam  wersje  V8.93 i 
naprzyklad dlatego mi nie wykryje Wdasma bo w nazwie mam V8.93 a nie v8.9   ;->)
--------------------------------------------------------------------------------


>>>[Rekompilacja]<<<
Wpadlem na pomysl aby zrobic sobie rekompilacje crackme po to aby ladnie wywalic
junki  i po  to aby  wyripowac  sobie  funkcje do napisania keygena. Ale jak sie
pozniej okazalo gdy usunalem NOPy ze spatchowania, crackme generowalo inne hashe
z Name.  Nie chialo mi szukac dlaczego tak jest wiec je zostawilem. No nic i tak 
sie nam przyda rekompilacja podczas pisania keygena ;)
Rekompilacja to szybki i latwy proces:
-disassemblujemy crackme w IDA  dajemy  "File->Produce file->Create ASm file..."
-wklejamy poszczegolne sekjce do szkieletu aplikacji
-wyciagamy zasoby naprzyklad "ResHacker'em"
-kompilujemy np: MASMem i po zabawie ;)

Nie opisywalem jej dokladnie bo tutoriale na temat rekompilacji mozna znalezc na
http://www.crackmes.prv.pl
Do  tutoriala dolaczylem wszystkie pliki potrzebne do skompilowania rekompilacji
i znajduja sie w katalogu "Recompilation_Sage_Jump_NOPs".
--------------------------------------------------------------------------------


>>>[Analiza procedury sprawdzajacej poprawnosc Seriala]<<<
!!!UWAGA!!!
Crackme analizowalem na podstawie mojej  rekompilacji  tak  wiec wszelkie adresy
kodu i pamieci podawana w dalszej czesci tutka tycza sie pliku  "sage10_rek.exe"
!!!UWAGA!!!

Ponizej  opisalem  bardzo  dokladnie  sposob  dzialania  crackmeska  i procedure 
porownujaca wspiany serial.  Nie  wklejalem fragmentow kodu gdyz zaciemniloby to 
obraz dzialania crackmeska (Gdyby  ktos  sam chcial posledzic crackme to podalem 
adresy wazniejszych miejsc w kodzie i pamieci) a zreszta nikomu do szczescia nie 
jest potrzbny opis co robi kazda linijka kodu. Sam zreszta nie zaglebialem sie w
sposob dzialania  procedur  bo  przy  lamaniu  wazne jest aby zrozumiec co mniej
wiecej robi dana funkcja i  jaki jest schemat  sprawdzania  poprawnosci seriala.

BlackList:
Funkcja pod adresem 00401879 sprawdza czy Name zaczyna sie od slowka "Kufel"  to
jesli tak to BADBOY

Name musi byc >= 7 znakow co  jest sprawdzane  pod adresem 004011EB,  jesli jest
mniejsze   to   wyswietlany   jest  komunikat   "This isn't the correct answer".
A wprzypadku gdy podamy niepoprawny Serial to "You Lose, I Win"

Ja wpisalem do sledzenia:
Name: ManSun I.C.T.
Serial: 1029384756


[1] Hashowanie Name
Na podstawie Name generowane sa dwa 30 znakowe hashe i wartosc
(oznaczmy ja jako X)  obliczona  ze  znakow Name. Dla naszego przykladowego Name 
beda to wartosci:

        /           HASH_1           \
HASH_1: 7hfSmtQHeBfRfyia7o2nJnroUDj6jN

        /   HASH_2A    \/   HASH_2B  \
HASH_2: QLVe2VM9fHaW9gYj3WJFoHXDOdgE7X

Wartosc X: q (czyli 71 hex)

Wazniejsze miejsca!
Code address:
0040120C -procka sprawdzajaca zakres znakow Name
004013AE -procka generujaca HAHS_1
004012B3 -kod odpowiedzialny  za  przekopiowanie HASH_1  w  inna  forme  w  inne
miejsce pamieci. Jest to bardzo wazny fragment kodu gdyz jesli w Name nie bedzie
spacji to zostana  przekopiowwane  jedynie  dwa  znaki  i nie  ma mozliwosci aby 
Serial byl poprawny
0040121D -procka tworzaca HASH_2
004016B4 -obliczenie wartosci ze znakow Name (potrzebne do seriala)

Memory address:
004030C2 -znaki HASH_1
00403005 -znaki HASH_2
004030F3 -obliczona wartosc X ze znakow Name


[2] Deszyfrowanie Seriala
Nastepnie  nasz  wpisany  Serial  jest  deszyfrowywany  (znak  po  znaku) prosta 
funkcyjka  ktora  znajduje  sie  pod adresem  00401765.  Wpisany adres Seriala w 
pamieci to 00403026. Jest to rowniez adres odszyfrowanego Seriala.
Szczerze nie myslac  dlugo jak  ja odwrocic  (bo chyba sie nie da)  postanowilem
zrobic sobie tablice przejsc czyli jaka wartosc odszyfrowana odpowiada wpisanemu
znakowi seriala: 

TABLICA PRZEJSC (pierwszy znak to spacja):
Znak wpisany:       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\
Znak deszyfrowany: WXYZabcdefghijklmnopqrstuvwxyzpo023456789ABCDEFGHIJKLMNOPQRST

Znak wpisany:      ]^_`abcdefghijklmnopqrstuvwxyz{|}~
Znak deszyfrowany: UVWXYZabcdefghijklmnopqrstuvwxyzpo

Oczywisie przy pisaniu keygena tablice przejsc mozna znacznie zmniejszyc poprzez
usuniecie wartosci powtarzajacych sie.
Naszym znakom hasha beda odpowiadaly:

        /           HASH_1           \
HASH_1: 7hfSmtQHeBfRfyia7o2nJnroUDj6jN
Serial: Fjh[ovYPgJhZh<kcFqApRptq]LlElV

        /   HASH_2A    \/   HASH_2B  \
HASH_2: QLVe2VM9fHaW9gYj3WJFoHXDOdgE7X
Serial: YT^gA^UHhPc_HialB_RN?P!LWfiMF!


[3] Porownywanie i postac prawidlowego Seriala
Na podstawie analizowanego kodu  poprawnosci  wpisanego Seriala z hashami z Name 
prawidlowy Serial powinien miec nastepujaca strukture:

F(BSWAP dword(HASH_1)) + HASH_2B + (X zmienna jednobajtowa) + HASH_2A

Oznaczenia:
(a) + oznacza zlaczenie
(b) BSWAP dword(HASH_1) -  oznacza  ze  pobieranych  jest  4  bajty znakow hasha 
    przepuszczanych przez operacje BSWAP (czyli odwrocenie kolejnosci  bajtow) i
    zapisywanych z powrotem w to samo miejsce np: 7hfs -> sfh7
(c) Funckja F -konwertuje hasha w ten sposob ze pobiera znak  z prawej  strony i 
    zapisuje do bufora,  nastepnie  pobiera  znak z lewej  strony  i zapisuje do 
    bufora przed wpisanym znakiem (bardzo ladnie mozna to zrobic na wskaznikach)
    i wykonuje to do momentu  spotkania wskaznika z lewej  strony ze wskaznikiem 
    prawej strony hasha.
    Przykad: ABCDEF -> CDBEAF
              246531    654321
    (Mozna  rowniez  zapisac  w  kolejnosci od 1 od poczatku bufora, a nastepnie 
    dokonac odwrocic tablicy z hashem)

Nasz HASH_1 zostanie skonwertowany na:
7hfSmtQHeBfRfyia7o2nJnroUDj6jN  -HASH_1
Sfh7HQtmRfBeaiyfn2o7ornJ6jDUNj  -BSWAP dword(HASH_1)
yfina2eoB7foRrmntJQ6Hj7DhUfNSj  -Funckja F

Dla naszego przykladowego Name caly Serial to:
                                                        (X zmienna jednobajtowa)
                                                           ^
                                                           |
                /  F(BSWAP dword(HASH_1))  \  / HASH_2B  \ | /   HASH_2A  \
               /                            \/            \|/              \
CipherSerial:  yfina2eoB7foRrmntJQ6Hj7DhUfNSj3WJFoHXDOdgE7XXQLVe2VM9fHaW9gYj
PlainSerial:   <hkpcAgqJFhqZtopvRYEPlFLj]hV[lB_RN?P!LWfiMF!4YT^gA^UHhPc_Hial

Wazniejsze miejsca i kolejnosc porownywania czesci Seriala!
Code address:
004017AE -sprawdzenie poprawnosci HASH_2B
004018D7 -sprawdzenie poprawnosci HASH_1
00401967 -sprawdzenie poprawnosci HASH_2A
0040199E -sprawdzenie poprawnosci wartosci X

Memory address:
004030F3 -prawidlowa wartosc X obliczona ze znakow Name
--------------------------------------------------------------------------------


>>>[Podsumowanie]<<<
A  wiec  podsumowujac,  crackme  jest  calkiem  fajne,  lecz  troszke  dlugie do 
sledzenia. Przynajmniej ja stracilem na niego duzo czasu probujac zrozumiec o co
tu chodzi i jak to jest sprawdzane rzucajac na  prawo i lewo  QRWAMI. Ale  gdyby 
bylo krotsze to nie mialbym radochy z jego zlamania ;-D
Procki  sprawdzajace  sa  przemyslane,  a cala procedura sprawdzajaca poprawnosc 
seriala jest bardzo ciekawa i mi sie podoba ;)
Znajac strukture Seriala napisanie  keygena  nie  jest juz trudnoscia. Miejsca w 
pamieci hashow sa zawsze takie same wiec ja napisalem keygen na podstawie zrodel
z  rekompilacji crackmeska wywalajac niepotrzebny kod i dodajac kod sklejajacy i 
wyswietlajacy seriala.

Jak da sie zauwazyc dla jednego  Name moze byc kilka  prawidlowych Seriali  gdyz
tablica przejsc posiada niektore wartosci powdojnie
np: 'n' odpowiada wartosc '1' lub 'p'.

Rowniez  nie  dla  kazdego  Name  da  sie wygenerowac  Serial, a to poniewaz nie 
ma odpowiadajacej wartosci w tablicy przejsc dla znaku hasha '1' i  tak  np  dla
Name  "ManSun ICT" (wpisane  bez  cudzyslowi)  nie  mozna  wygenerowac  Seriala.

Przykladowe prawidlowe dane to!
Name: ManSun I.C.T.
Serial: <hkpcAgqJFhqZtopvRYEPlFLj]hV[lB_RN?P!LWfiMF!4YT^gA^UHhPc_Hial

Aha  jeszcze  jedno  w  crackme  jest  blad wyrowaniania stosu gdyz po klikniecu
"Try it!" i wyswietleniu komunikatu po jego zaakceptowaniu zglaszany jest  blad!
"The instruction  at 0x77e189ce..."  na  (Win2k  En SP4). Aby wszystko bylo OK w
funkcjach zamiast retn 4 nalezy dac retn 8
    leave
    retn   4  ;<-ERROR powinno byc 8 
--------------------------------------------------------------------------------


>>>[Greetsy]<<<
Greets fly to:
Lilith   -bardzo ladny i zrozumialy tut do  mojego crackmeska "ICT Trial Level1"
shield   -niezly pomysl na rozwalanie junkow ;)
_TeStON_ -What's up baby? Your skills are great
YOU!     - ;->

W przypadku jakis uwag lub niejasnosci pisz na mansun[at]o2.pl
-----------------------------------------------------------------------------EOF