使用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 // 系统进程不用,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 命令。在列出的所有进程中,任意选择一个,只要不是那几个OS的进程即可。
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符号文件。