P-Programowanie

CodeCave

Ostatania modyfikacja: 28 września 2017, kategoria: C++

Każda uruchomiona aplikacja posiada swoją pamięć (pamięć procesu). Technika DllInjection pozwala programiście na „wstrzyknięcie” kodu do uruchomionego procesu, dzięki czemu można poszerzyć go o nowe funkcje lub wywoływać istniejące funkcje procesu w dowolnym momencie. Jedną z wielu metod wstrzykiwania kodu jest korzystanie z codecave.

Codecave – jest to nieużywana pamięć uruchomionej aplikacji, do której można wstrzyknąć dowolny kod a następnie wykonać go.

Zaprezentuję prosty przykład działania codecave. Potrzebny będzie edytor pamięci np. CheatEngine oraz debbuger OllyDbg. Co prawda istnieją inne debbugery, nawet CheatEngine posiada swój wbudowany, jednak możliwości OllyDbg przerastają wszystkie inne programy tego typu. Jak wspomniałem w innym artykule, nie trzeba umięć programować w Asm jednak trzeba znać jego najważniejsze rozkazy.

Zbieranie informacji

Naszym zadaniem będzie taka modyfikacja kodu Sapera, aby po zmniejszeniu ilości min (licznik po lewej stronie) wyskakiwał komunikat z informacją.

sp1

Utwórz kopię gry Saper i wklej ją do jakiegoś folderu. Kopię pliku nazwij ‚saper.exe’ i uruchom. Otwórz program CheatEngine i wczytaj proces sapera. Musimy odczytać adres zmiennej przechowującej aktualną ilość min, czyli 10.

Wierzę, że umiesz to zrobić, zostało to opisane w artykule „edycja pamięci procesów”. Znaleziony przeze mnie adres to 1005194, Twój może się różnić jeżeli posiadasz inną wersję gry.

Posiadając adres zmiennej przechowującą ilość min, pozostaje nam znaleźć adres funkcji, która modyfikuje ilość min. Adres zmiennej a adres funkcji to zupełnie inne nie powiązane ze sobą wartości. Aby znaleźć adres funkcji klikamy na adres 1005194 prawym przyciskiem myszy i a następnie na pozycję Find out what writes to this address.. Pokaże się komunikat informujący o konieczności użycia debbugera, klikamy „yes”. Został ustawiony breakpoint (pułapka) na adres zmiennej przechowującej ilość min, uaktywni się w momencie zapisania nowej wartości do zmiennej. Można także ustawiać pułapkę na odczytywanie informacji z pod adresu.

Pułapka (breakpoint) – ustawia się ją za pomocą debbugera na określony adres w pamięci. Pułapki ustawia się na zapis lub odczyt z adresu. Pułapka przerywa działanie programu w momencie użycia zmiennej na którą została ustawiona, pozwalając programiście analizować kod.

Po ustawieniu pułapki na zapis, musimy sprawić aby szukana funkcja zapisała nową wartość do naszego adresu. Klikamy prawym przyciskiem myszy na dowolnym polu w saperze, ustawi to flagę na pole i zmniejszy ilość min o 1. Oznacza to że szukana przez nas funkcja będzie musiała nadpisać zmienną z ilością min nową wartością. Na liście instrukcji powinna pojawić się taka pozycja:

sp2

Na czerwono zaznaczyłem adres szukanej funkcji, następnie widoczne są wartości odpowiadające heksadecymalne naszej funkcji, na razie nas to nie interesuje. Rozkaz ADD jest odpowiedzialny za arytmetyczne dodawanie wartości, w tym wypadku dodawana jest wartość rejestru EAX do zmiennej wyświetlającej ilość naszych min (kolor zielony).

Podsumowując, posiadamy dwa adresy:

1005194 – adres zmiennej z ilością min

100346E – adres funkcji edytujący zmienną z ilością min

Wstrzykiwanie kodu do gry Saper

