《电子技术应用》
您所在的位置:首页 > 嵌入式技术 > 业界动态 > Windows 9x内核模式驱动程序的设计与策略

Windows 9x内核模式驱动程序的设计与策略

2009-04-16
作者:谭章熹

  摘 要: 在Windows 98或Windows 95下如何高效编写硬件设备驱劝程序是微机应用开发中迫切需要解决的问题。介绍了虚拟设备驱动程序(VxD)在Windows 9x下运行的机理和通信策略,以及如何设计内核模式驱动程序。
  关键词: 保护模式 VMM VxD DPMI


  1995年Microsoft公司推出了其新一代的桌面操作系统Windows 95,从技术层面来看它是为发挥32位处理优越性能而设计的一个32位操作系统。而它出色的稳定性,强大的寻址能力,无不归功于对32位处理保护模式的充分应用。具体来讲,它利用了80386的保护机制,从操作系统到一般应用程序分别分到4个特权层上,操作系统享有最高的优先级,被安排在ring-0上运行,而优先级最低的普通应用程序被安排在ring-3上运行。这样做的好处是如果一般的应用程序在ring-3上崩溃将不会影响到ring-0的操作系统,另一方面也是对在ring-3上的应用程序所能访问到的资源做了一定的限制,从而大大降低了因应用程序直接操作而产生的意外错误。换句话说,在Windows 98或Windows 95下,应用程序不能像在实模式下可以随意操作硬件资源,而需要通过编写运行在内核模式(ring-0)的虚拟设备驱动程序(virtual device driver)才能达到目的。因此,在Windows 9x下如何高效编写硬件设备驱动程序是微机应用开发中迫切需要解决的问题。
1 Windows 9x系统结构
  确切的说Windows 9x不是一个操作系统,而是一个操作系统的集合。当计算机运行在保护模式下时,有“两个”操作系统同时存在,即Windows 本身和一个更低的操作系统,我们把它称为VMM/DPMI(virtual machine manager/Dos protect mode interface)。VMM的主要目的是管理同时运行的32位保护模式Windows应用程序(Win32 applications)以及运行在虚拟86模式下的MS-Dos程序,前者称为“线程”(threads),后者称为VM(virtual machine)。VMM使每一条线程拥有自己的独立地址空间,使每一个VM都“单独”占有CPU,并为它们提供各种服务。从图1中我们可以看出,threads和VMs所能访问到的资源已不是直接的物理资源,而是被VMM虚拟化(virtualized)后的虚拟资源了。


  另外,VMM是一个可扩充的“操作系统”,它的核心部件以及标准部件(比如,DMA控制器管理VDMAD,中断管理VPICD等)是由Microsoft提供的。但我们可以编写一些扩充模块,也就是用VxD来增强VMM对硬件的虚拟能力,使整个操作系统获得对新硬件的访问能力。不仅如此,这种扩充操作系统的办法,还能为Win32程序与MS-DOS程序之间的通讯提供一种新的途径以代替传统的MS-DOS设备驱动程序以及内存驻留程序TSRs。从某种意义上说,没有VxD不能完成的事情,而且由于VxD是运行的保护模式下,所以它并不占有宝贵的常规内存。此外,运行实模式MS-DOS驱动程序所导致的模式切换也不复存在。因此一般来讲,VxD的运行速度要高出MS-DOS驱动程序一倍以上。更重要的是VxD在Windows 9x下可以动态装入与卸载而不需要重新启动计算机,这就大大提高了系统的灵活性,同时也为即插即用(Plug and Play)提供了可能。与实模式的驱动程序相比,可动态装、卸载可谓是一场革命。
