P-Programowanie
Tekst
zmniejsz/powiększ
Kolory
jasne/ciemne/kontrast/brak

Dll Injection

Szykuje się artykuł, opisujący wykonanie techniki DLL Injection. Do napisania artykułu przymierzałem się już wiele miesięcy temu, miał być pierwszym dotyczącym reverse engineeringu. Ciągle odwlekałem go na później, ponieważ kiepsko u mnie z czasem, a chciałem napisać go solidnie. Umiejętność wykonania DLL Injection wiele razy przyda Ci się, szczególnie w programach edytujących pamięć innych aplikacji.

Czym jest DLL Injection

Pojęcia DLL Injection nie należy postrzegać dosłownie. W głównej mierze chodzi o uruchomienie dowolnego kodu (napisanego przez nas) w obcym procesie. Wspominam o tym z powodu dostania kilku listów na temat artykułu Wywoływanie funkcji poprzez DLL Injection. Kilka osób było oburzonych faktem, że w artykule dotyczącym DLL Injection posłużyłem się gotowym injectorem, zamiast napisać własny.

DLL Injection (ang. wstrzyknięcie DLL) jest techniką, która pozwala na uruchomienie dowolnego kodu w przestrzeni adresowej innego procesu. Przygotowany przez nas plik DLL wstrzykujemy programem nazywanym injectorem (strzykawka).

dll injection C++

Według mnie, jest to technika bardzo silnie związana z reverse engineeringiem. W większości przypadków wykorzystywana jest do zmiany zachowań innych aplikacji oraz modyfikacji ich funkcjonalności. Idąc dalej tym tropem, należy śmiało stwierdzić, że tę technikę wykorzystuje zdecydowana większość wirusów i innych programów uprzykrzających życie.

Dzięki przeprowadzeniu „ataku” DLL Injection, w obrębie przestrzeni adresowej innego procesu uruchamiamy osobny wątek (ang. thread), zawierający kod naszego autorstwa. Wątek znajdujący się w obcym procesie ma swobodny dostęp do pamięci tego procesu, co za tym idzie może modyfikować wszelkie zmienne oraz wywoływać jego funkcje. Chcąc modyfikować zmienne wystarczy użyć w tym celu wskaźników generycznych, a do wywoływania funkcji wystarczy utworzyć wskaźnik. Schemat DLL Injection metodą CreateRemoteThread wygląda następująco:

  • otwieramy proces OpenProcess w celu uzyskania uchwytu
  • alokujemy w nim kilka bajtów za pomocą VirtualAllocEx aby mieć miejsce na nazwę DLLki
  • w zalokowane miejsce (pkt 2) wpisujemy nazwę pliku DLL funkcją WriteProcessMemory
  • znajdujemy adres funkcji LoadRibrary w przestrzeni adresowej procesu za pomocą GetProcAddress
  • startujemy nowy wątek w procesie jako początek podając mu adres LoadRibrary (pkt 4) a jako argument adres nazwy DLLki  (pkt 2)

Injector może posługiwać się różnymi metodami w celu wstrzyknięcia pliku DLL. W tym artykule opiszę tylko metodę opartą na CreateRemoteThread.

DLL Injection – metoda CreateRemoteThread

Jak wspomniałem, istnieje wiele metod na wstrzyknięcie pliku DLL do innego procesu. Jedną z najbardziej popularnych metod (niestety bardzo wykrywalnych przez antywirusy) jest użycie CreateRemoteThread wraz z funkcją LoadRibrary. Zaletą tej metody jest duża skuteczność i kompatybilność z różnymi wersjami Windowsów (od XP wzwyż). W dużym skrócie polega ona na „zmuszeniu” obcej aplikacji, do wywołania funkcji LoadRibrary, która z kolei wczyta nasz plik DLL.

Pierwszym krokiem jest otwarcie procesu, do którego chcemy wstrzyknąć plik DLL. Zrobimy to za pomocą funkcji OpenProcess w zamian otrzymując uchwyt procesu. Argumentem jaki przyjmuje funkcja jest m.in. PID. Proces należy otworzyć z flagą zapewniającą pełną kontrolę PROCESS_ALL_ACCESS.

dll injection open process

Posiadając uchwyt procesu, możemy przystąpić do alokowania pamięci, potrzebnej do zapisania nazwy pliku DLL. Zrobimy to za pomocą funkcji VirtualAllocEx. Parametrami funkcji są: uchwyt procesu, długość nazwy DLL, flagi MEM_RESERVE|MEM_COMMIT zapewniające rezerwację wirtualnej pamięci wypełnionej zerami (pustej) oraz flaga PAGE_READWRITE zapewniająca możliwość odczytu i zapisu nowego fragmentu pamięci.

Należy pamiętać, że do nazwy pliku DLL należy dopisać NULL kończący C-stringa oraz uwzględnić na niego dodatkowe miejsce. W przypadku podania tylko nazwy pliku DLL, plik musi znajdować się w tym samym katalogu co program, w który wstrzykujemy DLLkę. Możliwe jest oczywiście podanie pełniej ścieżki, wtedy plik DLL może znajdować się w byle jakiej lokalizacji. W takim przypadku wskazane jest użycie GetFullPathName.

dll injection virtualallocex

