wtorek, 19 lipca 2016

Monitorowanie plików za pomocą skryptu windbg

W ramach naszych wpisów edukacyjnych związanych z analizą złośliwego oprogramowania dzisiaj o skryptach w windows debugger.

O monitorowaniu funkcji API pisaliśmy już kilka razy. Tym razem pokażemy, jak w prosty sposób można monitorować aktywność procesów (dotyczącą tworzenia czy kasowania plików) z użyciem windbg oraz języka skryptowego. Skorzystamy z przykładu, który zamieszczony jest w książce „Practical Reverse Engineering” i przeznaczony jest dla architektury 32 bitowej. My rozbudujemy go o obsługę aplikacji 64 bitowych. Omawiany skrypt umieściliśmy na github.

Skrypt będzie wyświetlał nazwę funkcji API oraz nazwę pliku.

Budowa skryptu jest bardzo prosta. Komenda bp oznacza breakpoint. Następnie podajemy nazwę biblioteki oraz nazwę funkcji API na której ustawiamy breakpoint warunkowy. Ustawiamy następujące parametry: nazwę funkcji API, informację czy funkcja jest w wersji ASCII czy Unicode oraz numer argumentu na stosie (po weryfikacji w MSDN wszystkie funkcje w pierwszym argumencie przekazują nazwę pliku). Poniżej przykład:

bp kernelbase!CreateFileA @"$$>a<${$arg0} CreateFileA 0 1";
bp kernelbase!CreateFileW @"$$>a<${$arg0} CreateFileW 1 1";
...

Dla systemu 32 bitowego wszystkie argumenty funkcji są przekazywane przez stos. Można zauważyć, że pobieramy zawartość wskazywaną przez adres (wskaźnik) do csp + 4 * (numer argumentu).  CSP to current call stack pointer (może to być zarówno esp – dla 32 bitowej architektury lub rps – dla 64 bitowej architektury). 4 * (numer argumentu czyli w naszych funkcjach API = 1), gdyż w momencie zatrzymania na stosie jest już umieszczony adres powrotu do funkcji wywołującej.

r $t1 = poi(@$csp + 4 * ${$arg3});

W przypadku systemu 64 bitowego cztery pierwsze argumenty są przekazywane za pomocą kolejnych rejestrów RCX, RDX, R8 oraz R9. Tutaj wystarczy gdy pobierzemy zawartość pierwszego rejestru RCX.

r $t1 = rcx;

Aby skrypt obsługiwał jednocześnie 32 i 64 bitową wersję aplikacji musimy wykrywać pod jaką architekturą jest uruchamiany. Pamiętajmy, że instalowane są dwie wersje Debugging Tools for Windows (dla aplikacji 32 i 64 bitowych) więc moglibyśmy przygotować dwa oddzielne skrypty.
Za pomocą komendy .effmach wyświetlimy aktualny tryb pracy. Wynik zapisujemy w aliasie korzystając z .foreach, które świetnie się nadaje do „wyciągania” informacji z wyniku wywołanej komendy. Następnie w zależności o wykrytej architektury (spat służy do porównania ciągów znaków) wykonamy jedną z dwóch komend (podanych powyżej) związaną z pobraniem nazwy pliku i zapisaniem jej do jednego z pseudo-rejestru ($t1).

.foreach /pS 2 (token {.effmach}); { aS CurrentArch ${token};};

.if $spat(@"${CurrentArch}", "*x86*") == 1
{
 r $t1 = poi(@$csp + 4 * ${$arg3});
}
.else
{
 r $t1 = rcx;
}

Ostatni fragment to wyświetlenie za pomocą .printf zawartości pseudo-rejestru w zależności od formatu (ASCII/Unicode).

Pozostaje nam tylko po podłączeniu się do monitorowanego procesu wywołać skrypt za pomocą komendy:

$$>a<E:\file_activity.wds init;g;

Brak komentarzy:

Publikowanie komentarza