Wstrzykiwanie biblioteki DLL do procesu

Poprzedni post skończył sie napisaniem (nieprzechodzących) testów. Teraz nadszedł czas na implementację mechanizmu wstrzykiwania biblioteki DLL do innego procesu.

Na początek stwórzmy bibliotekę, która będzie wstrzykiwana w docelowy proces. Niestety nie możemy jej napisać w F# ponieważ musi być ona natywna (i zgodna z architekturą docelowego procesu), tak więc wykorzystamy C++. Po załadowaniu do procesu wywołana zostanie funkcja DllMain:

Zwrócenie wartości FALSE powoduje natychmiastowe wyładowanie biblioteki z pamięci. Dzięki temu nie będzie zaśmiecać docelowego procesu. Komunikacja z Patherem odbywać będzie się przy pomocy named pipe, a cała pętla obsługi znajduje się w funkcji injection:

Nazwa potoku budowana jest według wzoru: \\.\pipe\pather\<id-procesu>, a na na protokół składają sie trzy operacje: echo (kod 45), ustawianie (01) i odczytywanie (02) zmiennej środowiskowej. Na razie zostawy ich implementację i przyjrzyjmy się jak to wygląda stronie Pathera, która jest zdecydowanie bardziej złożona.

Na początek trzeba zaimportować kilka funkcji WinApi:

Wstrzykiwanie biblioteki DLL do jakiegoś procesu opiera się na utworzeniu w nim wątku (z pomocą CreateRemoteThread) z funkcją LoadLibrary jako entrypointem i ścieżką do biblioteki jako parametrem w postaci wskaźnika na łańcuch znaków zakończony znakiem 0. Wymaga to uprzedniego umieszczenia go w pamięci procesu co umożliwia para VirtualAllocEx i WriteProcessMemory. Całość rozbudowana o wybranie odpowiedniej wersji biblioteki DLL (x86 albo x64) przedstawia się następująco:

Funkcja findFunction pozwala na określenie adresu zadanej funkcji w przestrzeni adresowej docelowego procesu i będzie tematem następnego postu.

Mając mechanizm wstrzykiwania możemy obudować go w obsługę named-pipe:

Mając podstawową obsługę komunikacji z obu stron możemy zaimplementować trzy operacje:

ze strony Pathera:

oraz biblioteki DLL:

Wyjaśnienia wymagają funkcje C++ readString, readStringLength, writeString oraz writeStringLength - są to funkcje implementujące ten sam sposób kodowania łańcuchów znaków co BinaryReader i BinaryWriter. Ich implementacja jest bliźniaczo podobna do ich odpowiedników w .NET (BinaryReader.ReadString, BinaryWriter.WriteString).

Świadomie nie skupiałem się na problemach związanych z aplikacjami 32-bitowymi na 64-bitowym systemie - jedynie funkcja injectLibrary wybiera odpowiednią bibliotekę na podstawie architektury docelowego procesu. Problemy związane z WoW64 zostaną opisane w następnym poście.

Obsługa wiersza polecenia

Obsługa wiersza polecenia, a własciwie argumentów przekazywanych w ten sposób, to temat rzeka. Istnieje niezliczona liczba bibliotek i ko...… Continue reading

Pakowanie aplikacji z ILRepack

Published on March 30, 2016

Paket i FAKE

Published on March 24, 2016