Do zarezerwowanego miejsca w pamięci wpisujemy nazwę DLLki korzystając z WriteProcessMemory.

dll injection writeprocessmemory

Aby wczytać DLLkę używamy funkcji LoadRibraryA. Jest ona importowana z biblioteki kernel32.dll. Oznacza to, że DLL Injection tą metodą, możemy wykonać tylko do aplikacji importujących kernel32.dll. Na szczęście używa jej prawie każda aplikacja Win32. Aby móc wykorzystać funkcję LoadRibraryA musimy znaleźć jej adres w pamięci procesu, do którego wstrzykujemy DLLkę. LoadRibraryA przyjmuje jako argument wskaźnik na nazwę pliku DLL (dokładniej LPCTSTR czyli const char*).

Adres funkcji znajdziemy używając GetProcAddress z dodatkowym GetModuleHandle:

dll injection LoadRibrary

Wszystko zostało przygotowane do wstrzyknięcia DLL. Ostatnim krokiem jest wystartowanie nowego wątku w procesie posługując się CreateRemoteThread. Jako główną funkcję startową wątku lpStartAddress podajemy adres funkcji LoadRibraryA. Parametrem przekazanym do głównej funkcji nowego wątku lpParameter będzie wskaźnik na nazwę wpisaną funkcją WriteProcessMemory.

dll injection CreateRemoteThread

Wątek startuje i wykonuje się główna funkcja biblioteki DLL. Kompletny kod injectora napisanego w C++ może wyglądać następująco:

 

Jak to zwykle bywa, nie ma w moim kodzie obsługi błędów. Nie umieściłem ich po to aby kod był treściwy i krótki. Należy takową oczywiście dodać.

Komunikacja z DLLką

Plik DLL wstrzyknięty do pamięci innego procesu, nie musi być główną instancją naszego programu. Może pełnić jedynie rolę „modułu” komunikującego się z naszą bazową aplikacją. Do komunikacji pomiędzy naszym programem a naszą DLLką wstrzykniętą do obcego procesu, należy użyć komunikacji międzyprocesowej (ang. IPC). Zazwyczaj w takim przypadku  injector oprócz funkcji wstrzykiwania DLL posiada także interfejs i funkcje dla użytkownika (wysyłające sygnały do wstrzykniętej DLLki poprzez IPC).

ipc C++

Techniki IPC zapewniają możliwość wymiany informacji pomiędzy dwoma aplikacjami poprzez:

  • pliki mapowane w pamięci (ang. file mapping)
  • pamięć współdzieloną (ang. shared memory)
  • semafory (ang. semaphores)
  • łącza (ang. pipes)
  • gniazda (ang. sockets)
  • kolejki komunikatów (ang. message queues)

Więcej na ten temat, ukaże się w osobnym artykule.

Podsumowanie

Istnieją inne metody umożliwiające przeprowadzenie DLL Injection. Najpopularniejsze z nich to:

  • CreateRemoteThread & LoadRibrary (opisana w artykule)
  • CreateRemoteThread & WriteProcessMemory (wstrzyknięcie do CodeCave kodu DLLki, bez wczytywania jej funkcją LoadRibrary)
  • SetWindowsHookEx

Łatwo znaleźć o nich informacje w internecie, przeważnie nie po polsku.

Metoda opisana w artykule działa zarówno na systemach x86 oraz x64. W przypadku wystąpienia błędu ERROR_ACCESS_DENIED o kodzie 0x5 prawie na pewno chodzi o wstrzykiwanie DLLki skompilowanej dla architektury x86 do aplikacji działającej w architekturze x64. Jeżeli skompilujesz DLLke w Code::Blocks x86 nie będziesz wstanie wstrzyknąć jej w żaden program systemowy na Windows7 x64 (kalkulator, notatnik itp).

Kolejną kwestią o której warto wspomnieć są problemy z otwieraniem procesu w trybie PROCESS_ALL_ACCESS. Jeżeli skompilujesz Inector na systemie Vista lub Windows7, nie będziesz w stanie uruchomić go na Windows XP. Aby temu zapobiec należy zdefiniować w Injectorze:

Wynika to z różnic w wielkości flag na poszczególnych systemach, więcej na ten temat można znaleźć na MSDN.

Udostępnij ten artykuł na fejsie lub zostaw komentarz!

Komentarze:

Użytkownik Konrad napisał/a:

30 lipca 2014


Technike Dll injection znam od dawna ale pierwsze słysze o IPC , jak masz jakąś większą wiedze na ten temat to możesz napisać jakiś art :)

Użytkownik Roberik napisał/a:

04 grudnia 2014


Kiedyś szukałem długo o tej komunikacji między injectorem a DLL, nawet pisałem na forach i niczego sie nie dowiedziałem.. a tu prosze :) podane na tacy sposoby komunikacji i jeszcze obiecany poradnik :D z potężnym podkreśleniem na „obiecany” :D

Użytkownik Zeroche napisał/a:

18 lipca 2016


Jak dokładnie podać scieżkę do pliku.dll ? Gdy odpalam injecor nic sie nie dzieje :( Pomimo że mój plik dll Działa pod Innym Injectorem :(

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0

Zachęcam Cię do polubienia bloga na facebooku! Dając lajka wspierasz moją pracę - wszystkie artykuły na blogu są za darmo!