Czym jest DLL Injection

Podobne dokumenty
Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Wyjątki (exceptions)

Praktycznie całe zamieszanie dotyczące konwencji wywoływania funkcji kręci się w okół wskaźnika stosu.

DLL Injection. Przejęcie kontroli nad procesem

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

Utworzenie pliku. Dowiesz się:

Zasady programowania Dokumentacja

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

C++ - [1-3] Debugowanie w Qt Creator

Programowanie w C++ Wykład 9. Katarzyna Grzelak. 14 maja K.Grzelak (Wykład 9) Programowanie w C++ 1 / 30

public: // interfejs private: // implementacja // składowe klasy protected: // póki nie będziemy dziedziczyć, // to pole nas nie interesuje

Jak Windows zarządza pamięcią?

Jak napisać listę jednokierunkową?

Znajdywanie adresu funkcji z parametrami

Materiał. Typy zmiennych Instrukcje warunkowe Pętle Tablice statyczne Funkcje Wskaźniki Referencje Tablice dynamiczne Typ string Przeładowania funkcji

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Ćwiczenie 4. Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1.

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Technika mikroprocesorowa. Systemy operacyjne czasu rzeczywistego

Aplikacja Sieciowa wątki po stronie klienta

Zadania: 1. Funkcja przeliczająca F na C: float FtoC(float f){ return (f 32.0) * 5.0 / 9.0; }

Tworzenie projektu asemblerowego dla środowiska Visual Studio 2008.

Podstawy języka skryptowego Lua

Assembler w C++ Syntaksa AT&T oraz Intela

Instytut Teleinformatyki

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

1 Pierwsze kroki w C++ cz.3 2 Obsługa plików

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Necurs analiza malware (1)

Poniższe funkcje opisane są w 2 i 3 części pomocy systemowej.

Programowanie obiektowe

Przez F(C) oznaczamy figurę narysowaną w kartezjańskim układzie współrzędnych, która ograniczona jest przez:

Wprowadzenie do projektu QualitySpy

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 6. Karol Tarnowski A-1 p.

Ok. Rozbijmy to na czynniki pierwsze, pomijając fragmenty, które już znamy:

Programowanie - wykład 4

2.4 Dziedziczenie. 2.4 Dziedziczenie Przykłady programowania w C - kurs podstawowy

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Czym są właściwości. Poprawne projektowanie klas

Logiczny model komputera i działanie procesora. Część 1.

Wprowadzenie do programowania i programowanie obiektowe

Wstęp do programowania. Wykład 1

Programowanie Obiektowo Zorientowane w języku c++ Przestrzenie nazw

5.2. Pierwsze kroki z bazami danych

Czym jest całka? Całkowanie numeryczne

Od uczestników szkolenia wymagana jest umiejętność programowania w języku C oraz podstawowa znajomość obsługi systemu Windows.

Wstęp do programowania

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

RPC. Zdalne wywoływanie procedur (ang. Remote Procedure Calls )

Wstęp do Programowania, laboratorium 02

Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1. Kraków 2013

Cwiczenie nr 1 Pierwszy program w języku C na mikrokontroler AVR

[1/15] Chmury w Internecie. Wady i zalety przechowywania plików w chmurze

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Aplikacja Sieciowa. Najpierw tworzymy nowy projekt, tym razem pracować będziemy w konsoli, a zatem: File->New- >Project

Wskaźniki w C. Anna Gogolińska

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 21 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 24

Programowanie w języku C++

Instytut Teleinformatyki

Pytania sprawdzające wiedzę z programowania C++

Tak przygotowane pliki należy umieścić w głównym folderze naszego programu. Klub IKS

5. Model komunikujących się procesów, komunikaty

Od uczestników szkolenia wymagana jest umiejętność programowania w języku C oraz podstawowa znajomość obsługi systemu Linux.

Rodzina protokołów TCP/IP. Aplikacja: ipconfig.

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Forte Zarządzanie Produkcją Instalacja i konfiguracja. Wersja B

