P-Programowanie

Subclassing i zwiększanie funkcjonalności aplikacji

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

Kolejny artykuł dotyczący ingerencji w aplikacje trzecie, opisujący podstawową technikę zwiększania funkcjonalności innych procesów. Głównym wątkiem który poruszę, będzie zastosowanie subclassingu w połączeniu z dll injection. Jak zwykle na ruszt weźmiemy grę Saper dostępną w systemie Windows XP.

Działanie aplikacji Windows

Zanim opiszę subclassing wspomnę trochę o zasadzie działania programów napisanych dla systemu Windows. Wszystkie programy składają się ze zbioru kontrolek i form. Mają one różne cechy i nazwy. Każdą kontrolkę identyfikuje jej unikalny uchwyt nazywany hwnd. Jest on potrzebny wielu funkcjom WinAPI operującym na tychże kontrolkach.

Podczas używania wszelkich kontrolek generowane są różne komunikaty. Aby program (czyli zbiór form i kontrolek) mógł komunikować się z systemem, potrzebna jest obsługa tych komunikatów. Komunikaty wysyłane przez kontrolki zostają przechwytywane przez pętlę komunikatów. Pętla komunikatów jest po prostu zwykłą pętlą while, odbierającą wiadomości od kontrolek zawartych w programie. Komunikaty są odbierane za pomocą specjalnych funkcji WinApi i kierowane do procedury okna.

Procedura obsługi okna jest specjalną funkcją, która zapewnia obsługę komunikatów dostarczanych przez pętlę komunikatów. Funkcja posiada kilka argumentów dzięki którym możemy odróżniać komunikaty i sprawdzać ich treść.

Oto opis argumentów:

  • Hwnd -unikalny uchwyt kontrolki od jakiej przyszedł komunikat
  • Message – wiadomość jaka została wysłana przez kontrolkę
  • wParam i lParam – zawierają parametry charakterystyczne dla wysłanej wiadomości (np. współrzędne kursora)

Najlepszą dostępną dokumentacją dotyczącą WinAPI i komunikatów jest oczywiście strona msdn.microsoft.com. W końcu to oni najlepiej powinni wiedzieć, jak działa to co stworzyli.

Na przykład, spójrzmy na komunikat WM_COMMAND. Jak wynika z dokumentacji jest on wysyłany przez opcje menu oraz przyciski na formie. W zmiennej wParam znajduje się  ID kontrolki lub opcji menu. lParam dla kontrolki zwraca uchwyt dla jej okna, a dla pozycji menu zwraca 0.

Przykładowy szkielet procedury obsługi okna wygląda następująco:

Zauważ, że w procedurze obsługi okna powyżej obsłużyliśmy tylko 2 komunikaty. Rodzajów komunikatów są setki, odpowiadają za każdą operację związaną z programem (nawet za „namalowanie” okna). Gdybyśmy chcieli obsłużyć wszystkie komunikaty kod stałby się niesamowicie długi. Z tego powodu przy wyjściu z funkcji, przekazujemy argumenty do domyślnej procedury okna za pomocą funkcji DefWindowProc. Nie jest to konieczne, ale za to bardzo wygodne. Jest ona odpowiedzialna za standardową obsługę komunikatów w domyślny sposób.

Inna postać procedury okna

W większości przykładów w internecie, spotkasz nieco inną postać procedury obsługi okna. Przeważnie na końcu zwraca ona returnem wartość 0, a wywołanie domyślnej procedury okna znajduje się w switchudefault. Wygodniejsza dla nas będzie powyższa postać.

Czym jest subclassing?

Subclassing polega na zmianie wskaźnika do procedury obsługi okna. Wskaźnik ten jest zapisany w strukturze WNDCLASS.

