第三章:编写内核模式驱动
gushaow@mails.gscas.ac.cn
除了文档,DDK还提供了特别的头文件和导入库去和windows 2000内核模块交互。
主要的问题在于VC没有提供一个生成内核模式驱动工程的向导。本书中提供了一个内核模式驱动向导,在/src/w2k_wiz中有完全的源代码。事实上这个模板可以生成好几种类型的工程,包括Win32动态连接库和应用程序。
驱动程序的入口是DriverEntry(),当然可以在连接的时候通过/entry来设置成别的名字。驱动初试化的时候首先创建设备对象和符号链接,然后保存设备对象和设备上下文的值。接着设置所有可接受的IRP的回调处理函数以及DriverUnload函数指针。
#pragma alloc_text(INIT,DriverEntry),使得DriverEntry存储在另一个代码段INIT中而不是默认的代码段。驱动加载器能够认出这个特别的段,并在初试化完成之后丢弃它。
接下来的章节将出现的代码使用叫做设备I/O控制(IOCTL)的技术使得允许用户模式代码某种程度上的远程控制。如果一个程序需要存取某些在用户模式下无法获得的系统资源,内核模式驱动可以完成这个工作,IOCTL将架起两者之间的桥梁。当然两者之间必须自定义一个通信协议。
l 客户通过特别的入口点控制设备,也就是kernel32!DeviceIoControl()。
l 客户提供一个设备表示,一个控制代码,一个输入数据缓冲。设备表示就是成功打开的设备的句柄。
l 控制代码告诉目标设备的IOCTL分发例程要调用哪个控制函数。
l 操作的结果通过一个状态代码报考给客户
加载和卸载驱动
一般来说,驱动是在系统启动的时候加载和开始的。但是可以通过服务控制管理器动态加载和卸载驱动。
服务是2k用于在后台运行程序的强大模块,跟用户界面外壳独立。也就是说,服务是一个即使没有用户登陆也可以运行的进程。参考Windows Developer’s Journal,1996a,和1996d,Paula Tomlinson的两篇文章。
服务控制管理器可以处理服务和驱动程序。
服务控制管理器的接口通过advapi32.dll开放给Win32程序。在能够加载和存取任何服务之前,必须打开服务控制管理器的句柄,调用OpenSCManager()。以下是服务控制管理器的用于加载和卸载服务/驱动的接口函数列表。
NAME | DESCRIPTION |
CloseServiceHandle | Close handle obtained from openscManager() , createservice ( ) , or OpenServicef ) |
ControlService | Stop, pause, continue, interrogate, or notify a loaded service/driver |
CreateService | Load a service/driver |
DeleteService | Unload a service/driver |
OpenSCManager | Obtain a handle to the SC Manager |
OpenService | Obtain a handle to a loaded service/driver |
QueryServiceStatus | Query the properties and the current state of a service/driver |
StartService | Start a loaded service/driver |
加载驱动的一般过程:
1. Call OpenSCManager ( ) 获得管理器句柄
2. Call CreateService ( )给系统添加服务/驱动
3. Call StartService ( ) 启动服务/驱动
4. Call CloseServiceHandle ( ) 释放管理器和服务/驱动句柄.
如果StartService调用失败,必须调用DeleteService,另外CreateService函数需要一个全路径参数,如果是相对路径,调用就会失败,所以必须先用GetFullPathName获得路径。
服务控制管理器提供了一个函数,用于枚举:EnumServicesStatus。