派遣函数 - 跟踪IRP的利器/RPTrace
IRP是驱动程序中重要的数据结构,可以说驱动程序的运行是由IRP所“驱动”的。在驱动程序中,仅凭查看log信息有时候是不能满足调试需要的,程序员往往需要更直观地跟踪IRP的传递、转发、结束等操作。
有时候IRP的处理非常复杂,跟踪IRP显得尤为重要。这里介绍一个工具软件IRPTrace,这个软件可以从网上下载试用版或者购买完整版。
以下简单介绍一下该软件的使用方法。
(1)用IRPTrace 跟踪各类 IRP
或者选择菜单“Mesmage”|“Hook Setup”。然后会弹出一个窗口,
如下图所示,选中左边的“Driver”选项卡,程序会枚举出系统加载的所有驱动程序。
在本例中,选中驱动程序 HelloDDK,这时,右面会列出需要跟踪的IRP类型,
选择“ALL”。
或者选择菜单“Mesnge”|“Clear IRP 1og”,将前面的log信息清除,至此,已经做好了跟踪前的准备。下面所要做的就是执行之前“通过设备链接打开设备”这节的应用程序,IRPTrace会自动跟踪IRP。
(2)用IRPTace 观察IRP数据结构中的各项内容。
将IRPTrace 程序最小化,执行“通过设备链接打开设备”中的应用程序会发现有三个IRP被跟踪下来,分别是IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_CLEANUP,这和预期的完全一致。程序左边列出了跟踪到的IRP,右边会列举出具体的IRP跟踪信息示。
从图中可以査看IRP_MJ_CREATE的详细信息。首先程序列出IRP数据结构的指针该地址是内核模式下的地址,所以是4GB 空间中的高 2GB 部分,紧接着列出了IRP的主类型和子类型。然后列出的是 Target Device,这是 IRP 发送到设备栈中遇到的第一个设备。然后列出的是IRP的完成状态,这个例子中的完成状态是,这个例子中的完成状态是 STATUS_SUCCESS。然后列出的是该IRP是出自于哪个进程和哪个线程,在本例中IRP是出自 Test.exe 进程中的0x7f8号线程。
(3)观察IRP的每层I/O堆栈
最后我们还能査看IRP请求是如何被结束的,本例中IRPTrace指出IRP是在HelloDDK驱动程序中被结束的,位置是 HeloDDK.sys!+40EEh。有兴趣的同学可以对HelloDDK 进行反汇编,可以看出调用 IoCompleteRequest 的位置恰恰就是 40EEh 位置。
除了查看 IRP 相关信息,IRPTrac 还可以査看IO_STACK _LOCATION 信息。单击 Stack Locations 的超链接,得到详细信息。
(4)设置符号表
需要指出的是,IRP请求是在HelloDDK.sys!+40EEh的位置被结束的,但很难知道HelloDDK.sys!+40EEh这个位置对应源代码的什么位置。如果想将这个地址与源程序中位置对应起来查看,需要正确设置驱动程序的符号表。微软的编译器在编译程序时会生成符号表文件,它可以将行号,变量名等和二进制代码的偏移位置对应起来。符号表一般存储在pdb文件中。驱动程序被编译后,都会伴随产生一个相应的pdb文件。
选择“Tools”|“Terminal Option” | "Symbols",出现图4所示的界面,将次驱动对应的pab的路径加入到符号表路径中。
这样就完成了对符号表的配置。HelloDDK.sys!+40EEh被替换成了HelloDDK.sys!HelloDDKDispatchRoutine+8D(F7A610EE)。
另外,IRPTrace还可以再系统启动时就进行跟踪。选择菜单“Tools" |"IRPTrace Driver Control",会弹出一个对话框如图5所示。
如果需要在系统启动时跟踪 IRP,请选择“Startup Type”下拉菜单中“Boot”。
IRPTrace会非常详细的列出IRP的处理过程,这有利于程序员跟踪 IRP。
以后会介绍更多的跟踪工具,利用这些工具,程序员既可以方便的跟踪调试驱动,
同时又可以加深对内核的了解。