Wstęp do crackingu.docx

(251 KB) Pobierz

Wstęp do crackingu

Programy, które likwidują zabezpieczenia w oprogramowaniu, ogólnie nazywa się crackami. Przedstawię dwa sposoby na nielegalne zarejestrowanie aplikacji dla zabezpieczenia, które jest zawarte w programie CrackMe2. Autorem zabezpieczenia jest polski cracker - massh z grupy CookieCrK. Programy tego typu, są pisane przez crackerów, w celu zdobywania doświadczenia. Łamaniem takich programów również zajmują się crackerzy - dla chwały i kasy ;-) Lekcje crackingu często są wstępem, do pisania wirusów ukierunkowanych na określony cel. W tekście skoncentrowałem się na popularnym przed kilkoma latami narzędziu SoftICE, prudukt nie jest już rozwijany, ale równie skutecznym narzędziem jestOllyDBG, który spełni wymagania początkujących crackerów.

http://4.bp.blogspot.com/_R5h8b2tlzK4/TQc3eg2uvNI/AAAAAAAAABI/pYORf-CmtL0/s320/0.PNG



Aby zarejestrować program, należy wpisać nazwę użytkownika (okno edycyjne- user) oraz klucz rejestrujący (okno edycyjne - serial). Dla każdego użytkownika w procesie rejestracji powstaje inny klucz. Zadaniem crackera jest zarejestrowanie programu bez poprawnego klucza rejestrującego lub stworzenie go dla danego użytkownika. Rejestracja bez właściwego klucza wymaga modyfikacji procedury rejestrującej lub całkowitego jej usunięcia. Można tego dokonać, kiedy klucz rejestrujący nie jest jednocześnie kluczem deszyfrującym instrukcje w zabezpieczonej aplikacji. Kiedy w zabezpieczonej aplikacji istnieją zaszyfrowane instrukcje, a kluczem, który je deszyfruje jest wartość wyliczana na podstawie nazwy użytkownika, należ stworzyć generator kluczy.

PIERWSZE KROKI


Nie ma określonego przepisu na cracka, ponieważ każde zabezpieczenie wymaga indywidualnego podejścia. Pierwszym krokiem, jest analiza zabezpieczonej aplikacji, która polega na zebraniu jak najwięcej informacji o programie. Język w jakim został napisany program, format nagłówka wykonywalnego pliku programu, wykorzystywane zasoby zewnętrzne, odwołania do rejestrów systemu oraz do plików to informacje podstawowe ułatwiające dalsze działanie. Najpopularniejszym narzędziem crackera, jest debugger SoftICE, ale gdy zabezpieczona aplikacja jest napisana w języku VisualBasic, to odpowiednim narzędziem będzie program SmartCheck. Format wykonywalnego pliku programu, najczęściej jest to PE (opis według Microsoft ang. Portable Executable), określa, w jaki sposób ułożone są poszczególne sekcje oraz tabele importowanych i eksportowanych funkcji. Najważniejszymi informacjami o zasobach wykorzystywanych przez program, są importowane funkcje. Jeśli program importuje funkcje związane z pomiarem czasu w systemie, można się spodziewać zabezpieczenia w postaci ograniczeń czasowych. Kiedy program odwołuje się do plików i rejestrów systemu jest możliwość, że zapisuje w nich ważne, z punktu widzenia crackera, informacje, takie jak data instalacji, nazwa użytkownika lub klucz rejestrujący. Odwołania do plików i rejestrów wykrywa monitor Process Monitor.
Po zebraniu niezbędnych informacji można przejść do próby złamania zabezpieczenia w pamięci komputera. Najczęściej śledzenie programu w pamięci rozpoczyna się w miejscu gdzie użytkownik podaje klucz rejestrujący. Zastawianie pułapek na wywoływane funkcje jest możliwe dzięki znajomości importowanych zasobów. Dla crackera najważniejsze są funkcje odpowiedzialne za obsługę kontrolek edycyjnych - okienek z miejscem na hasło. O tym czy program zostanie zarejestrowany decydują instrukcje wykonywane po wpisaniu klucza. Cracker musi usunąć, zmodyfikować lub odwrócić funkcję odpowiedzialną za rejestrację.

