這次我們通過一個實際調試驅動的例子,來逐漸體會Windbg在核心調試中的作用.
由于條件所限,大多數情況下,很多人都是用VMware+Windbg調試核心(VMware的确是個好東西

).但這樣的調試需要占用大量的系統資源,對于和我一樣急性子的朋友來說這是不可接受的:).利用雙機調試就可以讓你一邊喝咖啡一邊輕松的看結果,而不至于郁悶的等待每次長達數分鐘的系統響應.有關雙機調試的基本設定,請參考:http://www.cnblogs.com/Sonic2007/archive/2008/03/20/1114807.html
本次調試驅動所建構的環境如下:
host computer: WinXP+Windbg
Target computer: Vista SP1
driver object: sys
connect setting: 1394資料線
說明: 1.1394卡在很多機器上都已經沒有了,Vista也取消了1394的資料連接配接協定
(調試還是可以的),但不可否認的是利用1394資料線連接配接調試要比COM口和USB速率快很多(為什麼好用的東西卻得不到支援!
).2.本次調試的driver是公司開發的某個軟體的驅動程式,拿來嘗試在Vista SP1下track.由于涉及到商業機密,本驅動源代碼不便公開.3.Vista SP1就沒什麼好說的了,前些天才釋出,MS又一個失敗的典型.
OK,Let's go!
該驅動是一個類型sr.sys(MS的System Restore驅動)的Filter Driver,屬于檔案系統過濾驅動,加載在檔案系統驅動上層,由Filter Manager負責與使用者層和底層通信.連接配接到目标機後,按下Ctrl+break中斷目前狀态.(注:你也可以進入到explorer之後再中斷,為了了解驅動加載時的進入點,以及系統啟動時核心的裝态,我們中斷到這裡)
Microsoft (R) Windows Debugger Version 6.6.0007.5
Copyright (c) Microsoft Corporation. All rights reserved.
Using 1394 for debugging
Opened \\.\DBG1394_INSTANCE01
Waiting to reconnect...
Connected to Windows Vista 6000 x86 compatible target, ptr64 FALSE
Kernel Debugger connection established.
Symbol search path is: D:\symbolslocal; D:\IR\SystemOK\Restore\Driver\objchk_wlh_x86\i386
Executable search path is:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlmp.exe -
Windows Vista Kernel Version 6000 MP (1 procs) Free x86 compatible
Built by: 6000.16584.x86fre.vista_gdr.071023-1545
Kernel base = 0x81800000 PsLoadedModuleList = 0x81908ad0
System Uptime: not available
WARNING: Whitespace at start of path element
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
*
* You are seeing this message because you pressed either
* CTRL+C (if you run kd.exe) or,
* CTRL+BREAK (if you run WinDBG),
* on your debugger machine's keyboard.
*
* THIS IS NOT A BUG OR A SYSTEM CRASH
* If you did not intend to break into the debugger, press the "g" key, then
* press the "Enter" key now. This message might immediately reappear. If it
* does, press "g" and "Enter" again.
nt!RtlpBreakWithStatusInstruction:
818355e8 cc int 3
然後,在Command line裡鍵入lm,檢視目前系統加載的子產品和驅動(會發現我們的driver列在其中):
kd> lm
start end module name
80404000 80412000 PCIIDEX (deferred)
80412000 80419000 intelide (deferred)
80419000 80429000 mountmgr (deferred)
80429000 80438000 volmgr (deferred)
80438000 8045d000 pci (deferred)
8045d000 80465000 msisadrv (deferred)
80465000 8046e000 WMILIB (deferred)
8046e000 804b1000 acpi (deferred)
804b1000 804be000 WDFLDR (deferred)
804be000 80539000 Wdf01000 (deferred)
80539000 8061a000 CI (deferred)
8061a000 80655000 CLFS (deferred)
80655000 8065d000 BOOTVID (pdb symbols)
8065d000 80666000 PSHED (deferred)
80666000 806c6000 mcupdate_GenuineIntel (deferred)
806c6000 806ce000 kdcom (deferred)
81800000 81b95000 nt (pdb symbols)
81b95000 81bc9000 hal (pdb symbols)
81c06000 81c0e000 spldr (deferred)
81c0e000 81c44000 volsnap (deferred)
81c44000 81cae000 ksecdd (deferred)
81cae000 81db6000 Ntfs (deferred)
81db6000 81def000 NETIO (deferred)
81def000 81e1a000 msrpc (deferred)
81e1a000 81f1e000 ndis (deferred)
81f1e000 81f270c0 PxHelp20 (deferred)
81f28000 81f4f000 sys32v (private pdb symbols)
81f4f000 81f5f000 fileinfo (deferred)
81f5f000 81f90000 fltmgr (deferred)
81f90000 81fae000 ataport (deferred)
81fae000 81fb6000 atapi (deferred)
81fb6000 82000000 volmgrx (deferred)
8234f000 82358000 crcdisk (deferred)
82358000 82368000 agp440 (deferred)
82368000 82389000 CLASSPNP (deferred)
82389000 8239a000 disk (deferred)
8239a000 823bd000 fvevol (deferred)
823bd000 823e2000 ecache (deferred)
823e2000 823f1000 mup (deferred)
823f1000 82400000 partmgr (deferred)
注: 若符号檔案沒有加載成功,Windbg會提示響應的符号找不到,不過一般Windbg會自己尋找符号檔案路徑.實在找不到時,就包含
srv*c:\symbols*http://msdl.microsoft.com/download/symbols, 然後reload一下(!reload).
另外,鍵入lm t n, 我們可以檢視更為詳細的子產品及驅動資訊.
然後,鍵入!thread和Kp,檢視目前的線程詳細資訊和堆棧(或者Alt+6也可以看stack).注意目前thread的ID:
kd> !thread
THREAD 84254ae8 Cid 0004.0008 Teb: 00000000 Win32Thread: 00000000 RUNNING on processor 0
Not impersonating
Owning Process 84254d90 Image: System
Wait Start TickCount 0 Ticks: 1 (0:00:00:00.015)
Context Switch Count 1
UserTime 00:00:00.0000
KernelTime 00:00:00.0015
Win32 Start Address nt!Phase1Initialization (0x819433ae)
Stack Init 81c06000 Current 81c05db8 Base 81c06000 Limit 81c03000 Call 0
Priority 31 BasePriority 8 PriorityDecrement 0
ChildEBP RetAddr Args to Child
81c05af0 818aa92c 00000001 81867999 0002625a nt!RtlpBreakWithStatusInstruction (FPO: [1,0,0])
81c05af8 81867999 0002625a 00000000 00000001 nt!KdCheckForDebugBreak+0x22 (FPO: [0,0,0])
81c05b18 81836cfd 81928100 000000d1 81c05b9c nt!KeUpdateRunTime+0x270
81c05b18 81ba4130 81928100 000000d1 81c05b9c nt!KeUpdateSystemTime+0xed (FPO: [0,2] TrapFrame @ 81c05b28)
81c05b9c 81ba3fd0 81bb28a0 8181dced 81c05bc8 hal!XmGetCodeByte+0x30 (FPO: [Non-Fpo])
81c05bac 81ba40c5 81bb28a0 0000c000 00001da4 hal!XmEmulateStream+0x88 (FPO: [Non-Fpo])
81c05bc8 81ba374d 00000010 81c05c0c 8181dced hal!XmEmulateInterrupt+0x80 (FPO: [Non-Fpo])
81c05bdc 81ba0a1c 00000010 81c05c0c 00000000 hal!x86BiosExecuteInterruptShadowed+0x43 (FPO: [Non-Fpo])
81c05bf8 81ba0a5b 00000010 81c05c0c 00000000 hal!x86BiosCall+0x22 (FPO: [Non-Fpo])
81c05c2c 80656697 80806ae0 8080f438 00000000 hal!HalpBiosDisplayReset+0x25 (FPO: [Non-Fpo])
81c05c58 81b2cd6d 00000001 81b0ab01 80806ae0 BOOTVID!VidInitialize+0x135 (FPO: [Non-Fpo])
81c05c7c 81b3f098 00000001 80806ae0 00000007 nt!InbvDriverInitialize+0x81
81c05d74 819433bb 81c05dc0 819afbad 80806ae0 nt!Phase1InitializationDiscard+0xd0
81c05d7c 819afbad 80806ae0 81c0e680 00000000 nt!Phase1Initialization+0xd
81c05dc0 8189a346 819433ae 80806ae0 00000000 nt!PspSystemThreadStartup+0x9d
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
kd> kp
ChildEBP RetAddr
81c05af0 818aa92c nt!RtlpBreakWithStatusInstruction
81c05af8 81867999 nt!KdCheckForDebugBreak+0x22
81c05b18 81836cfd nt!KeUpdateRunTime+0x270
81c05b18 81ba4130 nt!KeUpdateSystemTime+0xed
81c05b9c 81ba3fd0 hal!XmGetCodeByte+0x30
81c05bac 81ba40c5 hal!XmEmulateStream+0x88
81c05bc8 81ba374d hal!XmEmulateInterrupt+0x80
81c05bdc 81ba0a1c hal!x86BiosExecuteInterruptShadowed+0x43
81c05bf8 81ba0a5b hal!x86BiosCall+0x22
81c05c2c 80656697 hal!HalpBiosDisplayReset+0x25
81c05c58 81b2cd6d BOOTVID!VidInitialize+0x135
81c05c7c 81b3f098 nt!InbvDriverInitialize+0x81
81c05d74 819433bb nt!Phase1InitializationDiscard+0xd0
81c05d7c 819afbad nt!Phase1Initialization+0xd
81c05dc0 8189a346 nt!PspSystemThreadStartup+0x9d
00000000 00000000 nt!KiThreadStartup+0x16
鍵入!process [PID] 0, 查到目前程序:
kd> !process 0004.0008 0
PROCESS 84254d90 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00122000 ObjectTable: 830001d0 HandleCount: 1.
Image: System
VadRoot 00000000 Vads 0 Clone 0 Private 0. Modified 0. Locked 0.
DeviceMap 00000000
Token 83003830
ElapsedTime 00:00:00.015
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (4, 0, 0) (16KB, 0KB, 0KB)
PeakWorkingSetSize 0
VirtualSize 0 Mb
PeakVirtualSize 0 Mb
PageFaultCount 0
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 0
THREAD 84254ae8 Cid 0004.0008 Teb: 00000000 Win32Thread: 00000000 RUNNING on processor 0
在lm指令列出的資訊中,start是子產品的起始位址,通過鍵入"u 驅動起始位址",我們可以反彙編出它的代碼:
kd> u 81f28000
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0x0):
81f28000 4d dec ebp
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0x1):
81f28001 5a pop edx
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0x2):
81f28002 90 nop
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0x3):
81f28003 0003 add byte ptr [ebx],al
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0x5):
81f28005 0000 add byte ptr [eax],al
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0x7):
81f28007 000400 add byte ptr [eax+eax],al
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0xa):
81f2800a 0000 add byte ptr [eax],al
sys32v!SysAllocatePostCopyWorkItem <PERF> (sys32v+0xc):
81f2800c ff ???
逐漸查找(enter),最終我們可以發現driver的入口點.這個過程其實是非常慢的,因為系統核心在加載驅動實際代碼的過程中進行了N多次調用.如果我們本身有驅動的代碼,也可以直接包含源代碼路徑,通過在實際代碼中設定斷點,讓Windbg自己中斷到相應的代碼位置(在實際調試核心的過程中,這幾乎是不可能的,因為你不會得到Windows核心或某個驅動程式的源代碼.Linux系列的某些driver們又另當别論).這裡為了友善,我包含了sys的源代碼,增加斷點直接走到DriverEntry例程:
kd> u 81f42780
sys32v!DriverEntry [隐藏了address]:
81f42780 8bff mov edi,edi
81f42782 55 push ebp
81f42783 8bec mov ebp,esp
81f42785 51 push ecx
81f42786 c745fc010000c0 mov dword ptr [ebp-4],0C0000001h
81f4278d a1749cf481 mov eax,dword ptr [sys32v!SysDbgFlags (81f49c74)]
81f42792 83e004 and eax,4
81f42795 7424 je sys32v!DriverEntry+0x3b (81f427bb)
其中顯示的彙編代碼,是核心調用驅動是進行的操作,其實也和實際代碼相對應.
在driver代碼中,如果要檢視目前參數值,用dv指令:
kd> dv
DriverObject = 0x84663730
RegistryPath = 0x8084b560
status = 8
dontload = 0
另外,用"dt 參數名"可以看某個參數的目前值.
kd> dt DriverObject
Local var @ 0x81c05af8 Type _DRIVER_OBJECT*
0x84663730
+0x000 Type : 4
+0x002 Size : 168
+0x004 DeviceObject : (null)
+0x008 Flags : 2
+0x00c DriverStart : 0x81f28000
+0x010 DriverSize : 0x27000
+0x014 DriverSection : 0x84230a68
+0x018 DriverExtension : 0x846637d8 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING "\FileSystem\Sys"
+0x024 HardwareDatabase : 0x81af6ed8 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"
+0x028 FastIoDispatch : (null)
+0x02c DriverInit : 0x81f4a005 sys32v!GsDriverEntry+0
+0x030 DriverStartIo : (null)
+0x034 DriverUnload : (null)
+0x038 MajorFunction : [28] 0x8189a5c1 nt!IopInvalidDeviceRequest+0
這樣,我們就可以通過上述的這些指令,逐漸分析一個驅動程式在加載和執行過程中的情況。另外,Windbg還有衆多核心調試指令,如!irp可以檢視一個對象的資料結構,!devobj可以檢視裝置對象等,在今後的作業系統核心學習過程中會不斷用到這些指令。
從上面的操作過程我們可以看出,利用Windbg調試驅動程式,或者說進行核心調試,是非常友善的。如果我們對Windows核心有一定的了解,同時擁有一定彙編語言的功底,就可以有Windbg進行簡單的系統排障(比如系統加載是出現藍屏,或是某個系統子產品出現問題)、驅動學習等。同時,這個過程也可以讓我們更深入的了解作業系統原理。另外,Windbg也可以進行系統服務(service)的調試,這就是User mode的調試過程了。