Kmd教程1 For FASM

 

 KmdKit的全称是Kernel Mode Driver development Kit for assembly language programmers,即内核模式驱动程序汇编开发包。程序员

 

1.Kernel Mode驱动程序基础

    本教程讲述了如何在Windows NT为基础的操做系统上用Win32汇编开发KMD,包括NT4.0、2000、XP和2003等操做系统。开发Windows 95/98/ME使用的VxD驱动程序方面的知识并不在本教程讲述的范围内,另外,毫无疑问本教程并不那么完美,可能还包含了诸多未发现的错误,若是您发现了问题,请告知做者,毕竟做者的母语并非英语,把它翻译成英文已经够难为我了(注:原做者是俄国人也),也感谢masquer和Volodya的校对工做。算法

 

    注意本文做者是将MASM翻译成FASM,Thanks for 罗云彬编程

 

1.1 KMD结构概述安全

 

     根据地址空间、代码权限和职责的不一样,Windows NT内部划分为两个大相径庭的部分。网络

 


   
地址空间的享用方式也很是容易理解,整个32位系统的4GB内容被划分为两个相等的部分,用户模式(user-mode)的进程使用的地址空间被映射到低位的2GB上(地址范围00000000 - 7FFFFFFFh),而高位的2GB(地址范围80000000h - 0FFFFFFFFh)则供操做系统的组成部分来使用,如设备驱动程序、系统内存池、系统使用的数据结构等,在这部分中,内存共享的权限和职责等方面就要复杂一点了。

数据结构

 下面就是用户模式进程的一些简单分类:xss


◎ 系统支持进程--如Logon进程(位于/%SystemRoot%/System32/Winlogon.exe)
◎ 服务进程--如Spooler进程(位于/%SystemRoot%/System32/spoolsv.exe)
◎ 用户应用程序--任何Win3二、Windows 3.一、DOS、POSIX或者OS/2程序
◎ 子系统--Windows内置3个子系统:Win32(位于/%SystemRoot%/System32/Csrss.exe)、POSIX子系统(位于/%SystemRoot%/System32/Psxss.exe)和OS/2子系统(位于/%SystemRoot%/System32/Os2ss.exe),在Windows XP以及后续的操做系统中,POSIX和OS/2子系统已经被去掉了。函数


 


 而下面是内核模式的一些模块:工具


◎ 运行模块--内存管理、进程和线程的管理、安全机制等
◎ 内核--线程调度、中断、异常的分派等(运行模块和内核位于/%SystemRoot%/System32/Ntoskrnl.exe)
◎ 设备驱动程序--硬件设备驱动程序、文件系统和网络驱动程序
◎ 硬件抽象层(Hardware Abstraction Layer, HAL)--将内核、设备驱动程序和运行模块和具体的硬件平台隔离开(位于/%SystemRoot%/System32/Hal.dll)
◎ 窗口和图形系统--实现GUI函数,如处理窗口、用户界面的控制和绘画等(位于/%SystemRoot%/System32/Win32k.sys)
学习

 

 、

 

 

 Windows NT结构简图

 

1.1.2 内核模式和用户模式

    Intel x86体系结构的处理器定义了4个级别的权限(称为Ring),Windows系统使用了Ring0(供特权模式使用)和Ring3(供用户模式使用),Windows系统只使用了2个级别的权限级别的缘由是为了和其余一些硬件系统兼容,这些硬件系统只有2个级别的权限,如Compaq Alpha和Silicon Graphics MIPS等。

 

 

  每一个用户模式的进程有其私有的地址空间,这些进程在最低的权限级别下运行(称为Ring3或者用户模式),它们不容许执行CPU的特权指令,对系统所属的数据、地址空间以及硬件等的访问也是被严格限制的,例如,若是某个用户程序访问4G地址空间中的高位2G,那么系统就会当即将其终止执行要注意的是,进程调用系统功能的时候,能够切换到内核模式执行,可是调用结束后,就返回到用户模式了。

  用户模式的进程老是被认为是对操做系统稳定性的潜在威胁,因此它们的权限被严格地限制,任何触及这些限制的举动都将使进程被终止。
    而内核模式的组件则能够共享这些受保护的内核模式内存空间,在特权级别下运行(也称为Ring0),容许执行任何CPU指令,包括特权指令,能够无限制地访问系统数据、代码和硬件资源。
    内核模式代码运行在系统地址空间中,并老是被认为是可信任的,一旦被装载运行后,驱动程序就是系统的一部分,能够无限制地作任何事情。

  总的来讲,用户模式程序被彻底从操做系统隔离,这对操做系统的完整性来讲是件好事情,但对某些种类的应用程序来讲就太头痛了,好比Debug工具。幸运地是,这些在用户模式几乎不可能完成的任务彻底能够经过内核模式的驱动程序来完成,由于这些驱动程序的操做是不受限制的。所以,若是你打算从用户模式存取操做系统内部的数据结构或者函数的话,惟一的方法就是将一个内核模式驱动程序装载到系统的地址空间中(并调用它),这是很简单的事情,操做系统彻底支持这样的操做。


1.2 Windows NT设备驱动程序

1.2.1 设备驱动程序的分类

 

 Windows NT支持的设备驱动程序的范围很广,它们的分类以下:

    用户模式的驱动程序:
◎ 虚拟设备驱动程序(Virtual Device Drivers/VDD)--用户模式的组件,用于为16位的MS-DOS应用程序提供虚拟的执行环境,虽然和Windows 95/98里面的VxD从功能上看起来是差很少的,但实际上二者根本不一样。
◎ 打印驱动程序--将与设备无关的图形转换到和打印机相关的指令

    内核模式驱动程序:
