派遣例程与IRP结构

提到派遣例程,必须理解IRP(I/O Request Package),即"输入/输出请求包"这个重要数据结构的概念。Ring3通过DeviceIoControl等函数向驱动发出I/O请求后,在内核中由操作系统将其转化为IRP的数据结构,并"派遣"到对应驱动的派遣函数中,如图21.1.6所示。

Ring3程序调用kernel32.dll导出的DeviceIoControl函数后,会调用到ntdll.dll导出的NtDeviceIoControlFile函数,进而调用到系统内核模块提供的服务函数NtDeviceIo ControlFile,该函数会将I/O请求转化为IRP包,并发送到对应驱动的派遣例程函数中。对于其他I/O相关函数,如CreateFile、ReadFile、WriteFile、GetFileSize、SetFileSize、CloseHandle等也是如此。

 
图21.1.6 从Ring3的I/O请求到内核的IRP请求包

一个IRP包该发往驱动的哪个派遣例程函数,是由IRP结构中的MajorFunction属性决定的,MajorFunction属性的值是一系列宏,如下所示。

  1. //
  2. // Define the major function codes for IRPs.
  3. //
  4. #define IRP_MJ_CREATE                   0x00
  5. #define IRP_MJ_CREATE_NAMED_PIPE        0x01
  6. #define IRP_MJ_CLOSE                    0x02
  7. #define IRP_MJ_READ                     0x03
  8. #define IRP_MJ_WRITE                    0x04
  9. #define IRP_MJ_QUERY_INFORMATION        0x05
  10. #define IRP_MJ_SET_INFORMATION          0x06
  11. #define IRP_MJ_QUERY_EA                 0x07
  12. #define IRP_MJ_SET_EA                   0x08
  13. #define IRP_MJ_FLUSH_BUFFERS            0x09
  14. #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
  15. #define IRP_MJ_SET_VOLUME_INFORMATION   0x0b
  16. #define IRP_MJ_DIRECTORY_CONTROL        0x0c
  17. #define IRP_MJ_FILE_SYSTEM_CONTROL      0x0d
  18. #define IRP_MJ_DEVICE_CONTROL           0x0e
  19. #define IRP_MJ_INTERNAL_DEVICE_CONTROL  0x0f
  20. #define IRP_MJ_SHUTDOWN                 0x10
  21. #define IRP_MJ_LOCK_CONTROL             0x11
  22. #define IRP_MJ_CLEANUP                  0x12
  23. #define IRP_MJ_CREATE_MAILSLOT          0x13
  24. #define IRP_MJ_QUERY_SECURITY           0x14
  25. #define IRP_MJ_SET_SECURITY             0x15
  26. #define IRP_MJ_POWER                    0x16
  27. #define IRP_MJ_SYSTEM_CONTROL           0x17
  28. #define IRP_MJ_DEVICE_CHANGE            0x18
  29. #define IRP_MJ_QUERY_QUOTA              0x19
  30. #define IRP_MJ_SET_QUOTA                0x1a
  31. #define IRP_MJ_PNP                      0x1b
  32. #define IRP_MJ_PNP_POWER                IRP_MJ_PNP      // Obsolete....
  33. #define IRP_MJ_MAXIMUM_FUNCTION         0x1b

MajorFunction最多有0x1b(27)个,也就是说驱动中最多可以设置27个不同的派遣例程函数。helloworld.c中为了简单,将所有的派遣例程都设置到了DrvDispatch函数,并且DrvDispatch函数中只做了最简单的处理。

IRP的数据结构非常复杂,如果全部展示出来恐怕需要好几页的篇幅。"授人以鱼不如授人以渔",因此这里重点给出学习IRP数据结构的方法。

对于初学者,在安装了最新版的WDK后,可以通过WDK Help中的"WDK Documentation"文档来学习IRP数据结构,如图21.1.7所示。

 
(点击查看大图)图21.1.7 通过WDK帮助文档学习内核数据结构IRP

该文档会重点介绍驱动程序中用到的一些IRP成员的含义和使用方法,另外文档末尾还有一段Comments,也是非常有价值的内容。

WDK文档中省略了IRP结构中的某些成员(Undocumented members),如果阅读了文档中IRP的Comments后,就会知道这些Undocumented members之所以被保留,是因为只有I/O manager或FSDs才能使用这些成员。为了更全面地了解IRP的数据结构,更直接的办法是找到WDK中定义IRP的头文件,阅读其中的注释。例如,头文件在这里的路径是D:\WINDDK\7600.16385.0\ inc\ddk\wdm.h,其中对IRP定义如图21.1.8所示。

 
图21.1.8 通过WDK头文件wdm.h学习内核数据结构IRP