2 VxD的结构及通讯策略
  普通的Win32应用程序都是PE格式(Portable Exectable Format)的,而VxD则不同,它没有一般程序的进出口而是输出一种称作设备描述块DDB(Device Descriptor Block)的数据结构。它包括VxD设备ID、初始化顺序、Win32DeviceIOControl回调函数句柄、V86API句柄、PM API句柄等VMM在调用VxD时所需要的重要信息。此外,同其他应用程序一样,VxD由五个段构成,它们分别是:
  (1)VxD_CODE段:保护模式代码段。该段包含VxD系统控制过程、回调过程、服务和API过程。
  (2)VxD_DATA段:保护模式数据段。该段包括设备描述表、服务表和部分VxD全局数据。
  (3)VxD_ICODE段:保护模式初始化代码段(可选)。该段一般包括只在VxD初始化过程中使用的过程和服务,VMM在Init_Complete消息发生后丢弃此段。
  (4)VxD_IDATA段:保护模式初始化数据段(可选)。该段一般包括初始化过程和服务使用的数据,VMM在Init_Complete消息发生后丢弃此段。
  (5)VxD_REAL_INIT段:实模式初始化段(可选)。该段包含实模式初始化过程和数据,VMM在装载VxD其它部分之前调用此过程,过程返回后丢弃此段。
  当VxD装入内存时,VxD通常要靠DDB中所添入的一个16位的VxD设备ID,以区别于其它VxD。为了防止与其他新VxD冲突,Microsoft通过请求和注册标识来保证自己的VxD设备ID没有被其它厂商使用,为此Microsoft保留0~01FFH之间的所有VxD设备ID供自己使用。
  在编写VxD时首先要编写VMM的消息处理函数,以便作相应的处理。例如,在VxD装入内存时VMM对能动态装载的VxD发出SYS_DYNMAIC_DEVICE_INIT消息,在要求卸载VxD时VMM又向其发出SYS_DYNAMIC_DEVICE_EXIT消息。在VxD中只需编写相应的处理函数,便可达到设备初始化与卸载释放资源的目的。拿Win32程序来说,它使用CreateFile API函数打开可动态装、卸载的VxD时VMM便会发出SYS_DYNAMIC_DEVICE_INIT消息。相应的,当它使用CloseHandle API函数卸载VxD时VMM便会发生SYS_DYNAMIC_DEVICE_EXIT消息。
  另外,在具体调用VxD中的函数时,也不像调用ring-3 DLL中的函数那样容易。我们以调用对象不同分以下几种情况讨论:
  (1)从其他VxD中调用(ring-0调用ring-0)
  当生成VxD时,所有可以被其他VxD调用的函数都列在一个数组里,我们称这种函数为一个服务(Service)、这个数组为服务项目表(Service_Table)。在调用时,并不是用服务的名称而是直接使用该函数在数组中的索引号。例如对VMM中的1号服务Get_Cur_VM_Handle
  可采用如下格式:
  int 20h
  DD00010001h
  32位的DD由两部分组成,它的高字包含了VxD设备的ID,低字包含了服务号(这里VMM的设备ID为0001h)。
  (2)从V86代码或Win16(保护模式)代码中调用(ring-3调用ring-0)
  这里应用程序要申请被调用的VxD函数地址,这个地址可以通过int 2Fh/AX=1648h调用获得。为了识别是调用哪一个VxD的函数,调用时可令BX=VxD设备ID。当int 2Fh指令返回时,寄存器ES:DI(对保护模式有ES:EDI)包含一个seg:offset(对保护模式有selector:offset)指针,调用该指针就可以把控制权交给运行在ring-0下的VxD。
  (3)从Win32代码中调用(ring-3调用ring-0)
  事实上Microsoft隐藏了Win32的VxD服务接口,作为替代提供了Windows NT下的设备输入、输出控制(DeviceIOControl)Win32 API。Win32程序通过使用此函数向特定的VxD发送控制码与数据。与此相应在编写VxD时要提提供一个相应的回调函数以响应它所发出的W32_DeviceIOControl消息,并再去回调函数中响应相应的控制码,最后还要把该回调函数的句柄添加到DDB中。它的定义如下:
  BOOL DeviceloControl(
  HANDLE hDevice,//用CreateFile API函数打开VxD设备获得的句柄
  DWORD dwloControlCode,//ring3程序向VxD传递的命令码(可由编程写者自定)
  LPVOID lnBuffer,//ring3程序传给VxD的数据缓存的地址
  DWORD nlnBufferSize,//ring3程序传给VxD的数据缓存的字节数
  LPVOID lpOutBuffer,//VxD的返回数据所存放的缓存地址(该缓存由ring-3预留)
  DWORDnOutBufferSize,//VxD的返回数据所存放的缓存的字节数
  LPDWORD lpBytesReturned,//VxD实际返回数据的字节数
  LPOVERLAPPED lpOverlapped //一个OVERLAPPED的结构地址,通常为NULL);
  由此不难看出这种DeviceIOControl的结构也为VxD向ring-3回传数据提供了一种途径。这种通讯方式在NT的设备驱动程序中也得到了广泛应用,它是Microsoft大力提倡的Win32程序应采用的一种通讯方式。
3 VxD的实现
  从编程工具方面来看,我们需要Windows95 DDK和一个32bit的汇编编译器,如MASM6.11c,如果打算用C/C++开发驱动程序的话,还应选用一个32bit的C/C++4.0编译器,笔者推荐采用Micrfoft Visual C++ 4.0以上的版本,因为它支持一种新的关键字——declspec(naked) 。采用该关键字的函数,编译器将不为其生成相应的函数进出口代码,这样对于采用特殊函数结构的VxD函数来说是非常方便的。除此之外,也有一些公司提供了一些VxD向导器以帮助用户生成C/C++的程序框架,使用它们可以大大提高开发效率,应予以考虑,其中最著名的有Vtoolsd95, VxDwriter等。在编程中应注意,不要使用C/C++所提供的库函数,特别是Microsoft的MFC,因为它们都是运行在ring-3上的,如果非用不可的话,只有一些个别函数能通过使编译器生成嵌入式指令来达到目的,但这样做是要相当小心的。另外,调试运行在ring-0的驱动程序是相当困难的,VC++以及MASM中的调试均不能满足需要,而需采用内核级的调试工具比如Microsoft的WDEB386以及Numega的SoftIce等。
4 VxD的局限性
  VxD技术只适用于Windows 9x操作系统,Windows NT不支持此项技术,而是采用更为先进的面向对象的驱动程序模型,例如Window 98和Window 2000就采用了一种基于NT的驱动程序模型WDM。此外,由于VxD运行在ring-0上根本不受ring-3的制约,也给病毒的制造者即黑客以可乘之机,比如著名的CIH病毒是一个VxD。
参考文献
1 Microsoft Develop Network Library 98;6(5)
2 Writes,Ruediger R.Asche.What's New in Windows 95 for VxD Microsoft Developer Network Technology Group
3 Ruediger R.Ashe.The Little Device Driver,Microsoft Development Network Technology group
4 Win 9x虚拟设备驱动程序编程指南.清华大学出版社,1999.3

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。