Kancelaria Prawna.WEB - POMOC

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Tablice. Monika Wrzosek (IM UG) Podstawy Programowania 96 / 119

8. Generowanie raportów

Wstęp do informatyki- wykład 11 Funkcje

Podstawy programowania skrót z wykładów:

Inwentarz Optivum. Jak wykorzystać kolektor danych do wypełniania arkuszy spisowych?

ZASADY PROGRAMOWANIA KOMPUTERÓW

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania. Programowanie systemów informatycznych laboratorium. Ćw. 3: Akwizycja danych. RS 232 cd.

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Wstęp do informatyki- wykład 9 Funkcje

Maple i wykresy. 1.1 Najpierw należy się zalogować. Jak to zrobić zostało opisane w moim poprzednim tutorialu.

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

Lekcja 10. Uprawnienia. Dołączanie plików przy pomocy funkcji include() Sprawdzanie, czy plik istnieje przy pmocy funkcji file_exists()

Wielozadaniowość w systemie Microsoft Windows

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Materiał Typy zmiennych Instrukcje warunkowe Pętle Tablice statyczne Wskaźniki Tablice dynamiczne Referencje Funkcje

Adam Kotynia, Łukasz Kowalczyk

Programowanie na poziomie sprzętu. Programowanie w Windows API

Podstawy programowania w C++

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE

Tytuły Wykonawcze. Opis systemu tworzenia dokumentacji TW-1

Języki i metodyka programowania. Wprowadzenie do języka C

Prezentacja systemu RTLinux

1 Wskaźniki. 1.1 Główne zastosowania wskaźników

Pliki. Operacje na plikach w Pascalu

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 5. Karol Tarnowski A-1 p.

Budowa i generowanie planszy

Listy powiązane zorientowane obiektowo

Rozpoznawanie obrazu. Teraz opiszemy jak działa robot.

Rozpocznijmy ten odcinek od rozwiązania problemu postawionego w poprzednim odcinku:

Transkrypt:

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). 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 Karol Trybulec p-programowanie.pl 1

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. Karol Trybulec p-programowanie.pl 2

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. Do zarezerwowanego miejsca w pamięci wpisujemy nazwę DLLki korzystając z 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: 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. Karol Trybulec p-programowanie.pl 3

Parametrem przekazanym do głównej funkcji nowego wątku lpparameter będzie wskaźnik na nazwę wpisaną funkcją WriteProcessMemory. Wątek startuje i wykonuje się główna funkcja biblioteki DLL. Kompletny kod injectora napisanego w C++ może wyglądać następująco: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <windows.h> using namespace std; int main() { HANDLE HProc; LPVOID LibAddr, DllAdr; char Dll[9] = "dll.dll\0"; //pid aplikacji do ktorej wstrzykujemy DLLke DWORD pid = 5816; // otwieramy proces HProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // alokujemy pamiec i zapisujemy adres DllAdr = (LPVOID)VirtualAllocEx(HProc, NULL, strlen(dll), MEM_RESERVE MEM_COMMIT, PAGE_READWRITE); // wpisujemy nazwe dllki do pamieci WriteProcessMemory(HProc, (LPVOID)DllAdr, Dll,strlen(Dll), NULL); // szukamy adresu LoadRibraryA i zapisujemy go LibAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); // startujemy watek podajac adres do LoadRibraryA // oraz adres do sciezki do DLLki CreateRemoteThread(HProc, NULL, NULL, (LPTHREAD_START_ROUTINE)LibAddr, (LPVOID)DllAdr, NULL, NULL); } CloseHandle(HProc); return ; Karol Trybulec p-programowanie.pl 4

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). 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. Karol Trybulec p-programowanie.pl 5

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: 1 #define _WIN32_WINNT _WIN32_WINNT_WINXP Wynika to z różnic w wielkości flag na poszczególnych systemach, więcej na ten temat można znaleźć na MSDN. Karol Trybulec p-programowanie.pl 6