为了灵活地查阅内核数据结构信息,还可以使用一些PDB辅助工具。一般地,内核数据结构大多定义在内核模块中。有了内核模块,还需要得到对应的PDB符号文件,这里推荐使用SymbolTypeViewer免费工具来下载符号文件。该工具使用非常简单(下载链接:http://www.laboskopia.com/download/SymbolTypeViewer_v1.0_beta.zip),如图21.1.9所示。

 
(点击查看大图)图21.1.9 通过SymbolTypeViewer免费工具下载符号文件

启动SymbolTypeViewer后,单击"File"按钮,选择本机的内核模块文件(例如C:\WINDOWS\system32\ntkrnlpa.exe),然后单击"Symbol Path"按钮,选择要保存符号文件的路径,再单击"Server"按钮,选择默认的微软链接,最后单击"Get Symbols"按钮,就开始下载符号了。点击左侧树形控件中的符号项,右侧的"Info"窗口中就会列出该符号的相关信息,例如这里的D:\WINDOWS\Symbols\ntkrpamp.pdb\140D20ABBC1B433EA7BF82B979B6BF

9D1\ntkrpamp.pdb。

下一步就是浏览下载到的PDB文件,虽然SymbolTypeViewer工具也支持对内部符号的浏览,但是没有链接功能,不太方便。这里推荐使用另一个专门浏览PDB符号信息的免费工具PDB_Explorer(http://blog.titilima.com/wp-content/uploads/attachments/date_200907/pdbexp_v1.10.zip)。

启动PDB Explorer后,单击"打开"按钮,选择前面下载的PDB文件,然后在搜索框中输入"_IRP",在选择列出的第一个匹配项"_IRP",在右侧的内容区就可以看到如图21.1.10所示的符号信息。

可以看到PDB Explorer是支持前进后退的,即展示出的结构体中,如果有类似union或子struct等成员时,还可以"点"进去浏览更多信息。这样浏览的好处是,不至于"一口吃个大胖子",循序渐进地掌握类似IRP这样复杂的内核数据结构。

以上是一些学习内核数据结构的方法,希望这些内容能够起到"授人以渔"的作用,更希望读者能够通过这些方法逐渐理解IRP结构中每个成员的含义和用法。

 
(点击查看大图)图21.1.10  通过PDB Explorer免费工具浏览符号文件
时间: 2024-10-20 08:52:59

派遣例程与IRP结构的相关文章

YJX_Driver_016_为DDK_HelloWorld添加默认派遣例程

1. [145]IRP简介 [205]IRP作用: 上层应用程序 与 底层驱动通信.exe程序 与 sys . [245]5种常用IRP类型 [305]IRP也可以用于 驱动与驱动间的通信 IRP_ML_CREATE(0x00) // 一般由用户层的CreateFile函数产生 IRP_ML_CLOSE // 一般由用户层的CloseHandle函数产生 IRP_ML_READ IRP_ML_WRITE IRP_ML_DEVICE_CONTROL 2.

IRP 与 派遣函数

什么是派遣函数: 派遣函数是 WIndows 驱动程序中的重要概念.驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的.也就是说,派遣函数是用来处理驱动程序提交过来的 I/O 请求. 那什么是 I/O 请求呢? 上层程序与驱动程序之间通信时,上层会发出I/O请求,即输入输出请求包(I/O Request package) 用户模式下(上层)与所有驱动程序之间的I/O请求,全部由操作系统转化为一个叫 IRP 的数据结构,不同的 IRP 会被派遣到不同的派遣函数(Dis

IRP和IO_STACK_LOCATION结构的关联

IRP结构中的IRP!StackCount--IRP!CurrentLocation--IRP!CurrentStackLocation三个字段关系错综,仅以此文已做备忘. //IRP结构后面接一个IO_STACK_LOCATION数组 typedef struct _IRP { CSHORT Type; USHORT Size; struct _MDL *MdlAddress; ULONG Flags; union { struct _IRP *MasterIrp; volatile LONG

IRP派遣操作

IRPTrace工具跟踪IRP 派遣函数(Dispathc Funtion)是windows驱动中的重要概念.驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的.用户模式下所有对驱动程序的I/O请求.全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会派遣到不同的派遣函数中. IRP(I/O Request Package) 和windows应用程序的消息处理机制相似. IRP中一个MajorFunction, 其保存派遣的函数 如: pDriverOb

IO_STACK_LOCATION与IRP的一点笔记

IO_STACK_LOCATION和IRP算是驱动中两个很基础的东西,为了理解这两个东西,找了一点资料. 1. IRP可以看成是Win32窗口程序中的消息(Message),DEVICE_OBJECT可以看成是Win32窗口程序中的窗口(Window) 2. 任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序.IRP的头部有一个当前IO_STACK_LOCATION的数组索引,同时也有一

[转&精]IO_STACK_LOCATION与IRP的一点笔记

IO_STACK_LOCATION和IRP算是驱动中两个很基础的东西,为了理解这两个东西,找了一点资料. 1. IRP可以看成是Win32窗口程序中的消息(Message),DEVICE_OBJECT可以看成是Win32窗口程序中的窗口(Window) 2. 任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序. IRP的头部有一个当前IO_STACK_LOCATION的数组索引,同时也有

从IRP说起(转)

原文链接:http://www.cnblogs.com/zhuyp1015/archive/2012/03/14/2396595.html IRP(I/O request package)是操作系统内核的一个数据结构.应用程序与驱动程序进行通信需要通过IRP包.当上层应用程序需要与驱动通信的时候,通过调用一定的 API函数,IO管理器针对不同的API产生不同的IRP,IRP被传递到驱动内部不同的分发函数进行处理.对于不会处理的IRP包需要提供一个默认的分 发函数来处理. 现在我们来看一下IRP的

Delphi中根据分类数据生成树形结构的最优方法

一. 引言:    TreeView控件适合于表示具有多层次关系的数据.它以简洁的界面,表现形式清晰.形象,操作简单而深受用户喜爱.而且用它可以实现ListView.ListBox所无法实现的很多功能,因而受到广大程序员的青睐.    树形结构在Windows环境中被普遍应用,但在数据库开发中面对层次多.结构复杂的数据,如何快速构造树形目录并实现导航呢?    二. 实现关键技术:    在Delphi提供的控件中包含了TreeView控件,但树的具体形成还需要用户编写代码.即它的列表项要在程序

派遣函数

派遣函数是Windows驱动程序中的重要概念,驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理. 用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”到不同的的派遣函数中,这也是派遣函数名字的由来. IRP处理机制类似Windows应用程序中的“消息处理”机制,驱动程序接到不同类型的IRP之后,会进入不同的派遣函数,在派遣函数中IRP得到处理. IRP的两个基本的属性:一个是MajorFuntion,一个是