Erste Schritte mit WinDbg (Kernelmodus)
WinDbg ist ein Kernelmodus- und Benutzermodusdebugger, der in Debugtools für Windows enthalten ist. Dieser Artikel enthält Übungen, die Ihnen bei den ersten Schritten bei der Verwendung von WinDbg als Kernelmodusdebugger helfen.
Informationen darüber, wie Sie Debugging-Tools für Windows erhalten, finden Sie unter Herunterladen und Installieren des WinDbg-Windows-Debuggers. Nachdem Sie die Debugtools installiert haben, suchen Sie die Installationsverzeichnisse für 64-Bit-Versionen (x64) und 32-Bit-Versionen (x86) der Tools. Zum Beispiel:
- C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
- C:\Program Files (x86)\Windows Kits\10\Debuggers\x86
Einrichten eines Kernelmodus-Debuggens
Eine Kernelmodus-Debugumgebung verfügt in der Regel über zwei Computer, den Hostcomputer und den Zielcomputer. Der Debugger wird auf dem Hostcomputer ausgeführt, und der debuggierte Code wird auf dem Zielcomputer ausgeführt. Der Host und das Ziel werden über ein Debugkabel verbunden.
Die Windows-Debugger unterstützen die folgenden Kabeltypen:
- Ethernet
- USB 3.0
- Serial (auch als Nullmodem bezeichnet)
Für Geschwindigkeit und Zuverlässigkeit sollten Sie ein Ethernet-Kabel mit einem lokalen Netzwerkhub verwenden. Das folgende Diagramm veranschaulicht einen Host- und Zielcomputer, der für das Debuggen mit einem Ethernet-Kabel verbunden ist.
Eine Option für ältere Versionen von Windows ist die Verwendung eines direkten Kabels, z. B. eines seriellen Kabels.
Ausführliche Informationen zum Einrichten der Host- und Zielcomputer finden Sie unter Manuelles Einrichten des Kernelmodusdebuggings.
Virtueller Computer - (VM)
Informationen zum Verbinden eines Debuggers mit einem virtuellen Hyper-V-Computer finden Sie unter Einrichten des Netzwerkdebuggings eines virtuellen Computers – KDNET.
Einrichten einer Kernelmodusdebuggingsitzung
Nachdem Sie Ihren Host- und Zielcomputer eingerichtet und mit einem Debuggerkabel verbunden haben, können Sie eine Kernelmodus-Debuggingsitzung einrichten. Befolgen Sie die Anweisungen im selben Thema, das Sie zum Einrichten verwendet haben. Wenn Sie beispielsweise ihren Host- und Zielcomputer für das Debuggen über Ethernet einrichten möchten, finden Sie Anweisungen zum Einrichten einer Kernelmodus-Debuggingsitzung im folgenden Artikel:
Erste Schritte mit WinDbg
Öffnen Sie auf dem Hostcomputer WinDbg, und richten Sie eine Kernelmodus-Debuggingsitzung mit dem Zielcomputer ein.
Um die CHM-Datei der Debuggerdokumentation zu öffnen, wechseln Sie zum Menü Hilfe, und wählen Sie Inhalt aus. Die Debugger-Dokumentation ist auch online in Debuggingtools für Windows verfügbar.
Wenn Sie eine Debugging-Sitzung im Kernelmodus einrichten, bricht WinDbg möglicherweise automatisch in den Zielcomputer ein. Wenn WinDbg nicht einbricht, wechseln Sie zum Menü Debuggen, und wählen Sie Unterbrechen.
Geben Sie in der Befehlszeile unten im WinDbg-Fenster den folgenden Befehl ein:
Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
Symbol search path is: srv* Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols
Der Symbolsuchpfad teilt WinDbg mit, wo nach Symboldateien (PDB) gesucht werden soll. Der Debugger benötigt Symboldateien, um Informationen zu Codemodulen wie Funktionsnamen und Variablennamen abzurufen.
Geben Sie den folgenden Befehl ein, der WinDbg angibt, die anfängliche Suche und das Laden von Symboldateien auszuführen:
Geben Sie den folgenden Befehl ein, um eine Liste der geladenen Module anzuzeigen:
Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
0:000>3: kd> lm start end module name fffff800`00000000 fffff800`00088000 CI (deferred) ... fffff800`01143000 fffff800`01151000 BasicRender (deferred) fffff800`01151000 fffff800`01163000 BasicDisplay (deferred) ... fffff800`02a0e000 fffff800`03191000 nt (pdb symbols) C:\...\ntkrnlmp.pdb fffff800`03191000 fffff800`03200000 hal (deferred) ...
Geben Sie den folgenden Befehl ein, um die Ausführung des Zielcomputers zu starten:
Um erneut einzubrechen, wechseln Sie zum Menü Debuggen und wählen Sie Unterbrechen aus.
Geben Sie den folgenden Befehl ein, um den
_FILE_OBJECT
Datentyp imnt
Modul zu untersuchen:Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
0:000>0: kd> dt nt!_FILE_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B +0x008 DeviceObject : Ptr64 _DEVICE_OBJECT +0x010 Vpb : Ptr64 _VPB ... +0x0c0 IrpList : _LIST_ENTRY +0x0d0 FileObjectExtension : Ptr64 Void
Geben Sie den folgenden Befehl ein, um einige der Symbole im
nt
Modul zu untersuchen:Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
0:000>0: kd> x nt!*CreateProcess* fffff800`030821cc nt!ViCreateProcessCallbackInternal (<no parameter info>) ... fffff800`02e03904 nt!MmCreateProcessAddressSpace (<no parameter info>) fffff800`02cece00 nt!PspCreateProcessNotifyRoutine = <no type information> ...
Geben Sie den folgenden Befehl ein, um einen Haltepunkt bei MmCreateProcessAddressSpace zu platzieren:
bu nt! MmCreateProcessAddressSpace
Um zu überprüfen, ob der Haltepunkt festgelegt ist, geben Sie den folgenden Befehl ein:
Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
0:000>0: kd> bu nt!MmCreateProcessAddressSpace 0: kd> bl 0 e fffff800`02e03904 0001 (0001) nt!MmCreateProcessAddressSpace
Geben Sie g ein, damit der Zielcomputer ausgeführt werden kann.
Wenn der Zielcomputer nicht sofort in den Debugger einbricht, führen Sie einige Aktionen auf dem Zielcomputer aus (z. B. Editor öffnen). Der Zielcomputer wechselt in den Debugger, wenn MmCreateProcessAddressSpace aufgerufen wird. Um die Stapelablaufverfolgung anzuzeigen, geben Sie die folgenden Befehle ein:
Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
0:000>2: kd> k Child-SP RetAddr Call Site ffffd000`224b4c88 fffff800`02d96834 nt!MmCreateProcessAddressSpace ffffd000`224b4c90 fffff800`02dfef17 nt!PspAllocateProcess+0x5d4 ffffd000`224b5060 fffff800`02b698b3 nt!NtCreateUserProcess+0x55b ... 000000d7`4167fbb0 00007ffd`14b064ad KERNEL32!BaseThreadInitThunk+0xd 000000d7`4167fbe0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
Wählen Sie im Menü Ansicht die Option Disassembly aus.
Wählen Sie im Menü Debuggen die Option Schritt über aus (oder drücken Sie F10). Geben Sie schrittbefehle ein paar mal ein, während Sie das Fenster "Disassembly" ansehen.
Löschen Sie Ihren Haltepunkt, indem Sie den folgenden Befehl eingeben:
Geben Sie g ein, damit der Zielcomputer ausgeführt werden kann. Um erneut zu unterbrechen, wechseln Sie zum Menü Debugger und wählen Sie Pause oder drücken Sie STRG-Pause.
Um eine Liste aller Vorgänge abzurufen, geben Sie den folgenden Befehl ein:
Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
0:000>0: kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS ffffe000002287c0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001aa000 ObjectTable: ffffc00000003000 HandleCount: <Data Not Accessible> Image: System PROCESS ffffe00001e5a900 SessionId: none Cid: 0124 Peb: 7ff7809df000 ParentCid: 0004 DirBase: 100595000 ObjectTable: ffffc000002c5680 HandleCount: <Data Not Accessible> Image: smss.exe ... PROCESS ffffe00000d52900 SessionId: 1 Cid: 0910 Peb: 7ff669b8e000 ParentCid: 0a98 DirBase: 3fdba000 ObjectTable: ffffc00007bfd540 HandleCount: <Data Not Accessible> Image: explorer.exe
Kopieren Sie die Adresse eines Prozesses, und geben Sie den folgenden Befehl ein:
Beispiel:
!process ffffe00000d5290 2
Die Ausgabe zeigt die Threads im Prozess an.
0:000>0:000>0: kd> !process ffffe00000d52900 2 PROCESS ffffe00000d52900 SessionId: 1 Cid: 0910 Peb: 7ff669b8e000 ParentCid: 0a98 DirBase: 3fdba000 ObjectTable: ffffc00007bfd540 HandleCount: Image: explorer.exe THREAD ffffe00000a0d880 Cid 0910.090c Teb: 00007ff669b8c000 ffffe00000d57700 SynchronizationEvent THREAD ffffe00000e48880 Cid 0910.0ad8 Teb: 00007ff669b8a000 ffffe00000d8e230 NotificationEvent ffffe00000cf6870 Semaphore Limit 0xffff ffffe000039c48c0 SynchronizationEvent ... THREAD ffffe00000e6d080 Cid 0910.0cc0 Teb: 00007ff669a10000 ffffe0000089a300 QueueObject
Kopieren Sie die Adresse eines Threads, und geben Sie den folgenden Befehl ein:
Beispiel:
!thread ffffe00000e6d080
Die Ausgabe zeigt Informationen zum einzelnen Thread an.
0: kd> !thread ffffe00000e6d080 THREAD ffffe00000e6d080 Cid 0910.0cc0 Teb: 00007ff669a10000 Win32Thread: 0000000000000000 WAIT: ... ffffe0000089a300 QueueObject Not impersonating DeviceMap ffffc000034e7840 Owning Process ffffe00000d52900 Image: explorer.exe Attached Process N/A Image: N/A Wait Start TickCount 13777 Ticks: 2 (0:00:00:00.031) Context Switch Count 2 IdealProcessor: 1 UserTime 00:00:00.000 KernelTime 00:00:00.000 Win32 Start Address ntdll!TppWorkerThread (0x00007ffd14ab2850) Stack Init ffffd00021bf1dd0 Current ffffd00021bf1580 Base ffffd00021bf2000 Limit ffffd00021bec000 Call 0 Priority 13 BasePriority 13 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5 ...
Um alle Geräteknoten in der Plug Play Gerätestruktur anzuzeigen, geben Sie den folgenden Befehl ein:
0:000>0: kd> !devnode 0 1 Dumping IopRootDeviceNode (= 0xffffe000002dbd30) DevNode 0xffffe000002dbd30 for PDO 0xffffe000002dc9e0 InstancePath is "HTREE\ROOT\0" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe000002d9d30 for PDO 0xffffe000002daa40 InstancePath is "ROOT\volmgr\0000" ServiceName is "volmgr" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe00001d49290 for PDO 0xffffe000002a9a90 InstancePath is "STORAGE\Volume\{3007dfd3-df8d-11e3-824c-806e6f6e6963}#0000000000100000" ServiceName is "volsnap" TargetDeviceNotify List - f 0xffffc0000031b520 b 0xffffc0000008d0f0 State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) ...
Um die Geräteknoten und deren Hardwareressourcen anzuzeigen, geben Sie den folgenden Befehl ein:
0:000>... DevNode 0xffffe000010fa770 for PDO 0xffffe000010c2060 InstancePath is "PCI\VEN_8086&DEV_2937&SUBSYS_2819103C&REV_02\3&33fd14ca&0&D0" ServiceName is "usbuhci" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) TranslatedResourceList at 0xffffc00003c78b00 Version 1.1 Interface 0x5 Bus #0 Entry 0 - Port (0x1) Device Exclusive (0x1) Flags (0x131) - PORT_MEMORY PORT_IO 16_BIT_DECODE POSITIVE_DECODE Range starts at 0x3120 for 0x20 bytes Entry 1 - DevicePrivate (0x81) Device Exclusive (0x1) Flags (0000) - Data - {0x00000001, 0x00000004, 0000000000} Entry 2 - Interrupt (0x2) Shared (0x3) Flags (0000) - LEVEL_SENSITIVE Level 0x8, Vector 0x81, Group 0, Affinity 0xf ...
Um einen Geräteknoten mit einem Dienstnamen des Datenträgers anzuzeigen, geben Sie den folgenden Befehl ein:
0: kd> !devnode 0 1 disk Dumping IopRootDeviceNode (= 0xffffe000002dbd30) DevNode 0xffffe0000114fd30 for PDO 0xffffe00001159610 InstancePath is "IDE\DiskST3250820AS_____________________________3.CHL___\5&14544e82&0&0.0.0" ServiceName is "disk" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) ...
Die Ausgabe von !devnode 0 1 zeigt die Adresse des physischen Geräteobjekts (PDO) für den Knoten an. Kopieren Sie die Adresse eines physischen Geräteobjekts (PDO), und geben Sie den folgenden Befehl ein:
Beispiel:
<PdoAddress>!devstack 0xffffe00001159610
0:000>0: kd> !devstack 0xffffe00001159610 !DevObj !DrvObj !DevExt ObjectName ffffe00001d50040 \Driver\partmgr ffffe00001d50190 ffffe00001d51450 \Driver\disk ffffe00001d515a0 DR0 ffffe00001156e50 \Driver\ACPI ffffe000010d8bf0
Um Informationen zum Treiber disk.sys abzurufen, geben Sie den folgenden Befehl ein:
0:000>0: kd> !drvobj disk 2 Driver object (ffffe00001d52680) is for: \Driver\disk DriverEntry: fffff800006b1270 disk!GsDriverEntry DriverStartIo: 00000000 DriverUnload: fffff800010b0b5c CLASSPNP!ClassUnload AddDevice: fffff800010aa110 CLASSPNP!ClassAddDevice Dispatch routines: [00] IRP_MJ_CREATE fffff8000106d160 CLASSPNP!ClassGlobalDispatch [01] IRP_MJ_CREATE_NAMED_PIPE fffff80002b0ab24 nt!IopInvalidDeviceRequest [02] IRP_MJ_CLOSE fffff8000106d160 CLASSPNP!ClassGlobalDispatch [03] IRP_MJ_READ fffff8000106d160 CLASSPNP!ClassGlobalDispatch ... [1b] IRP_MJ_PNP fffff8000106d160 CLASSPNP!ClassGlobalDispatch
Die Ausgabe zeigt
!drvobj
Adressen von Verteilerroutinen an. Beispiel:CLASSPNP!ClassGlobalDispatch
. Um einen Haltepunkt festzulegen und zuClassGlobalDispatch
überprüfen, geben Sie die folgenden Befehle ein:bu CLASSPNP!ClassGlobalDispatch
Eingeben,
g
um den Zielcomputer ausführen zu lassen.Wenn der Zielcomputer nicht sofort in den Debugger einbricht, führen Sie einige Aktionen auf dem Zielcomputer aus (z. B. Editor öffnen und Datei speichern). TDer Zielcomputer wechselt den Debugger, wenn
ClassGlobalDispatch
aufgerufen wird. Um die Stapelablaufverfolgung anzuzeigen, geben Sie die folgenden Befehle ein:Die Ausgabe sieht in etwa wie das folgende Beispiel aus:
2: kd> k Child-SP RetAddr Call Site ffffd000`21d06cf8 fffff800`0056c14e CLASSPNP!ClassGlobalDispatch ffffd000`21d06d00 fffff800`00f2c31d volmgr!VmReadWrite+0x13e ffffd000`21d06d40 fffff800`0064515d fvevol!FveFilterRundownReadWrite+0x28d ffffd000`21d06e20 fffff800`0064578b rdyboost!SmdProcessReadWrite+0x14d ffffd000`21d06ef0 fffff800`00fb06ad rdyboost!SmdDispatchReadWrite+0x8b ffffd000`21d06f20 fffff800`0085cef5 volsnap!VolSnapReadFilter+0x5d ffffd000`21d06f50 fffff800`02b619f7 Ntfs!NtfsStorageDriverCallout+0x16 ...
Geben Sie den folgenden Befehl ein, um die Debugging-Sitzung zu beenden:
Zusammenfassung der Befehle
- Befehl Inhalt im Menü Hilfe
- .sympath (Set-Symbolpfad)
- .reload (Modul neu laden)
- x (Symbole überprüfen)
- g (Gehe zu)
- dt (Anzeigentyp)
- Befehl Unterbrechen im Menü Debuggen
- lm (Liste der geladenen Module)
- k (Anzeigestapel-Backtrace)
- bu (Haltepunkt setzen)
- bl (Haltepunktliste)
- bc (Haltepunkt löschen)
- Einzelschritt-Befehl im Debug-Menü (F11)
- !process
- !thread
- !devnode
- !devstack
- !drvobj
- qd (Beenden und Trennen)