Uruchom OllyDbg a następnie przeciągnij i upuść do niego plik ‚saper.exe’. Program wyświetlił nam kod maszynowy Sapera w języku Assembler. Aby wstrzyknąć kod musisz znaleźć wolny obszar pamięci który nie jest używany (codecave), czyli taki który nie jest wypełniony żadnymi instrukcjami asma. Wolny obszar pamięci to DB 00, czyli po prostu bajt 0. Puste instrukcje oznacza również NOP (ang. No operation) ale są one wykorzystywane w środku kodu i nie tworzą codecave.

Musisz znaleźć obszar wolnych bajtów, ja znalazłem na końcu programu (adres 01004A56). Wygląda to tak:

ol1

Wolne bajty widoczne wyżej nadpiszemy własnym kodem, następnie zamiast wywołania funkcji zmieniającej ilość min wywołamy nasz kod. Nasz kod wyświetli MessageBox, uaktualni ilość min a na końcu wykona skok do miejsca gdzie powinna znajdować się oryginalna funkcja. Koncepcja prezentuje się następująco:

ol2

Zajmijmy się treścią komunikatu. Zaznaczamy około 15 linii w codecave (jedna linia to jeden rozkaz to jeden bajt i jedna litera). Następnie klikamy prawym przyciskiem myszy na zaznaczeniu i wybieramy z menu ‚Binary > Edit‚ (lub CTRL+E). Pokaże się okienko, wpisujemy tam treść komunikatu. Klikamy OK. Naciskamy na klawiaturze skrót CTRL+A, dzięki temu debbuger przetworzy sobie kod.

ol3

Zapiszmy tytuł komunikatu, znów zaznaczamy dowolną ilość linii, edytujemy i wpisujemy tytuł. Klikamy OK a następnie na klawiaturze skrót CTRL+A. Teraz zajmiemy się wyświetlaniem komunikatu. Struktura funkcji wygląda następująco:

Funkcja przyjmuje 4 parametry, z czego pierwszy może wynosić 0 i ostatni 0 (struktura dostępna i opisana na MSDN, pamiętaj że wartości na stos trafiają w odwrotnej kolejności niż mówi o tym struktura funkcji). Przejdź do dowolnej pustej linii i kliknij dwukrotnie. Pokaże się okienko do wpisania instrukcji. Pierwszym argumentem może być 0, więc dodajemy 0 do stosu wpisując w okienku PUSH 0. Drugim parametrem jest tytuł więc dodajemy do stosu adres (pierwsza kolumna) pod jakim zapisaliśmy wcześniej tytuł komunikatu, u mnie jest to adres 1004A67. Wpisz w okienku PUSH (adr_tytuł_komunikatu) np. PUSH 1004A67. Na stos dodajemy jeszcze adres treść komunikatu oraz parametr czwarty czyli 0. Na końcu dodajemy rozkaz call user32.MessageBoxA – wywoła on komunikat. Całość powinna wyglądać tak:

ol4

Różowymi strzałkami zaznaczyłem adresy treści komunikatu oraz tytułu komunikatu u Ciebie wszystkie adresy prawdopodobnie będą inne. Zapisz adres strzałki niebieskiej, wskazuje ona początek naszego kodu.

Naciśnij CTRL+G, otworzy się okienko pozwalające przenieść się pod dowolny adres. Wpisujemy tu adres naszej funkcji odpowiedzialnej za zapisywanie ilości min do zmiennej. Adres tej funkcji to: 100346E. Skopiuj i zapisz w notatniku 4 linijki począwszy od początku funkcji pod którą przeniósł Cię debugger. Zauważ, że debbuger zaznacza funkcje czarną klamerką po lewej stronie. Widać, że funkcja zaczyna się pod adresem 0100346A a kończy na 01003479. U mnie są to linijki:

ol8