◎ 文件系统驱动程序--实现标准的文件系统模型
◎ 传统设备驱动程序--用于在没有其余驱动程序帮助的状况下控制硬件设备,它们是为老版本的Windows NT系统所写的,可是也能够不加修改地运行在Windows 2000/XP/2003系统上
◎ 视频驱动程序--不用多介绍了吧?
◎ 流驱动程序--支持多媒体设备,如声卡
◎ WDM驱动程序--即Windows Driver Model,WDM包括对Windows NT电源管理和即插即用的支持,WDM能够在Windows 2000、Windows 98和Windows ME下实现,因此在这些操做系统下,WDM驱动程序在源代码级别是兼容的,在有些状况下,在二进制代码级别上也是兼容的

    在不一样的资料中,对驱动程序的分类方法可能彻底不一样,但这并非问题。
    从名称理解,设备驱动程序是用于控制某个设备的,但这个"设备"并不必定指的是物理上存在的设备,它也能够是虚拟设备。
    从文件结构上讲,设备驱动程序就是一个普普统统的PE格式文件,就像其余EXE或者DLL文件同样。设备驱动程序是一个可装载的内核模式模块,通常以SYS为扩展名。他们之间的不一样点在于两种的装载方法是彻底不一样的。实际上,咱们能够把设备驱动程序理解成一个内核模式的DLL,用于完成在用户模式下所不能完成的功能,本质上的不一样就在于咱们没法直接存取设备驱动程序的代码和数据(注:DLL的代码和数据是能够被直接存取的,这方面的资料能够参考《Windows环境下32位汇编语言程序设计一书》中的DLL一章),惟一的存取方式是经过I/O管理器,它提供了简单的驱动程序管理环境


    刚开始学习KMD的开发的时候,你可能感受本身根本就是一个菜虫(旁白:就是比菜鸟还低级,呵呵~~~),由于你之前用Windows API开发程序的经验在这里根本帮不上忙,即便你之前写过n多个(n趋向无穷大……)用户模式下的应用系统也没用。内核提供了彻底不一样的函数和数据结构,以致于你要从头开始了解,并且资料奇缺无比,通常状况下,可供参考的只有头文件。

 

1.2.2 分层的和单层的设备驱动程序

    大部分控制硬件设备的驱动程序是分层的驱动程序,分层驱动的概念就是当用户模式发出一个请求时,每一个请求从高层次的驱动程序逐层处理并流传到低层次的驱动程序中,一个I/O请求的处理可能分步在多个驱动程序中,例如,若是一个应用程序发出读盘请求,处理请求会在多个驱动程序中流过,在其中你也能够再加入n多个过滤驱动程序(好比插入一个加解密的模块)。


    单层的驱动程序是最简单的一类驱动程序,这一类驱动程序一般并不依赖于其余已装载的驱动程序,他们的接口仅仅针对用户模式的应用程序,开发和调试这一类驱动程序是很是简单的,咱们即将开始讨论的就是这类程序,其余类型的驱动程序将在之后讨论。

1.3 线程上下文(Thread Context)

    在大多数状况下,咱们的系统中只安装了一个CPU,因此,对于全部这些运行中的程序来讲,操做系统对每一个进程中的线程所使用的CPU时间进行调度,循环为每一个线程分配时间片,这就形成了多个程序同时执行的假象。若是系统中安装了多个CPU,那么操做系统的调度算法将复杂得多,由于它要将各CPU上的线程进行平衡。若是Windows检测到一个新线程要开始运行了,它将进行一次上下文切换(context switch)(注:上下文(Content)实际上就是线程运行的环境,也就是运行时各寄存器和其余东东的状态,更天然的理解就是"线程状态")。所谓上下文切换就是保存线程运行时的机器状态,而后将另外一个线程的状态恢复并从新开始执行。若是从新开始执行的线程属于另外一个进程,那么该进程的地址空间也将被同时切换过来(经过在CR3寄存器中装入页表)。
    每一个用户进程都有私有的地址空间,因此他们的页表都是不一样的,CPU经过切换页表来将虚拟地址映射到物理地址,设备驱动程序并不须要直接作这些工做。上下文切换比较耗CPU时间,因此驱动程序通常不建立它们本身的线程,它们通常在下列环境中的一个中运行:

1. 在发起I/O请求的用户线程中运行
2. 在内核模式下的系统线程中运行
3. 做为中断运行(并不处于哪一个特定的进程或线程中,由于它们都被暂时挂起了)

    在处理I/O请求包(IRPs)时,咱们老是运行在和用户模式的调用者相同的进程上下文中运行,这样咱们就能对用户程序的地址空间进行寻址。可是当驱动程序被加载或者卸载的时候,咱们将在系统进程中运行,这时存取的只能是系统的地址空间。

 

1.7 汇编程序员使用的KmdKit

    KmdKit包含了全部用汇编开发KMD所须要的东西:include文件、lib文件、宏定义、例子文件、工具和一些文章,你能够本身在软件包中找到更多的东西,下一节咱们将从这个软件包中包括的一些例子开始学习KMD的编程。

1.8 驱动程序的调试    调试内核模式的代码须要合适的调试器,Compuware的SoftIce是个不错的选择(见 http://www.compuware.com/products/numega/index.htm),固然你也可使用Microsoft Kernel Debugger,它须要两台计算机:主机和目标机器,目标机器是被调试的机器,主机是运行调试软件的机器。Mark Russinovich ( http://www.sysinternals.com/ ) 也写了一个工具,叫作LiveKd,它容许在单台机器上运行Microsoft Kernel Debugger,而再也不须要两台机器了。