WSTĘPNA ANALIZA

 

 Ilość informacji jakie można wydobyć z programu, jest bardzo duża. Niewielki rozmiar CrackMe2 wskazuje na to, że program powstał w asemblerze. Przy pomocy programu PE Explorer sprawdzamy, jaki jest format pliku. Uruchamiamy program PE Explorer, w menu File -> Open File wybieramy program CrackMe2 i natychmiast pokazują nam się wszystkie informacja zawarte w nagłówku pliku. Aby obejrzeć importowane funkcje wybieramy menu View -> Imports.

 

http://3.bp.blogspot.com/_R5h8b2tlzK4/TQc_6cLxyeI/AAAAAAAAABM/wBUae63A1Sk/s640/1.PNG

 

http://2.bp.blogspot.com/_R5h8b2tlzK4/TQdBj-t0s6I/AAAAAAAAABQ/mw1a4TUP7Xk/s640/2.PNG

 



Funkcja GetWindowTextA importowana z biblioteki User32.dll, jest to funkcją kopiująca do pamięci tekst z okna edycyjnego. Posłuży ona do zastawienia pułapki na CrackMe2.
Debugger pozwala śledzić instrukcje wykonywane przez procesor, dane zapisywane do pamięci oraz rejestry procesora. Dokładna wiedza o aktualnie wykonywanych przez procesor instrukcjach daje możliwość ingerencji w program. W praktyce najlepiej działa SoftICE 4.05 pod systemem Windows98. W przypadku debuggera SoftICE bardzo ważna jest jego odpowiednia instalacja i konfiguracja. Po zainstalowaniu programu należy otworzyć plik konfiguracyjny winice.dat i poprzez usunięcie średników wybrać biblioteki, z których pobierane są funkcje eksportowane do plików (np.: EXP=c:\windows\system\user32.dll).
Aby była możliwość śledzenia programu w debuggerze SofIce, należy wykonać następujące kroki:
- uruchamiamy CrackMe2 i wpisujemy dowolne dane w oknach edycyjnych.
- wyświetlamy okno debuggera poprzez wciśnięcie klawiszy [Ctrl+d].
- w linii komend wpisujemy bpx GetWindowTextA, komendę zatwierdzamy klawiszem [Enter]. Jest to instrukcja, która spowoduje przerwanie działania programów i przejście procesora w tryb pracy krokowej, w przypadku, kiedy jakiś program wywoła funkcję GetWindowTextA.
- wciskamy klawisz [F5], aby zamknąć okno debuggera.
- wciskamy przycisk [ok] w CrackMe2 i automatycznie pojawia się okno debuggera z zaznaczoną instrukcją. SoftICE pokazuje instrukcje tworzące funkcję GetWindowTextA. Pomiędzy linią komend, a oknem z kodem programu jest nazwa biblioteki, z której pochodzi funkcja. Crackera nie interesuje budowa funkcji, ale parametry jakie zwraca do programu, który ją wywołał.
- wciskamy klawisz [F11], aby znaleźć się w miejscu, z którego funkcja została wywołana. Teraz pomiędzy linią komend i oknem z kodem znajduje się nazwa programu, który wywołał funkcję GetWindowTextA, czyli CrackMe2.
Kolejnym zadaniem crackera jest analiza instrukcji odpowiedzialnych za rejestrację programu.
W listingach, używane są liczby zapisane w postaci szesnastkowej. Znaki oraz cyfry kodowane są według standardu ASCII. Cyfry poprzedzające instrukcje programu, są opkodami instrukcji maszynowych.

LISTING 1

6A1F            PUSH 1F

6824214000      PUSH 00402104

FF354C204000    PUSH DWORD PTR [0040204C]

E81C020000      CALL USER32!GetWindowTextA

85C0            TEST EAX,EAX

744D            JZ 00401260

A360204000      MOV [00402060], EAX

6A1F            PUSH 1F

6824214000      PUSH 00402124

FF3550204000    PUSH DWORD PTR [00402050]

E81C020000      CALL USER32!GetWindowTextA

85C0            TEST EAX,EAX

7432            JZ 00401260


