OE PowerTool 4.5.5
Twój adres IP to: 18.97.14.90
Przeglądarka: CCBot/2.0 (https://commoncrawl.org/faq/)
Załadujmy więc crackme do debuggera. Wciskamy F9 aby przeskoczyć na początek kodu programu (adres 0x00401000).
Wciskamy F9 jeszcze raz, aby uruchomić program.
Lecz co się okazuje? Crackme posiada zabezpieczenie przed reversowaniem za pomocą debuggera. Na szczęście jest to proste crackme i możemy sobie z tym zabezpieczeniem
poradzić dosyć łatwo. Realizowane jest ono za pomocą wywołania funkcji IsDebuggerPresent.
Normalnie funkcja ta zwraca zero, jednak gdy proces wywołujący działa pod kontrolą debuggera, funkcja zwraca wartość niezerową. Wartość zwracana jest standardowo,
przez rejestr EAX. Musimy więc sprawić, że w EAX będzie zero, nawet pod debuggerem. Przeglądając kod crackme (jest bardzo krótki, więc można ręcznie) widzimy, że funkcja IsDebuggerPresent jest wołana dwa razy:
raz z adresu 0x0040131A, a raz z 0x004013AF. W tych dwóch miejscach musimy więc zasymulować brak obecności debuggera. Aby program działał tak, jakby debuggera nie było,
trzeba wyzerować rejestr EAX. Można to zrobić np. instrukcją
XOR EAX, EAX
Ustawiamy więc kursor pod adresem 0x0040131A i wciskamy spację
Wpisujemy instrukcję, klikamy Assemble a następnie Cancel. OK, program mamy już spatchowany w jednym miejscu. Wykonujemy więc jeszcze taką samą operację dla adresu
0x004013AF.
Teraz można już przystąpić do analizy generowania hasła. Dla ułatwienia podzieliłem ją na punkty.
1. Program zaczyna się standardowo od adresu 0x00401000. Na początku skacze pod adres 0x00401017, gdzie znajduje się
kod wczytujący stringi i tworzący okienko.
2. Okienko tworzone jest funkcją DialogBoxIndirectParam. Ma ona parametr lpDialogFunc, który określa funkcję
przetwarzającą komunikaty okna. Tutaj jest ona pod adresem 00401308.
3. Procedura okna przetwarza przychodzące komunikaty. M.in. inicjalizuje wygląd okna w zależności od tego,
czy został wykryty debugger. Reaguje także na kliknięcie przycisku. Sygnalizowane jest to komunikatem WM_COMMAND.
Odpowiada mu liczba 0x111. Parametry są przekazywane do procedury przez stos. Dlatego możemy się do nich odwoływać
względem rejestru EBP:
5. Liczba znaków hasła jest przez funkcję GetDlgItemTextA zwracana przez rejestr EAX. Program kopiuje tę wartość
do rejstru EBX, a następnie dodaje do niej 0x3C (60 dziesiętnie). W ten sposób dla hasła 5-znakowego otrzymamy liczbę
65, które odpowiada litera A. Dla 6-znakowego będzie to liczba 66 czyli litera B, itd. Wynikowa litera zapisywana
jest na pierwszej pozycji generowanego ciągu.
6. Wpisane przez użytkownika hasło trafiło pod adres 0x00403144. Widzimy, że program ładuje do EBX wartość spod adresu
0x00403146, a więc trzeci znak hasła. Dodaje do niego 0x31, czyli 49 dziesiętnie. Patrząc na tablicę ASCII widzimy,
że taka operacja może np. zamieniać kolejne cyfry na litery, czyli cyfrę 0 (w sensie znaku ASCII reprezentującego
zero, mającego wartość 0x30, dziesiętnie 48) na literę a (znak o kodzie 0x61, dziesiętnie 97).
7. Następnie ładowana do EBX jest wartość spod adresu 0x00403148, czyli piąty znak hasła. Od tej wartości odejmowane
jest 0x0A, czyli 10. Czyli trzeci znak hasła musi być o 10 mniejszy od piątego.
8. W kolejnym kroku do pierwszego znaku dodawane jest 0x20. Jeśli znakiem jest litera, to z tabeli ASCII widzimy, że
dodanie 0x20 powoduje zamianę wielkiej litery na małą.
9. Potem analogicznie od szóstego znaku odejmowane jest 0x22 aby otrzymać znak piąty.
10. Szósty znak otrzymywany jest przez odjęcie 5 od drugiego znaku hasła. Następuje więc tu pewna zmiana, podczas
gdy znaki 2-5 ciągu były generowane względem wpisanego hasła, znaki 6-8 generowane są na podstawie znaków ciągu.
11. Siódmy znak otrzymywany jest przez odjęcie 0x28 od znaku szóstego.
12. Przy ósmym znaku widzimy, że od znaku siódmego odejmowane jest pięć, jednak wynik tej operacji nie jest używany.
Do pamięci wpisywana jest po prostu liczba zero, która powoduje zakończenie ciągu.
13. Możemy więc generowanie hasła przedstawić w postaci następującej tabelki, gdzie X - wpisane hasło, Y - ciąg generowany
przez crackme i porównywany z hasłem. Jako że liczymy znaki, pozwoliłem sobie indeksować od 1.
Y[1] = len(X) + 0x3C, np. litera C dla siedmioznakowego hasła
W ten oto sposób złamaliśmy hasło analizowanego crackme :)