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.
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
.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:
Prześlij komentarz