Mając plik sterownika w ręku, załaduj go do wybranego deasemblera i zbadaj punkt wejścia — w przykładach użyto IDA Pro.
UWAGA: Proces inżynierii wstecznej w tym laboratorium ma na celu wskazanie odpowiednich części programu. Być może będziesz musiał poświęcić czas na zapoznanie się z dokumentacją i inżynierią wsteczną, aby dojść do tych samych wniosków!
Wszystkie sterowniki zaczynają się od funkcji DriverEntry. W zależności od ustawień kompilatora, funkcja DriverEntry będzie albo tym, co napisał programista, albo automatycznie wstawionym stubem, który inicjuje plik cookie bezpieczeństwa dla całego sterownika, a następnie przechodzi do oryginalnego DriverEntry. Ten sterownik w rzeczywistości ma automatycznie wstawiony stub znany jako GsDriverEntry. Znajdź ostatnią instrukcję tej funkcji (jmp) i przejdź do funkcji, do której się odwołuje; ta funkcja jest prawdziwym DriverEntry. Na górze prawdziwego DriverEntry powinieneś zobaczyć kilka wywołań memmove i RtlInitUnicodeString, jak pokazano poniżej. Twój deasembler może lub nie pokazywać ciągów znaków, do których się odwołujesz.
Pokazane ciągi są ważne, ponieważ są następnie przekazywane do IoCreateDevice i IoCreateSymbolicLink. Oznacza to, że będziemy mogli wchodzić w interakcję z utworzonym urządzeniem z trybu użytkownika za pośrednictwem symlinku. Wywołanie IoCreateDevice pokazuje kilka innych informacji, takich jak DeviceType (0x9B0C) i DeviceExtensionSize (0xA0), jak pokazano poniżej.
Jeśli zarówno urządzenie, jak i utworzenie dowiązania symbolicznego powiedzie się, sterownik przeniesie wskaźnik funkcji do rax, a następnie wskaźnik funkcji zostanie przeniesiony do różnych przesunięć od rdi, jak pokazano na poniższej ilustracji. Prześledź, co znajduje się w rdi, a powinieneś odkryć, że jest to wskaźnik do _DRIVER_OBJECT, pierwotnie w rcx. Zaczynając od przesunięcia 0x70 w _DRIVER_OBJECT znajduje się tablica MajorFunction, więc funkcja przenoszona do rax musi być głównym programem obsługi funkcji dla sterownika. Obsługuje on cztery główne funkcje:
IRP_MJ_CREATE (0), IRP_MJ_CLOSE (2),
IRP_MJ_DEVICE_CONTROL (14) i
IRP_MJ_INTERNAL_DEVICE_CONTROL (15).
Następnie spójrz na górę głównego handlera funkcji, pokazanego tutaj. Dla ułatwienia zrozumienia, niektóre instrukcje zostały opatrzone adnotacjami o przesunięciach struktury i odpowiednimi wartościami stałych.
Jak widać, funkcja odwołuje się do pól w obu argumentach przekazanych do głównego programu obsługi funkcji: _DEVICE_OBJECT w rcx i _IRP w rdx. Pamiętaj, że struktura _IRP zawiera szczegóły dotyczące wykonywanego żądania. Najpierw _IO_STACK_LOCATION jest przenoszone do r8, a DeviceExtension jest przenoszone do rdi. Następnie stała 14 (IRP_MJ_DEVICE_CONTROL) jest porównywana z pierwszym bajtem _IO_STACK_LOCATION, który jest polem MajorFunction. Gdy sterowanie urządzeniem I/O jest przekazywane do sterownika, to sprawdzenie nie wykona skoku, zamiast tego kontynuując do następnego bloku. W następnym bloku bufor wejściowy (_IRP->AssociatedIrp.SystemBuffer) jest przenoszony do rax, a następnie umieszczany w rdi+0, czyli DeviceExtension+0. Następnie długość bufora wejściowego (_IO_STACK_LOCATION->Parameters.DeviceIoControl.InputBufferLength) jest przenoszona do DeviceExtension+8. Zobaczymy te dwie wartości odwoływane później, więc miej je na uwadze. Następnie długość bufora wejściowego jest porównywana z długością bufora wyjściowego (_IO_STACK_LOCATION->Parameters.DeviceIoControl.OutputBufferLength) i nie kontynuuje przetwarzania żądania sterowania I/O, jeśli nie są równe. Ta informacja stanie się ważna, gdy później spróbujemy napisać kod do interakcji ze sterownikiem. Podczas wyszukiwania luk w skompilowanych programach dobrą praktyką jest rozpoczęcie od wyszukiwania wywołań funkcji, które manipulują pamięcią, takich jak strcpy, memcpy i memmove. Otwórz odwołania krzyżowe do funkcji memmove w swoim deasemblerze. W IDA naciśnij klawisz X na funkcji, aby wyświetlić okno pokazane obok.
Poświęć trochę czasu na przejrzenie wszystkich tych wywołań memmove. Prześledź ich argumenty (rcx, rdx i r8), aby sprawdzić, czy możesz kontrolować którykolwiek z nich. Pamiętaj, że wartości pobrane ze struktur _IRP->AssociatedIrp.SystemBuffer i _IO_STACK_LOCATION->Parameters.DeviceIoControl można bezpośrednio kontrolować z trybu użytkownika. Pamiętaj również, że SystemBuffer i InputBufferSize zostały przeniesione do DeviceExtension odpowiednio na przesunięciach 0 i 8. Mam nadzieję, że po pewnych poszukiwaniach uznasz wywołanie memmove w sub_15294 za interesujące.
W zależności od wartości dl, wartość w r9+0x18 jest przenoszona do rcx (miejsce docelowe) lub rdx (źródło). Na początku tego fragmentu kodu, inny argument memmove znajduje się w rcx, a rozmiar ruchu jest przenoszony z eax do r8d. Prześledź dalej, aby zobaczyć, skąd pochodzą r9, rcx i eax, jak pokazano poniżej.
Wygląda na to, że rax pochodzi z rbx+0x10, a r9 pochodzi z rbx. W tym momencie wiemy, że zarówno argument rozmiaru, jak i źródło lub miejsce docelowe pochodzą z bufora w rbx. Kontynuuj śledzenie, aby znaleźć, że rcx (pierwszy argument) został przeniesiony do rbx w pierwszym bloku funkcji. Śledzenie do wywołującego za pomocą odniesienia krzyżowego pokazuje, że rdi został przeniesiony do rcx wewnątrz głównego programu obsługi funkcji, jak pokazano tutaj.
Wygląda na to, że rax pochodzi z rbx+0x10, a r9 pochodzi z rbx. W tym momencie wiemy, że zarówno argument rozmiaru, jak i źródło lub miejsce docelowe pochodzą z bufora w rbx. Kontynuuj śledzenie, aby znaleźć, że rcx (pierwszy argument) został przeniesiony do rbx w pierwszym bloku funkcji. Śledzenie do wywołującego za pomocą odniesienia krzyżowego pokazuje, że rdi został przeniesiony do rcx wewnątrz głównego programu obsługi funkcji, jak pokazano tutaj.
Prześledzenie jednego bloku z każdego z tych dwóch bloków ujawnia kody IOCTL dla każdego z nich: 0x9B0C1EC4 i 0x9B0C1EC8.
W tym momencie mamy wszystkie informacje, których potrzebujemy, aby przejść do dynamicznej analizy sterownika. Jako dodatkowe ćwiczenie spróbuj dowiedzieć się, co robią inne IOCTL w tym sterowniku. Funkcjonalność, którą właśnie zidentyfikowaliśmy, nie jest jedynym problemem z tym sterownikiem!