Subclassing jest niczym innym jak po prostu zamianą domyślnej procedury okna. Zamiany można dokonać za pomocą funkcji SetWindowLong z parametrem GWL_WNDPROC. Ogólnie rzecz biorąc nic ciekawego, ponieważ zmienić procedurę obsługi okna możemy tylko dla procesu, w obrębie wykonywanego wątku.

Ciekawy efekt można uzyskać po połączeniu subclassingu z techniką dll injection. Funkcja SetWindowLong zwraca wskaźnik na poprzednią procedurę okna. Dzięki temu powstaje ciekawe narzędzie przypominające hookowanie funkcji. Możemy śledzić parametry interesujących nas komunikatów, zmieniać je, lub w ogóle nie dopuścić do wykonania poszczególnych funkcji.

Subclassing i menu

Wstrzykiwać DLL będziemy standardowo za pomocą programu Winject. Po wstrzyknięciu pliku DLL poszerzymy menu o kilka pozycji. Następnie utworzymy własną procedurę okna, aby móc obsłużyć komunikat WM_COMMAND.

Zmodyfikowaliśmy menu, dodaliśmy do niego jedną pozycję. ID menu to 1234, a więc w procedurze obsługi okna musimy obsłużyć WM_COMMAND właśnie dla tego ID.

subclassing

W naszej nowej procedurze okna spróbujmy obsłużyć istniejące już elementy menu (np. po to aby zmienić ich funkcjonalność). W tym celu potrzebujemy ich ID. Można go zdobyć na kilka sposobów, najłatwiejszym z nich jest program Resource Hacker. Podejrzymy w nim budowę menu:

subclassing

ID pozycji „nowa gra” to 510. Obsłużmy komunikat WM_COMMAND w naszej procedurze obsługi okna:

Zauważ, że po funkcji MessageBox znajduje się wyjście z funkcji (return 0). Oznacza to, że po kliknięciu w menu „nowa gra”, nie zostanie wywołana oryginalna procedura obsługi okna Sapera, z tego też powodu nie możliwe stanie się rozpoczęcie nowej gry.

Subclassing i okienka

Spróbujmy pójść dalej tropem subclassingu. Modyfikacja menu nie dostarcza nam zbyt wielu funkcjonalności. Fajnym pomysłem może okazać się stworzenie nowego okienka, oczywiście otwieranego w obrębie procesu Sapera (a nie jako osobny program).

Stworzenie najprostszego okna dialogowego wymaga następujących kroków:

  • wypełnienie struktury WNDCLASSEX
  • rejestracja klasy funkcją RegisterClassEx()
  • utworzenie okienka za pomocą funkcji CreateWindowEx()

Okienko zostanie wyświetlone po kliknięciu dodanej przez nas pozycji menu. Po utworzeniu dialogboxa tworzymy odpowiednie kontrolki. Kilka etykiet, przycisk i timer. Etykiety będą wyświetlały aktualne informacje pobrane z pamięci, przycisk będzie odpowiadał za reset aktualnego czasu. Timer będzie odświeżał informacje i za pomocą SendMessage wyświetlał je na etykietach.

Niezbędne będzie odczytywanie wartości odpowiednich adresów w pamięci, a także ich modyfikacja. Ponieważ po wykonaniu Dll Injection będziemy znajdować się w wątku w obrębie procesu gry, nie będziemy używać Read/WriteProcessMemory. Będziemy modyfikować pamięć posługując się wskaźnikami generycznymi.

 

Zauważ, że okno dialogowe, posiada swoją własną procedurę obsługi okna. Oto efekt po wstrzyknięciu DLLki do pamięci Sapera:

subclassing dll injection

Użytkownik Dylan Hunt napisał:

05 stycznia 2014


Wszystko ładnie i pięknie opisane.
Trafiłem tu przypadkiem i chyba zostanę dłużej podoba mi się cały artykuł jak i wygląd strony.

Pozdrawiam.

Użytkownik Demolish napisał:

04 marca 2014


Więcej takich artykułów o reverse engineering ;) Bardzo ciekawe!

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0