进程的空间空际上被分成了两部分。一部分供进程独立使用,称为用户空间:另一部分容纳操作系统的内核,称为内核空间,或称为系统空间。具体到可以容纳4GB内存空间的32位Windows系统上,低2GB是用户空间,高2GB是内核空间。用户空间是各个进程隔离的,但是内核空间是共享的。也就是说,每个进程看见的高2GB空间范围内的数据,都应该是一样的。这是一个非常重要的概念。
内核空间是受到硬件保护的,比如X86加构下R0层(Ring 0)的代码才可以访问内核空间。普通应用程序编译出来之后都运行在R3层,R3层的代码要调用R0层的功能时 ,一般通过操作系统提供的一个入口(该入口中调用sysenter指令)来实现。
内核模块位于内核空间,而内核空间又被所有的进程共享。因此,内核模块实际上位于任何一个进程空间中。但是任意一段代码的任意一次执行, 一定是位于某个进程空间中的。这个进程是那一个?这取决于请求的来源、处理的过程等。
Windows的所谓系统进程是一个名为"system"的进程,是Windows自身生成的一个特殊进程,这个进程在Windows XP下PID始终为4。读者只要调用PsGetCurrentProcessId就会发现内核模块中分发函数调用时,当前进程一般都不是system进程。但是DriverEntry函数被调用时,一般都位于系统进程中。这是因为Windows一般都用系统进程来加载内核模块,并不说明内核代码始终运行在system进程里。
一个驱动对象(DRIVER_OBJECT)代表一个驱动程序或者说是一个内核模块。内核模块并不生成一个进程,只是填写一组回调函数让Windows来调用,而且这组回调函数必须符合Windows内核规定。
设备对象是内核中的重要对象,其重要性不亚于Windows GUI编程中的窗口(Windows).进行过Windows窗口应用程序开发的读者都知道,窗口是唯一可以接收消息的东西,任何消息都是发送给一个窗口的。而在内核世界里,大部分“消息”都可以请求(IRP)的方式传递。而设备对象(DEVICE_OBJECT)是唯一可以接收请求的实体,任何一个“请求”(IRP)都是发送给某个设备对象的。
大部分内核API都有前缀,主要的函数以Io-、Ex-、Rtl-、Ke-、Zw-、Nt-、和Ps-开头。些外,与NDIS网络驱动开发相关的函数几乎都是以Ndis- 开头的,与开发WDF驱动相关的函数都是以Wdf-开头的。
IO管理器就是将用户调用的API函数翻译成IRP或者将等价请求发送到内核各个不同的设备的关键组件。
在Windows系统上与安全软件相关的驱动开发过程中,“过滤”是极其重要的一个概念。过滤是在不影响上层和下层接口的情况下,在Windows系统内核中加入新的层,从而不需要修改上层的软件或者下层的真实驱动程序,就加入新的功能。
进行过滤的最重要的方法是对一个设备对象(Device Object)进行绑定。
通过编程可以生成一个虚拟的设备对象,并“绑定”在一个真实的设备上。一旦绑定,则本来操作系统发送给真实设备的请求,就会首先发送到这个虚拟设备。
驱动与应用层交互
Create
Read
Write
DeviceIoControl
Close
驱动服务安装
安装:
OpenSCManager()
CreateService()/OpenService()
StartService()
卸载:
OpenSCManager()
ControlService() -- SERVICE_CONTROL_STOP
DeleteService()
内核模块并不生成一个进程,只是填写一组回调了函数让Windows来调用,而且这组回调函数必须符合Windows内核规定。
这一组回调函数包括上面的“普通分发函数”(MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1])和“快速IO分发函数”。这些函数用来处理发送给这个内核模块的请求,一个内核模块所有的功能都由它们提供给Windows.
Windbg中的调试命令分为3种:基本命令、元命令、扩展命令
基本命令和元命令是调试器自带的
元命令是以"."点开头;而扩展命令是外部加入的,总是以感叹号"!"开头。
有效的内核同步方法有3种:内核事件同步、IRP同步和WMI同步
关于文件过滤的学习:
文件系统的设备对象
文件系统过滤虽然复杂,但是基本方法还是一样的,就是生成过滤设备对象来绑定真实的设备对象。
文件系统驱动(c:\windows\system32\drivers目录下两相fastfat.sys与ntfs.sys)
在文件系统驱动程序会生成两类设备:控制设备CDO与文件系统的卷设备
文件系统驱动会生成哪些设备对象?
像FAT32、NTFS这样的文件系统,主要生成两类设备。
首先文件系统驱动本身往往生成一个控制设备CDO,这个设备的主要任务是修改
整个驱动的内部配置。因此,一般的说,一个文件系统只对应一个CDO
另一种设备是这个文件系统的卷设备。一般一个卷对应一个逻辑盘。
说明:请注意这个卷设备本身并不是文件系统驱动生成的,而是卷管理
器生成的。但是当有一个卷使用了某种文件系统时,则该文件系统会对应
地为该设备生成一个没有名字的设备对象。
驱动对象结构DRIVER_OBJECT中既然有快速IO分发函数的设备接口,那么理
论上讲,所有的驱动对象都可以有快速IO分发函数---只是它们可能根本没
有被设置。但是文件系统不行,如果不设置,上层依然会调用,而且会导致
蓝屏。
快速IO分发函数是独立于普通的处理IRP的分发函数之外的另一组接口。但是
它们的作用是一样的,就是由驱动处理外部给予的请求,而且所处理的请求
也基本相同,只是根本没有IRP,本来应该写在IRP中的参数,被直接通过函数
的参数传递进来了。这可以减少分配IRP的效率消耗。
请注意,如果一个调用可以在高级处运行,那么它就能在低处运行,反过来则不行。
Windows本身有一个系统线程负责处理一些日常工作,也可以把自己的工作任务
插入其中,免除需要多生成一个线程的开销。
LARGE_INTEGER这是一个在Windows驱动开发中常用的64位整数数据的共用体。