Analizując złośliwe
oprogramowanie dość często spotykamy się z mechanizmem wstrzykiwania złośliwego
kodu do innych procesów użytkownika bądź explorer.exe. Dzisiaj opiszemy dwie z bardziej
popularnych technik. Pierwsza polega na utworzeniu nowego wątku w zdalnym
procesie a druga na wykorzystaniu APC (Asynchronous Procedure Call) do
modyfikacji jednego lub kilku istniejących wątków procesu.
Dla uproszczenia złośliwy kod
umieszczamy w zewnętrznej bibliotece. Jej pełną ścieżkę zapisujemy w buforze.
char*
buffer = "f:\\demodll.dll";
Następnie
musimy pobrać id procesu w kontekście którego będziemy uruchamiali złośliwy
kod. W tym celu malware często korzysta z funkcji CreateToolhelp32Snapshot()
oraz Process32First() i Process32Next().
Po
otrzymaniu id procesu pobieramy do niego uchwyt. Teraz możemy zaalokować
pamięci w tym zdalnym procesie za pomocą funkcji VirtualAllocEx() a następnie w
to miejsce zapisać zawartość bufora za pomocą funkcji WriteProcessMemory().
HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
procID);
LPVOID
pProcessMem = VirtualAllocEx(hprocess,
NULL,
strlen(buffer3),
MEM_COMMIT,
PAGE_READWRITE);
WriteProcessMemory(hprocess,
pProcessMem,
buffer3,
strlen(buffer3),
NULL);
Jak
można zauważyć do zdalnego procesu zapisujemy jedynie bufor – czyli pełną ścieżkę
do biblioteki z malware a nie zawartość biblioteki. W celu uruchomienia tej
biblioteki potrzebna nam jest funkcja LoadLibraryA a właściwie jej adres.
LPVOID addr = (LPVOID)GetProcAddress(
GetModuleHandle(L"kernel32.dll"),
"LoadLibraryA");
Teraz wykorzystamy pierwszą z wspomnianych
metod czyli funkcję CreateRemoteThread() która tworzy i uruchamia nowy wątek we wskazanym procesie.
HANDLE threadID = CreateRemoteThread(process,
NULL,
0,
(LPTHREAD_START_ROUTINE)addr,
pProcessMem,
NULL,
NULL);
Metoda 2 - Asynchronous Procedure Call
APC jest funkcją która wykonywana
jest asynchronicznie w kontekście wątku. Złośliwe oprogramowanie za pomocą QueueUserAPC
może dodać do kolejki wskazanego wątku funkcję. Gdy następnym razem wątek jest uruchamiany
(przełączanie kontekstu w systemie Windows realizowane jest właśnie w oparciu o
wątki a nie procesy) funkcja jest wywoływana. Funkcja nie jest uruchamiana od
razu ale dopiero w momencie osiągnięcia odpowiedniego stanu (np. po wywołaniu
SleepEx() czy WaitForSingleObjectEx()).
W celu identyfikacji wątku
należącego do zdalnego procesu ponownie skorzystamy z funkcji
CreateToolhelp32Snapshot() oraz funkcji Thread32First() oraz Thread32Next().
Następnie otwieramy uchwyt do
wątku i w kolejce rejestrujemy funkcję która będzie wywołana oraz wskaźnik do
parametru funkcji.
HANDLE
thread = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
…
if
(thstr.th32OwnerProcessID == procID)
{
HANDLE
thread2 = OpenThread(THREAD_ALL_ACCESS,
0,
thstr.th32ThreadID);
if (thread2){
QueueUserAPC((PAPCFUNC)addr,
thread2,
((ULONG_PTR)pProcessMem));
…
return 0;
}
}
…