转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家拍砖!
在驱动程序的开发中,经常会遇到系统崩溃一情况,我们很难想像用VC的调试器那样单步调试程序。但还是有一些高级驱动程序调试技巧,
可以帮助找出驱动程序中的Bug。另外,利用一些第三方工具软件,也可以帮助程序员找到驱动程序中的漏洞,从而提高开发效率。
一般性调试技巧包括打印调试信息、查看dump文件等。这些方法在调试驱动中比较常见。
打印调试信息,可以满足大部分的调试需要,然而有时驱动程序员经常遇到蓝屏死机的困扰,这样即便打印了信息,系统崩溃或重启了,驱动程序员也无未能看到。
这时程序员需要设置Dump信息。所谓Dump信息就是在系统崩溃之前,操作系统会将当前的调用的堆栈记录成一个dump文件,这个文件对于以后的分析极为有用。
右键单击“我的电脑”,选择“属性”,弹出“系统属性”对话框。在对话框中,单击“高级”选项卡,然后单击“设置”按钮,弹出一个对话七一,设置写入调试信息。
如下图:
可以选择“小内存转储”或者“完全内存转储”。其中小内存转储只存储64KB的存储信息,信息量少,而“完全内存转储”则将整个4GB的虚拟内存全部存储下来,
这样虽然信息完整,但耗时。
引起蓝屏死机现象可能有多种情况,引起系统蓝屏,最简单的办法就是在程序代码中加入一行ASSERT(0),从而产生一个断言,继而会产生一个异常。
可以说所有蓝屏都是由各类异常引起的,最常见的是读写空指针、读写不可操作的内存区域等。
eg: 在程序中加入一行ASSERT(0),它在check版本中等效于调用RtlAssert函数,而在Free版本中不做任何操作,因此check版本的ASSERT(0) 会引起蓝屏死机.
#pragma PAGEDCODE
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
PAGED_CODE();
KdPrint(("Enter HelloWDMAddDevice\n"));
ASSERT(0);
(1)
Windbg下载地址:http://dl.dbank.com/c0ypf5ytrh
安装后可能找不到Windbg.exe在哪里?后来发现因为我之前安装了DDK驱动开发文件,在DDK的安装下找到了它。
(2)也可以用系统默认的自带工具:
Dump信息,必须用专用的工具软件查看,如WinDbg等工具,在使用WinDbg工具时,最好下载系统的符号表。系统的DLL、EXE、SYS、AX等文件,都会有一个
相应的PDB文件,这就是符号表文件,这个PDB是微软在编译Windows时产生的符号表文件,有了这些信息,就可以知道某段代码属于哪个系统文件中的函数了。
首先,在系统环境变量中设置_NT_SYMBOL_PATH环境变量,内容可以设置为:
SRV *d:\symcache*http://msdl.microsoft.com/download/symbols
其含义是以 http://msdl.microsoft.com/download/symbols作为符号表服务器,一旦需要就可以去这个网站下载符号表,下载后将其存储在d:sysmcache目录中。
其次,安装WinDbg软件,该软件可以调试内核程序,同时还可以观察蓝屏后Dump显示出来的信息。
第一次使用WinDbg调试Dump文件,会等待很长时间,这主要是因为软件会自动到微软网站去下载符号表,即一些PDB文件。
如ntrnlpa.exe就会有对应文件nlknlpa.pdb。程序员自己编写的驱动程序是无法到微软网站下载符号表的,这就需要程序员自己提供了。
参考<<Win7 下分析蓝屏原因的方法>>
高级内核调试技巧一般用WinDbg进行双机调试,一台作为主机,一台作为目标机。
如果使用虚拟软件,如VMWare或Virtual PC等,可以在计算机中模拟出目标机,这样一台计算机就可以进行内核调试。
想像Ring3层的程序一样单步执行,在断点时候观察变量,修改内存,完全知道程序的运行情况,需要费一些周折,
因为驱动程序运行在Ring0层程序,调试软件不可能是Ring3层的程序,这与无法在二维空间观察三维空间是一样的。
WinDbg软件,它可以调试应用软件(Ring3层程序)、驱动程序(Ring0层程序)和蓝屏存储文件,但是在调试驱动程序时,WinDbg需要两台计算机调试,
一台作为主机(HOST),一台作为目标机(TARGET),用一根串口线或一条1394的电缆将两台计算机连接起来。
要安装尽量高版本的VMWare,首先在VMWare中安装一个虚拟的Windows,我们以安装Windows XP SP2为例。
安装方法请参考我的另一篇文章:<
由于是虚拟的PC,并且调试需要一个串口,因此利用虚拟机的虚拟特性,定制一个虚拟串口。
闭虚拟机,来到VMWare之后选择对应的虚拟机,对齐进行设置。
注意:如虚拟机中在添加新的串口前已经存在串口了,那么要把原有的串口Remove掉(特别是有些打印会占用串口),否则会导致windbg.exe与虚拟机连接不上。
使用“虚拟串口”使其建立一条虚拟的串口,一端是虚拟PC的串口COM1,另一端是Window上的管道。
另外,在虚拟机中找到启动配置文件boot.ini,去掉这个文件的只读属性,用记事本打开Boot.ini。
在我的虚拟系统中C盘下找不到boot.ini文件,后来从网上得到了解决。解决方法是:
打开电脑属性——高级——启动与故障恢复——在系统启动栏目下选择手动编辑,就打开boot.ini了。
注意:\WINDOWS的前面没有空格,否则启动会出现下面错误:
boot.ini大概的内容如下:
[boot loader]
timeout=10
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
上面的Timeout选项为等待时间,可以改短一点,如10,表示等待10秒钟。
在文件的最后增加这样一行内容:
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="XP Debug" /fastdetect /debug /debugport=com1 /buadrate=115200
如果要设置默认进入Debug模式,可以把上面这一行内容加到[operating systems]下面:
[boot loader]
timeout=10
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="XP Debug" /fastdetect /debug /debugport=com1 /buadrate=115200
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
之后保存即可。
我们在真的XP环境下开发驱动,经常会遇到蓝屏的现象,这给开发带来很大的痛苦,但是如果将驱动放到虚拟机上运行,如果出现死机就是重启虚拟机,
不会让真机重启,这大大节省了开发难度。
给Windbg创建一个快捷方式,设置一下这个快捷方式的属性:在快捷方式的目标后面增加一些命令,我这里是:
"C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" -b -k com:port=\\.\pipe\com_1,baud=115200,pipe
前面的字符串是Windbg的路径,加上后面的命令就可以了。(加入命令 -b 的作用是:在Windbg连接上时就暂停,如果不想马上处于暂停,那么可以把-b去掉。)
之后,最好给Windbg设置一下符号表。打开Windbg,选择菜单项的“File”->“Symbol File Path”,然后填下:
srv*c:\Symbols*http://msdl.microsoft.com/download/symbols
如上图如果我们勾选了Reload,那么相当于输入了.reload命令,这时开始下载:
表示从网上下载系统对应的符号表到C盘的symbols目录下,只有需要的时候才会下载;对于已经下载的以后就直接用这个文件夹里面的符号表了。
当然实际调试驱动时还要加上自己驱动对应的符号表。当然也可以把系统的Symbols从微软的网站上一次性打包下载下来再解压到C盘的Symbols文件夹。从http://msdn.microsoft.com/en-us/windows/hardware/gg463028可以下载到系统对应的符号表(注意是和虚拟机对应的系统版本)
之后关闭Windbg,会提示是否保存,点击是,保存。
不知为何,符号文件下不下来???????
=========================================================================================================================
现在我们假设你的驱动代码放在D:\mydriver目录中;
系统级Symbol文件存放在C:\WINDOWS\Symbols目录中,这些Symbol文件是从微软的网站上http://msdl.microsoft.com/download/symbols下载而来,这个网址是不可以用IE直接打开的,WinDbgà Fileà Symbol File Path...界面中选择Reload,WinDbg会自动帮你下载;
驱动生成的Symbol文件存放在D:\mydriver\objchk_wxp_x86\i386目录中。
a) 设置驱动Symbol路径,WinDbg->File-> Symbol File Path...为
SRV*C:\WINDOWS\Symbols*http://msdl.microsoft.com/download/symbols; D:\mydriver\objchk_wxp_x86\i386
b) 设置驱动源文件路径,WinDbg->File-> Source File Path…为D:\mydriver
c) 为了保险起见,我们同时设置系统变量。
My Computer -> Properties-> Advanced Tab-> Enviroment Variables->
Add._NT_DEBUG_BAUD_RATE=115200
_NT_SYMBOL_PATH=SRV*C:\WINDOWS\Symbols*http://msdl.microsoft.com/download/symbols
_NT_ALT_SYMBOL_PATH = D:\mydriver\objchk_wxp_x86\i386
_NT_SOURCE_PATH = D:\mydriver
14. 启动VMware,将主机目录C:\WINDOWS\Symbols下的拷贝到虚拟机的相同位置。同时请把驱动编译后生成在D:\mydriver\objchk_wxp_x86\i386目录下的*.pdb、*.sys、*.map、*.exp、*.lib文件一并拷贝到两个系统的C:\WINDOWS\Symbols目录中。
=================================================================================================================================
先打开虚拟机,开启对应的系统进入调试模式(过了菜单选择时间,进入Debug后会停留几秒钟),
选择XP Debug模式, 然后快速双击设置好的Windbg,就会自动连接到虚拟机了,如果Windbg出现如下的提示,那么就OK了:
调试器显示: Connected to Windows XP 2600 x86 compatible target at (Fri Jul 13 09:32:45.090 2012 (GMT+8)), ptr64 FALSE
,此时代表连接目标成功,处于中断状态
Microsoft (R) Windows Debugger Version 6.11.0001.402 X86
Copyright (c) Microsoft Corporation. All rights reserved.
Opened \\.\pipe\com_1
Waiting to reconnect...
Connected to Windows XP 2600 x86 compatible target at (Thu Jul 12 17:06:33.750 2012 (GMT+8)), ptr64 FALSE
Kernel Debugger connection established. (Initial Breakpoint requested)
Symbol search path is: srv*c:\Symbols*http://msdl.microsoft.com/download/symbols;SRV*d:\symcache*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows XP Kernel Version 2600 UP Free x86 compatible
Built by: 2600.xpsp_sp2_rtm.040803-2158
Machine Name:
Kernel base = 0x804d8000 PsLoadedModuleList = 0x805541a0
System Uptime: not available
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:
80527da8 cc int 3
在进行了上述设置后,就可以进行程序调试了。
2、3、1 首先运行VMWare中的虚拟机软件,然后启动新建立的WinDbg快捷方式,不过WinDbg很快就会停止运行,整个虚拟机也会停止下来,这里需要让虚拟机中的
Windows暂停下来,以便可以用Step in,Step out等方式调试。由于此时在Windows的内核下,且没有Windows源代码,所以看到的都是汇编命令,如下图所示:
这时候按F5键或者在命令行中输入g,或者单击“运行”图标,都可以让系统运行起来,这里的操作类似于VC的调试界面。
2、3、2 下一步的事情就是把以上编译的驱动程序放到虚拟机上运行。
这里需要首先解决是的如何将文件复制到虚拟机上,为此VMWare为用户提供了一个工具,叫做VMWare Tools,在VMWare上选择菜单“Install VMWare Tool”,
虚拟机会自动安装一个配套的软件插件。
遇到的问题:
我在选择“Install VMWare Tool”时提示
解决方法:
你先把虚拟机关上,然后下载个VMWARE tools6.iso安装文件,直接搜就行了下载完了之后,在虚拟机设置那儿光驱那里选择ISO镜像(如下图),进去之后,
再次选择“Install VMWare Tool”,安装成功了。
然后在VMWare的工程中,选择“属性”菜单,单击“选项”对话框,选择“共享文件夹”然后选择“Add"按钮,可以为虚拟机设置一个“网络共享”,如下图所示:
当为虚拟机设置好共享后,就可以在虚拟机上使用了;
在虚拟机里的资源管理器中输入\\.host\,就可以找到共享目录,这样就可以将PC中的文件复制到虚拟机的里。
这里先了解一下WinDbg的简单使用方法。WinDbg大部分调试都通过命令行方式,即通过输入命令实现。
(1)断点设置:对于设置的一般断点用bp,后面接函数名或者地址名。如bp HelloWDM!
DriveEntry或者bp 0x12345678。对于清除断点用bc。例如,bc * 代表清除所有断点,bc 1代表第1号清除断点。
对于没有加载符号表的驱动程序,可以使用延迟设置断点,用bu;查看断点用bl
例如,bu HelloWDM!DriveEntry。
此时若通过设备管理把设备卸载的话会有以下的信息:
(2)符号表设置:如果符号表设置成功,就不需要再设置了,但是符号表有时需要手动设置一下。重新加载符号表使用.reload命令。
使用“lm”显示加载的模块,
“lm v”为每个模块提供更详细的信息,“
!lm
“lmo”显示已经加载的模块,
“lml”显示已经加载符号文件的模块,
“lme”显示有符号问题的模块,
“lm m *
手动加载符号表使用.ld命令。
(3)显示驱动对象的相关信息
(3、1)我们以高度CYUSB.sys以例。首先把我们用到的驱动文件及CyConsole工具拷到虚拟机内。
(3、2)插入我们的CY7C68 USB设备,此时虚拟机会提示是否要把此设备连接到虚拟机上,我们点是。
(3、3)因为是虚拟机第一次接受此USB连接,所以提示需要驱动安装;指定目录让驱动安装。
(3、4)在虚拟机中动行我们的工具CyConsole.exe;
(3、5)在CyConsle.exe运行后马上在真机中的WinDbg中按Ctrl+Break让Target中断下来;因为CyConsole.exe会调用cyusb.sys,所以在Command窗口中输入:
!drvobj cyusb 2
!drvobj命令类似于SoftICE中的driver命令,用于显示驱动对象的相关信息;
这样我们将得到 cyusb.sys 驱动的Dispatch routines信息:
(3、6)知道了卸载例程DriverUnload的入口在0xb2237916,于是我们在0xb2237916处设下断点,在Command窗口中输入:
bp 0xb2237916
输入g,让Target继续跑起来,此时我们把USB拨掉。
此时WinDBG把Target中断了下来,中断之处正是我们刚才设置的例程处00xb2237916:
(3、7)从上图可以看出没有为cyusb.sys加载符号文件,下面我们来加载它的符号
将A软件安装在虚拟机中,安装完成后,运行A软件,进入注册界面,此时我们在WinDBG中再次按Ctrl+Break,让Target中断下来,A软件的注册算法在驱动程序snbus.sys中DeviceControl例程中(为什么在snbus中的DeviceControl例程中,请自行跟踪应用程序并查看DDK的相关文档就知道了,这里的重点不是Crack软件,而是讲内核驱动的调试),在Command窗口中输入:
!drvobj snbus 2
!drvobj命令类似于SoftICE中的driver命令,用于显示驱动对象的相关信息,具体的用法请参看WinDBG的帮助文档,当我们输入!drvobj snbus 2时,我们将得到这个驱动的Dispatch routines信息:
(4)添加源文件调试的方法
在windbg.exe停下来时:
*******************************************************************************
nt!RtlpBreakWithStatusInstruction:
8052c5dc cc int 3
现在添加 源文件 和 符号文件 目录
File -> Symbol Search Path -> Browse
"D:/Test7/NT_Driver/objchk_wxp_x86/i386" 把 Reload 勾上
File -> Open Source File ->Driver.cpp
现在以 DriverEntry 和 HelloDDKUnload 函数为例,设置断点,在 command 中输入 " bu HelloDDK!DriverEntry "
bu HelloDDK!HelloDDKUnload
好了,现在输入 g 回车,让操作系统加载起来。
现在在虚拟操作系统里面运行 DriverMonitor ,选择编译好的 sys 文件
点击 Go 按钮,这时候 真实机器 的 WinDbg 收到消息,转到 DriverEntry 入口函数停止下来。注意粉红色的标记
command 窗口显示函数信息:
--GetMcast: 6501a8c0 81f29e00
Breakpoint 0 hit
helloddk!DriverEntry:
f8bb2e90 8bff mov edi,edi
这个时候就可以 按 F10 一步一步执行函数,或按 F11 跳进函数内部查看执行过程。或者按 F5 直接执行到下一个断点处。
下面点击 DriverMonitor 的 stop 按钮。
执行的代码会以高亮显示,command 窗口会打印 KdPrint 的字符串
Enter DriverUnload // <-------------
helloddk!HelloDDKUnload+0x15:
f8bb2725 8b4508 mov eax,dword ptr [ebp+8]