Kliknij dwukrotnie na pierwszą linijkę funkcji w debbugerze (adres 0100346A). Pojawi się okienko pozwalające edytować istniejący rozkaz. Zastąp MOV EAX,DWORD PTR SS:[ESP+4] skokiem do naszego kodu czyli JMP 1004A6F (u ciebie adres jest inny i miałeś go zapisać! spójrz na poprzedni obrazek!). Teraz zamiast funkcji nadpisującej ilość min program wykona skok do naszego kodu, który wyświetli komunikat.

ol5

Zauważ, że zostały dodane automatycznie rozkazy „NOP”. Zapisz adres ostatniego z nich na boku (u mnie 1003473, widać na obrazku). Kliknij na pierwszą czerwoną linijkę (rozkaz JMP) i naciśnij ENTER. Zostałeś przeniesiony do naszego kodu. Zauważ, że zamiast wywołania funkcji nadpisującej ilość min, wywoływany jest skok na nasz kod w codecave. Oznacza to że ilość min przestanie być aktualizowana. Musimy naprawić aktualizację min czyli wywołać oryginalną funkcję, którą zastąpiliśmy skokiem (obrazek wyżej). Kazałem zapisać Ci 4 pierwsze linijki przed nadpisaniem funkcji, teraz będą nam one potrzebne. Pierwsze dwie nadpisane linijki to:

Pierwsza linijka (rozkaz MOV) dodaje do rejestru wartość ze wskaźnika stosu SS:[ESP+4]. Druga linijka odpowiedzialna jest za dodanie wartości z rejestru do zmiennej wyświetlającej ilość min. Jest to właśnie sedno naszej funkcji modyfikującej ilość min (pamiętasz adres 0100346E z 1 części artykułu?). W naszym kodzie po wywołaniu komunikatu (CALL user32.messageboxa) znajduje się puste pole (DB 00). Kliknij na nie dwukrotnie i wklej rozkaz „MOV EAX,DWORD PTR SS:[ESP+4]”, następnie w nowej linii wklej „ADD DWORD PTR DS:[1005194],EAX”, dzięki temu licznik min odzyska swoją funkcjonalność. Następnie w kolejnej linii wykonaj skok na instrukcję „NOP” (obrazek wyżej), której adres przed chwilą zapisałeś (u mnie 1003473). W tym celu wpisz w okienku „JMP 1003473” i kliknij OK. Cały nasz dodatkowy kod powinien wyglądać tak (Ty masz inne adresy):

ol6

Klikamy prawym przyciskiem myszy w głównym oknie a następnie ‚Coppy to executable > All modyfications’. Wyskoczy nowe okienko. W nowym okienku kliknij prawym przyciskiem myszy a następnie ‚Save File’ i zapisz plik pod dowolną nazwą.

Uruchom nowo zapisany plik. Teraz przy każdej zmianie ilości min powinien ukazać się komunikat. Jeżeli się nie ukazuje, oznacza że popełniłeś błąd.

ol7

Użytkownik CodeCave napisał:

19 sierpnia 2012


Świetny art jak i strona pozdrawiam.

PS: Teraz mogę się pobawić:).

Użytkownik Karol napisał:

05 stycznia 2013


W razie wzrostu zainteresowania, mogę napisać więcej artykułów o takiej tematyce.

Użytkownik Arek napisał:

23 stycznia 2013


Artykuły po prostu zajebiste. Mógłbyś napisać art jak wywoływać funkcje ze wstrzykniętej DLL? Obecnie, robie to poprzez PIPEs (dość prowizorycznie, ale IPC jest dla mnie tematem tabu).

Użytkownik Karol napisał:

27 stycznia 2013


Napiszę coś na ten temat po sesji :)

Użytkownik Maciek napisał:

11 kwietnia 2014


Świetna strona, wszystko zrozumiale napisane.
Fajnie gdybyś napisał coś o WinSock, np jak zrobić prostą aplikacje klient-serwer ;)

Użytkownik Patryk napisał:

05 grudnia 2014


Świetny artykuł! Są jeszcze jakieś ciekawe fajne debuggery pod Windowsa? Polecisz jakieś książki o podstawach praktycznych RE?

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0