Instrukcje z listingu 1, wykonywane bezpośrednio po wpisaniu danych i wciśnięciu przycisku [ok], są odpowiedzialne, za kopiowanie danych do pamięci. Parametry odkładane na stos, przed wywołaniem funkcji, określają adresy w pamięci gdzie znajdą się dane, długości zmiennych oraz uchwyty do okien edycyjnych. Dzięki temu wiemy gdzie w pamięci szukać nazwy użytkownika oraz klucza rejestrującego. W linii poleceń debuggera wpisz „d 00402104”, to w oknie danych zobaczysz nazwę użytkownika, natomiast po wpisaniu „d 00402124” w oknie danych pojawi się klucz rejestrujący. Wartość 1F hex. jest długością zmiennych i oznacza, że nazwa oraz klucz nie mogą być dłuższe niż 31 znaków. Po skopiowaniu danych do pamięci, następuje sprawdzenie ich długości. Jest to możliwe, ponieważ funkcja, GetWindowTextA zwraca w rejestrze EAX długość skopiowanego ciągu znaków. Jeśli długość, danych jest równa 0, to procedura rejestrująca jest przerywana.
Aby w debuggerze SoftIce wykonywać kolejne instrukcje należy wcisnąć klawisz [F10]. Wciskamy [F10], aż dojdziemy do instrukcji:

E8DF000000     CALL 00401261 

Jest to wywołanie funkcji wewnętrznej programu, z pod adresu 00401261 (adresy również zapisywane są postaci szesnastkowej). Aby zobaczyć instrukcje tworzące funkcję należy wcisnąć klawisz [F8].
Po wejściu do funkcji widzimy:

LISTING 2

A160204000      MOV EAX, [00402060]

390564204000    CMP [00402064], EAX

752F            JNZ 0040129D

33C0            XOR EAX, EAX


Instrukcje z listingu 2, sprawdzają czy długość nazwy użytkownika jest taka sama jak długość klucza rejestrującego. Jeśli długości obu zmiennych są różne wyświetlany jest komunikat o niepoprawnym kluczy rejestrującym. Ostatnia instrukcja zeruje rejestr EAX. Wnioskiem z listingu 2 jest to, że długość klucza rejestrującego musi być taka sama jak długość nazwy użytkownika. 
Kolejnymi instrukcjami procedury rejestrującej są:

8B7C2404     MOV EDI, [ESP+04]
8B742408     MOV ESI, [ESP+08]
 

Pierwsza instrukcja kopiuje do rejestru EDI adres z nazwą użytkownika, a druga do rejestru ESI adres z kluczem rejestrującym.
Instrukcje z listingu 3, są sercem zabezpieczenia. Na ich podstawie będziemy w stanie stwierdzić, w jaki sposób powstaje klucz rejestrujący i jaki wpływ na niego ma nazwa użytkownika.



LISTING 3

0FB61F          MOVZX EBX, BYTE PTR [EDI]

0FB616          MOVZX EDX, BYTE PTR [ESI]

80FA30          CMP DL, 30

7C1A            JL 0040129D

80FA39          CMP DL, 39

7F15            JG 0040129D

80EA30          SUB DL, 30

83E30F          AND EBX, 0F

D0EB            SHR BL, 01

2ADA            SUB BL, DL

7509            JNZ 0040129D

47              INC EDI

46              INC ESI

803F00          CMP BYTE PTR [EDI], 00

75DD            JNZ 00401278

EB04            JMP 004012A1

Do rejestru EBX kopiowany jest pierwszy znak nazwy użytkownika, w rzeczywistości znajduje się on w najmniej znaczącej części tego rejestru, czyli w BL. Do rejestru EDX kopiowany jest pierwszy znak z klucza rejestrującego, również jest umieszczany w najmniej znaczącej części rejestru czyli DL. Kolejne cztery instrukcje są odpowiedzialne za sprawdzenie czy znak klucza jest cyfrą z zakresu 0-9 (wartość 0 jest reprezentowana w standardzie ASCII przez liczbę 30 hex, a cyfra 9 w tym standardzie to 39 hex). Jeśli znak nie jest cyfrą, następuje skok do procedury wyświetlającej okno o niepoprawnej rejestracji. Jak zapewne już zauważyłeś, adres 0040129D kryje za sobą procedurę z informacją, o niepoprawnej rejestracji programu. 

