Debugowanie jądra systemu Windows: Wprowadzenie
Być może zastanawiałeś się kiedyś nad tym, czy można i czy warto debugować nie pojedynczy program, ale wszytko to co znajduje się pod kontrolą systemu operacyjnego? Jeżeli odpowiedź brzmi “tak” lub właśnie wzbudziłem Twoją ciekawość, przygotuj sobie kawę lub herbatę i zapoznaj się z artykułem, który przygotowałem dla Ciebie.
1. Wstęp
Celem tego artykułu jest zapoznanie czytelnika z przygotowaniem środowiska do debugowaniem jądra systemu Windows, wyjaśnienie zalet i wad możliwych rozwiązań oraz poprowadzenie zainteresowanej osoby przez proces konfiguracji środowiska debugowania jądra systemu Windows.
2. Dlaczego ktoś by w ogóle chciał debugować jądro systemu operacyjnego?
Debugowanie jądra systemu operacyjnego jest niezbędne do rozwiązania dużej liczby problemów związanych z trybem jądra:
- odczytu danych z / zapisu danych do przestrzeni adresowej trybu jądra,
- opracowania sterownika trybu jądra,
- analizy oprogramowania złośliwego działającego w trybie jądra.
3. Środowisko
Jeśli nadal chcesz przejąć kontrolę nad całym komputerem z systemem Windows lub desperacko pragniesz zmienić sposób myślenia o wewnętrznych elementach systemu Windows, musisz pamiętać o kilku zmianach w stosunku do debugowania w „tradycyjnym” trybie użytkownika. Po pierwsze, uzyskasz dostęp do dowolnego zasobu w systemie: od procesora przez całą pamięć do wątków. Po drugie, każdy ustawiony breakpoint zatrzyma system. Dlatego właśnie potrzebujesz drugiej maszyny. Największe możliwości daje rozwiązanie zbudowane z maszyn fizycznych, jednak podnosi ono koszty zbudowania kompletnego środowiska ze względu na konieczność posiadania drugiego komputera. Alternatywnym rozwiązaniem jest użycie maszyny wirtualnej lub… wirtualizacja całego środowiska.
3.1 Środowisko fizyczne
Aby skonfigurować środowisko fizyczne, potrzebujesz dwóch komputerów: hosta (debugger) i debugowaną maszynę (debugee). Wbrew pozorom nie istnieje z góry narzucony przymus, aby utrzymywać wspólną wersję i architekturę systemu operacyjnego pomiędzy dwoma maszynami. Istotny jest ten sam typ połączenia między tymi maszynami. Obsługiwanymi typami połączeń są Ethernet, port szeregowy, IEEE 1394 (FireWire) oraz USB (w wersji 2.0 lub nowszej). Poniższa tabela prezentuje istotne cechy dopuszczalnych rozwiązań.
Połączenie | Niezawodność | Szybkość | Dodatkowe informacje |
---|---|---|---|
Ethernet | Stabilne | Szybkie | Konieczne wsparcie dla karty sieciowej |
Serial | Bardzo stabilne | Bardzo wolne | Umożliwia debugowanie na bardzo niskim poziomie, np. zarządzanie zasilaniem może być niedostępne w najnowszych komputerach |
IEEE 1394 | Bardzo stabilne | Szybkie | Może być wykorzystane z wykorzystaniem kart rozszerzeń |
USB | Mogą wystąpić problemy | Szybkie | Konieczny specjalny kabel USB |
Istnieją pewne uwagi związane z wykorzystaniem niektórych typów połączeń, o których należy pamiętać. Interfejs USB 2.0 jest dopuszczony do użycia tylko w przypadku, jeżeli jest to port nr 1. Konieczne jest również użycie kabla krosowanego. Jeśli jednak zdecydowałeś się na korzystanie z Ethernetu, powinieneś sprawdzić, czy zadeklarowano wsparcie dla posiadanego modelu karty sieciowej.
Jeśli wybrano już typ połączenia, wystarczy połączyć dwa komputery za jego pomocą.
3.2 Środowisko wirtualne
Debugowanie maszyny wirtualnej jest znacznie tańsze niż utrzymanie dodatkowych urządzeń fizycznych. Oczywiście fizyczny host nie musi być obsługiwany przez system Windows. Uniwersalnym rozwiązaniem jest połączenie gości (debuggera oraz maszyny debugowanej) za pomocą wirtualnego połączenia sieciowego.
Istnieją pewne założenia wstępne, którymi posłużono się projektując środowisko debugowania:
- host jest maszyną z systemem Linux i VirtualBox,
- debuggerem jest maszyną wirtualną z systemem Windows 10,
- debuggee to maszyna wirtualna z systemem Windows 10,
- debugger i debugee są połączone za pośrednictwem wirtualnej karty sieciowej.
Jeśli napotkasz jakiekolwiek problemy z komunikacją pomiędzy maszynami podczas korzystania z tego rozwiązania, upewnij się, że Twoja karta sieciowa jest obsługiwana.
Następna część artykułu prezentuje przygotowanie i konfigurację środowiska wirtualnego.
4. Konfiguracja środowiska wirtualnego
4.1. Przygotowanie maszyny debugowanej (debugee)
Jeżeli skonfigurowano już połączenie sieciowe, nadszedł czas, aby przygotować maszynę debugowaną.
Jako administrator uruchom polecenia używając adres IP debuggera:
bcdedit /debug ON
bcdedit /dbgsettings net hostip:192.168.0.108 port:50000 key:Win.Kernel.Debug.Env
W dowolnej chwili możesz zweryfikować konfigurację debugowanej maszyny uruchamiając polecenie:
bcdedit /dbgsettings
4.2. Przygotowanie debuggera
Pobierz i zainstaluj Windows 10 SDK .
Po zainstalowaniu wszystkie potrzebne narzędzia powinny być dostępne w katalogu
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\
.Utwórz katalog do cache’owania symboli, np.
C:\Symbols
.Wyeksportuj zmienną środowiskową _NT_SYMBOL_PATH:
setx _NT_SYMBOL_PATH "srv*C:\Symbols*https://msdl.microsoft.com/download/symbols"
4.3. Rozpoczęcie debugowania jądra systemu Windows
Jeżeli nie napisano wyraźnie inaczej, poniższe działania powinny być wykonywane na debuggerze.
Uruchom WinDBG znajdujący się w lokalizacji
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe
.Z menu File wybierz ‘Kernel Debug’.
- W zakładce ‘NET’ ustaw pole ‘Key’ jako ‘Win.Kernel.Debug.Env’.
- Wciśnij OK.
Zrestartuj debugowaną maszynę i poczekaj.
Po kilku sekundach powinieneś zobaczyć:
W tym momencie powinno być możliwe skuteczne przetestowanie możliwości debugowania jądra.
4.4. Test
W WinDBG wybierz Break z menu Debug lub po prostu naciśnij Ctrl + B.
Spróbuj uruchomić dowolne polecenie w sesji windbg, np. wypisanie listy wszystkich procesów:
!process 0 0
Jeśli widzisz listę podobną do poniższej, wszystko jest w porządku.
Jeśli będziesz mieć problem z symbolami jak na rysunku poniżej
możesz naprawić załadowane symbole, uruchamiając polecenia w sesji windbg:
.symfix
.sympath
5. Podsumowanie
W artykule zapoznano czytelnika z debugowaniem jądra systemu Windows. Ponadto przedstawiono zalety i wady dopuszczalnych konfiguracji zależnych od wybranego typu połączenia pomiędzy maszynami. W ostatniej części artykułu poprowadzono czytelnika krok po kroku przez proces przygotowania środowiska wirtualnego. Zaproponowane rozwiązanie zostało oparte o dwie maszyny wirtualne z systemem Windows 10, które zostały osadzone na fizycznej maszynie z systemem Linux. Połączenie pomiędzy maszynami wirtualnymi wykonano za pośrednictwem sieci wirtualnej.
Następny artykuł na temat debugowania jądra systemu Windows będzie opisywał wybrane polecenia windbg oraz możliwe sposoby ich wykorzystania.