轉載註明>> 【作者:張佩】【原文:www.yiiyee.cn/blog/】
引子
使用Windbg調試目標對象的時候,用戶發現到它的一個缺陷,就是不能自動識別目標設備的機器名。實際上Windbg總是標出了Machine Name的關鍵字,但卻從來都沒有顯示。可以認爲Windbg在這個地方有點小缺陷。見下面的例子:
0:000> vertarget
Windows 7 Version 7601 (Service Pack 1) MP (8 procs) Free x64
Product: WinNt, suite: SingleUserTS
kernel32.dll version: 6.1.7601.18015 (win7sp1_gdr.121129-1432)
Machine Name: //空空如也
Debug session time: Thu Aug 22 10:11:04.000 2013 (UTC + 8:00)
System Uptime: 14 days 17:26:44.613
Process Uptime: 14 days 17:14:25.000
Kernel time: 0 days 0:09:02.000
User time: 0 days 0:42:36.000
在調試一些很困難問題的時候,比如目標系統boot失敗、桌面不能正常顯示、dump分析,這些情況下,我們沒法通過登錄到目標機器上去查看機器名,只能藉助Windbg來實現。雖然Windbg沒有自動顯示功能,但仍然可以通過兩種方法來實現手動實現。我們分兩種情況來講:用戶調試環境(或用戶dump),內核調試環境(或內核dump)。用戶調試環境
在用戶調試的時候,可以通過進程的當前查看環境COMPUTERNAME。查看環境變量有下面兩種方法:
1. 執行!PEB命令,可列舉出當前進程使用的全部環境變量
2. 執行!envvar xxx 命令,查看指定的環境變量,如下所示:
0:000> !envvar computername
computername = MOZHANG
這臺目標設備的機器名是Mozhang。
內核調試環境
用戶調試環境中,這是唯一的辦法。在內核調試環境中,我們也可以通過查看指定進程的環境變量,來實現。不過步驟略複雜一些,因爲如果當前進程是System進程、會話管理器進程、子系統進程等OS的進程,它們這些進程裏面的PEB中,是沒有COMPUTERNAME環境變量的(System進程則沒有PEB),直接執行!peb或!envvar就會無效,這種情況下,需要把當前進程切換到其它進程去。
0: kd> !process // 當前進程爲System進程 PROCESS fffffa8007288040 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00188000 ObjectTable: fffff8a000003000 HandleCount: 364. Image: System VadRoot fffffa800911a840 Vads 9 Clone 0 Private 16. Modified 6371. Locked 64. DeviceMap fffff8a00000c500 0: kd> !envvar computername 0: kd> !peb PEB NULL... // PEB爲空也
如果遇到這種情況,必須避開這些進程,切換到其它進程去,步驟如下:
6: kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS fffffa8007288040 // System進程不用,PEB爲空 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00188000 ObjectTable: fffff8a000003000 HandleCount: 385. Image: System PROCESS fffffa800981a540 // 會話管理器進程不用 SessionId: none Cid: 013c Peb: 7f607a64000 ParentCid: 0004 DirBase: 03dd0000 ObjectTable: fffff8a00029e600 HandleCount: 36. Image: smss.exe PROCESS fffffa8009cc5800 // 子系統進程不用 SessionId: 0 Cid: 01a0 Peb: 7f65140f000 ParentCid: 0194 DirBase: 108ad0000 ObjectTable: fffff8a0009ced80 HandleCount: 96. Image: csrss.exe PROCESS fffffa80073c5080 // 此進程可用 SessionId: 0 Cid: 01f0 Peb: 7f633826000 ParentCid: 0194 DirBase: 10a276000 ObjectTable: fffff8a00134ed80 HandleCount: 84. Image: wininit.exe 6: kd> .process /i fffffa80073c5080 You need to continue execution (press 'g' <enter>) for the context to be switched. When the debugger breaks in again, you will be in the new process context. 6: kd> g Break instruction exception - code 80000003 (first chance) nt!DbgBreakPointWithStatus: fffff800`f227b930 cc int 3 4: kd> !envvar computername computername = mozhang上面是分了三個步驟:
1. 列舉進程列表,用!process 0 0 命令。在列出的所有進程中,任意選擇一個,只要不是那幾個系統的進程即可。
2. 切換到指定進程,通過.proces /i xxx命令,xxx爲內核進程對象的地址。進程切換是發送命令給目標設備的系統進行處理的,所以要執行以下go命令,以使目標設備有時間去完成進程切換的工作。
3. 執行!Peb或!envvar xxx命令。
上面介紹的是通過環境便來來獲取目標機器名。在內核調試的時候,還有另一種更方便的辦法,這種辦法也是MSDN文檔裏有說明的。原來在系統的srv.sys模塊中,通過一個全局變量srv!srvcomputername保存了本機的機器名。這樣的話,我們只要查看這個變量就可以了。此變量的類型爲UNICODE_STRING。我們通過下面的方法來實現:
6: kd> x srv!srvcomputername
fffff880`07107048 srv!SrvComputerName = <no type information>
6: kd> dt nt!_unicode_string fffff880`07107048
"mozhang"
+0x000 Length : 0xE
+0x002 MaximumLength : 0xE
+0x008 Buffer : 0xfffff8a0`02eaac90 "mozhang"
有人擔心,如果我沒有srv.sys的符號文件怎麼辦。這一點是沒問題的,srv.sys是微軟的系統模塊,我們可以通過微軟的公共符號服務器獲取它的public符號文件。參考:http://msdn.microsoft.com/en-us/library/windows/hardware/ff543991(v=vs.85).aspx