http://3.bp.blogspot.com/_R5h8b2tlzK4/TQdKVljfwHI/AAAAAAAAABU/Ii84twfwCv8/s1600/3.PNG

 
 Kolejna instrukcja odejmuje od pierwszego znaku klucza wartość 30 hex, dzięki temu w rejestrze DL zostają tylko ostatnie cztery bity znaku z klucza. Dzięki instrukcji AND EBX, 0F program nie będzie rozróżniał czy nazwa użytkownika jest napisana wielkimi czy małymi literami, ponieważ instrukcja AND EBX, 0F, usuwa pierwsze cztery bity rejestru BL. W ten sposób w rejestrze EBX znajdują się tylko ostatnie cztery bity znaku nazwy użytkownika. Instrukcja SHR, to operacja przesunięcia bitowego w prawo, jej działanie modyfikuje rejestr BL. Operacja SUB to odejmowanie arytmetyczne. W naszym przypadku oznacza to, że odejmowane są wartości umieszczone w rejestrach BL i DL. Należy pamiętać, że w BL znajduje się to, co zostało ze znaku nazwy użytkownika, a w DL ostatnie cztery bity znaku z klucza.
Kolejna instrukcja jest kluczowa dla procesu rejestracji. Instrukcja JNZ 0040129D to skok do procedury z informacją o niepoprawnej rejestracji. Skok zostanie wykonany tylko wtedy, gdy w rejestrach BL i DL będą różne wartości. Dla nas oznacza to, że odkryliśmy sposób, w jaki powstaje klucz rejestrujący oraz zależność między nim, a nazwą użytkownika. Dzięki temu wiemy jak dla danego użytkownika stworzyć klucz. Każda litera z nazwy użytkownika ma przypisaną cyfrę reprezentującą ją w kluczu rejestrującym. Nie trudno policzyć kolejne cyfry odpowiadające znakom z nazwy użytkownika, ponieważ: np.: litera „b” to w standardzie ASCII - 62 hex. i 0110 0010 binarnie. Instrukcja AND BL, 0F zeruje pierwsze cztery bity, więc otrzymujemy, 02 hex i 0000 0010 binarnie, po przesunięciu bitowym w prawo o jedną pozycję (instrukcja SHR BL, 01) otrzymujemy 0000 0001, czyli cyfrę 1. Aby zamienić tą cyfrę na znak 1 zapisany w standardzie ASCII należy do niej dodać dokładnie tyle ile zostało odjęte od rejestru DL, czyli 30 hex. W rezultacie dla litery „b” otrzymujemy 31 hex, czyli cyfrę 1. Należy pamiętać, że program nie rozróżnia małych i wielkich liter, więc dla litery „B” cyfrą w kluczu również będzie 1. Instrukcja JNZ 0040129D jest decydującą w porównaniu znaków nazwy użytkownika i klucza rejestrującego. Kolejne instrukcje są odpowiedzialne za zwiększenie rejestrów z adresami nazwy użytkownika i klucza oraz za skok do początku listingu 3. W przypadku, kiedy klucz rejestrujący jest poprawny, operacje z listingu 3, są wykonywane tyle razy ile jest znaków w nazwie użytkownika. Przerwanie pętli następuje, kiedy znak klucza nie odpowiada znakowi nazwy użytkownika lub gdy zostały sprawdzone wszystkie znaki nazwy użytkownika. Znakom nazwy użytkownika, przyporządkowane są następujące cyfry klucza:
Dla liter a,A,p,P,q,Q cyfra klucza to 0
Dla liter b,B,c,C,r,R,s,S cyfra klucza to 1
Dla liter d,D,e,E,t,T,u,U cyfra klucza to 2
Dla liter f,F,g,G,w,W,v,V cyfra klucza to 3
Dla liter h,H,i,I,x,X,y,Y cyfra klucza to 4
Dla liter j,J,k,K,z,Z cyfra klucza to 5
...

Zgłoś jeśli naruszono regulamin