分享
 
 
 

《Undocumented Windows 2000 Secrets》翻译 --- 第三章(1)

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

第三章 编写内核模式驱动程序

翻译:Kendiv

更新:Monday, February 07, 2005

在下一章中,我们会经常访问那些仅在内核模式下才有效的系统资源。大量的示例代码都被设计为内核驱动例程(Kernel-mode driver routine)。因此,需要有关开发此种软件的基本知识。因为我不能假定所有读者都有这方面的经验,我会在此简要地介绍一下内核模式驱动程序编程,不过这仅集中在如何使用驱动开发向导(在本书光盘上)。

本章还将讨论Windows 2000服务控制管理器(Service Control Manager,SCM)的基本知识,这包括SCM如何允许在运行时加载、控制和卸载驱动程序,resulting in wonderfully short change-build-test turnaround cycles。本章的题目或许会让人有些误解,驱动一词通常与控制硬件的底层软件相关。事实上,很多内核程序员每天都在做这些事情。不过,Windows 2000的驱动程序分层模式允许做比这更多的事情。内核驱动程序可以完成任意复杂的任务,若不考虑它们运行于更高的CPU特权级别上而且使用不同的开发接口,那它们很像用户模式下的DLL。在此,我们将使用这种强大的开发技术来侦测Windows 2000的内部秘密,使用内核驱动程序就像驾驶从狭小的用户模式飞往Windows 2000内核的太空飞船。

创建一个驱动程序的骨架

即使长时间开发Win32应用程序和库的开发人员,在首次编写内核驱动程序时,也会感觉像是一个绝对的初学者。这是因为,内核模式下的代码运行在一个完全不同的操作系统环境中。Win32开发人员的工作仅局限在属于Windows 2000 Win32子系统的几个系统组件上。其他开发人员可能编写POSI或OS/2应用程序,Windows 2000的附加子系统为它们提供支持。感谢子系统这个概念,Windows 2000就像一个变色龙---它可通过这些子系统(前面提及的)导出不同的应用程序开发接口来模拟不同的操作系统。与此相反,内核模式的代码可以看到“真实”的Windows 2000操作系统。它们使用的接口可以称之为“最终边界”。当然,这并不是说,内核模式完全摆脱了子系统。在第二章中,我们看到win32k.sys就是Win32 GUI和窗口管理器在内核模式下的分支,将它们放在内核是出于性能考虑。然而,win32k.sys导出的API函数集合中只有一小部分出现在了gdi32.dll和user32.dll中,这也意味着只有这一小部分函数可以作为Win32 API函数来使用,因此,Win32K决不只是Win32踏入内核世界的一脚,实际上,应把它看作是一个高性能的内核模式的图形引擎。

Windows 2000 DDK(Device Driver Kit)

由于内核模式下的编程使用了不同的系统接口,在Win32编程中经常使用的头文件和库都将无法在内核模式下使用。针对Win32开发,微软提供了Platform Software Development Kit(SDK)。而与内核模式的驱动开发相关的是,Windows 2000 Device Driver Kit(DDK)。随文档一起,DDK还提供了特殊的头文件和导入库,这些都是Windows 2000内核模块必须的接口。安装完DDK之后,接下来你应该打开Visual C/C++,把DDK的路径加入到编译器和链接器的目录列表中。在主菜单中选择ToolsàOptions,然后单击Directories。在目录选择下拉列表中选择Include files,然后将DDK的适当路径加入,如图3-1所示。默认情况下,DDK将安装到\NTDDK目录下,included文件位于\NTDDK\inc子目录中。需要注意的是,请将新添加的路径置于原有路径的上方,这样就会使用新的头文件或者库。

图3-1 添加DDK头文件路径

图3-2 添加DDK导入库路径

在添加完DDK头文件路径后,用同样的方法添加导入库的路径。DDK包含两组导入库,一组叫做free(release)builds,另一组叫做checked(debug)builds。其对应的目录为:\NTDDK\libfre\i386和\NTDDK\libchk\i386,参见图3-2。

DDK开发环境与Win32模式有所不同,下面给出二者之间的一些明显区别:

l 对于Win32程序员来说,主要的头文件是windows.h,对于内核模式代码来说,应使用ntddk.h替代之。

l 主进入点函数叫做DirverEntry(),而不再是WinMain()或main()。列表3-1给出了它们的原型。

l 不能再使用一些常见的Win32数据类型,如BYTE、WORD和DWORD。DDK使用UCHAR、USHORT、ULONG等。不过,很容易就能定义你自己喜欢的类型,列表3-2给出了这样的一个示例。

NTSTATUS DriverEntry ( PDRIVER_OBJECT pDriverObject,

PUNICODE_STRING pusRegistryPath);

列表3-1 DriverEntry函数的原型

typedef UCHAR BYTE, *PBYTE;

typedef USHORT WORD, *PWORD;

typedef ULONG DWORD, *PDWORD;

列表3-2 定义常见的Win32数据类型

此外,还需要注意Windows NT 4.0和Windows 2000所使用的DDK之间的差别,有三点不同需要注意,如下:

l 默认情况下,Windows NT 4.0 DDK的主目录叫做\DDK,而Windows 2000 DDK叫做\NTDDK

l 在Windows NT 4.0 DDK中,主要的头文件ntddk.h位于主目录之下。而在Windows 2000 DDK中,该文件被移到了\NTDDK\DDK子目录下。

l 导入库的路径也发生了变化:lib\i386\free变成了libfre\i386,lib\i386\checked变成了libchk\i386。

我不知道微软的这种改变有什么实际意义,不过为了生活,我们还是需要了解其变化J。

可定制的驱动程序向导

开发内核驱动程序的主要困难在于Visual C/C++没有提供此种类型的工程向导。幸运的是,MSDN里有一系列不错的关于Windows NT内核驱动开发的文章,是Ruediger R.Asche.在1994至1995年编写的。其中的两篇文章(Asche 1995a,1995b)详细说明了如何在Visual C/C++中加入自定义的驱动程序向导,这些文章给了我很大的帮助,尽管原始向导的输出文件不能满足我的所有需求,但这是一个很好的开始。我提供的内核驱动向导将基于Ruediger Asche的原始向导产生的输出文件。

我提供的驱动向导的所有源代码位于本书光盘的\src\w2k_wiz目录。通过阅读这些代码,你会发现它实际的标题“SBS Windows 2000 Code Wizard”。事实上,这是一个一般性的Windows 2000程序骨架生成器,该生成器可以产生多种类型的程序,包括Win32 DLL和应用程序。不过,光盘中的配置文件针对内核驱动开发做了一定的修改。基本上来说,我提供的向导是一个文件转换器,它读取一组文件,然后按照一些简单的规则将它们进行转换,最后将结果写入另一组文件中。输入文件是模板,输出文件是C工程文件。通过修改模板文件,该向导可以变成一个DLL向导等等。必须提供7个模板文件(如果丢失了某一个,会产生错误):

l 扩展名为.tw的文件是workspace模板,此种文件将会被保存为Visual Studio的工程文件.dsw。

l 扩展名为.tp的文件是工程模板,此种文件将被保存为.dsp文件。工程文件由于之关联的workspace文件引用,工程文件还包含生成工程的所有配置选项。

l 扩展名为.tc、.th、.tr和.td的文件都是C代码文件,这些文件最后会变成相应的.c、.h、.rc和.def文件。

l 扩展名为.ti的是icon文件,该文件会被直接保存为.ico文件。

这七个文件是一个新工程所必需的。.def文件以一种较老风格的方法从DLL中导出API函数,不过我更喜欢__declspec(dllexport)方式。因为驱动程序通常不导出函数,所以我省略了.td模板,导致的结果是,在开始时,向导会报告一个错误。我还省略了资源脚本和icon文件,不过经验告诉我,最好提供它们。采用的转换规则也非常简单,仅包含一个很短的字符串替换列表。在扫描模板文件时,转换器查找以%号开始的转义符。当它找到后,会根据%后的字符来决定执行什么样的动作。表3-1列出了验证过的转义符。

表3-1中有几处需参考配置文件---w2k_wiz.ini。示例3-1给出了其默认设置。在使用向导之前,你应该将光盘\src\w2k_wiz\release目录下的w2k_wiz.exe、w2k_wiz.ini和所有的w2k_wiz.t*模板文件复制到你的硬盘上,然后编辑配置文件,将对应内容改为你自己的设置。你还需要修改Include、Free和Checked,使其和你的DDK安装相匹配。如果你使用Visual C/C++ 6.0,可以不改变Root的值。如果不,则将其设为你存放工程文件的根目录。如果以一个反斜线结尾,它将作为默认值。在示例3-1中,其键值为:HKEY_CURRENT_USER\SoftWare\Microsofto\DevStudio\6.0\Directories,而WorkspaceDir用来存放基本的工作目录。

键入w2k_wiz MyDriver来执行该向导,它会当前目录下创建名为MyDriver的工程目录,该目录将存放向导生成的MyDriver.dsw、MyDriver.dsp、MyDriver.c、MyDriver.h、MyDriver.rc和MyDriver.ico文件。如果你指定了具体的路径,则会在你指定的路径下创建该目录。另一个合法的命令选项是星号,如:w2k_wiz *MyDriver。在此种情况下,向导不会在当前目录下创建工程目录,而是去查找Visual C/C++维护的默认的工程根目录,即w2k_wiz.ini中的Root所指向的位置。

; w2k_wiz.ini

; 08-27-2000 Sven B. Schreiber

; sbs@orgon.com

[Settings]

Text = <SBS Windows 2000 Code Wizard Project>

Company = <MyCompany>

Author = <MyName>

Email = <my@email>

Prefix = <MyPrefix>

Include = E:\NTDDK\inc

Free = E:\NTDDK\libfre\i386

Checked = E:\NTDDK\libchk\i386

Root = HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Directories\WorkspaceDir

示例3-1. 向导支持的自定义选项

运行驱动向导

现在,来试试这个驱动向导。示例3-2给出了在Windows 2000控制台下执行w2k_wiz *TestDrv后的输出。这将在Visual C/C++默认的工程根目录下创建一个名为TestDrv的工程目录。

显然,除了将.td模板转换为.def时出了错,其余转换都成功的完成了。因为该向导生成的驱动程序骨架不需要.def文件,所以不需要提供.td模板文件。现在,用Visual C/C++打开一个新的WorkSpace,然后你会发现一个名为TestDrv的新目录,该目录中包含一个名为TestDrv.dsw的WorkSpace文件。该文件可以被正确的打开。接下来,你因该为生成项目选择活动的配置信息。驱动向导生成的.dsp文件提供了如下两个可用配置:

1. Win2k Kernel-mode Driver(debug)

2. Win2k Kernel-mode Driver(release)

默认情况下,将使用debug配置来生成项目,但是你可在任何时候从Visual C/C++菜单Build/Set Active Configuration来选择不同的项目配置。最后,你要将光盘中的\src\common\include\DrvInfo.h复制到你自己的头文件目录中。在打开TestDrv.rc时,应使用文本模式来打开(如图3-3所示),这是因为该文件使用了来自DrvInfo.h中的复杂的宏定义,这些宏会导致资源编辑器异常退出。这个错误从Visual C/C++ 5.0开始,在我印象中,一直没有被改正过。和编辑器不同,资源编译器(Resource Compiler)可以正常的处理这些宏。

图3-3. 以文本模式打开TestDrv.c、TestDrv.h和TestDrv.rc

现在,已经为第一次编译做好了所有准备。在示例3-3中,我通过选择Build/Rebuild菜单来建立Driver的Release版,看起来一切都正常。顺便说一下,头两行末尾的省略号表示我截断了Build命令的输出。

链接器会在Debug或Release目录下创建了一个名为TestDrv.sys的可执行文件,这依赖于你的生成配置。Test Driver的Release版大小为5.5KB,其Debug版为8KB。你可以使用本书光盘中的MFVDasm或PEView来验证TestDrv.sys是否包含有效的代码和数据。

深入驱动程序的骨架

列表3-3展示了向导生成的TestDrv.c。与之相关的头文件TestDrv.h在列表3-4中。在列表3-3中,请注意标题处的<MyName>和<MyCompany>标志。如果w2k_wiz.ini中的作者和公司名称正确,那你自己的名字和相应的公司名称将会替代它们。

// TestDrv.c

// 08-07-2000 <MyName>

// Copyright @2005 <MyCompany>

#define _TESTDRV_SYS_

#include <ntddk.h>

#include "TestDrv.h"

// =================================================================

// DISCLAIMER

// =================================================================

/*

This software is provided "as is" and any express or implied

warranties, including, but not limited to, the implied warranties of

merchantability and fitness for a particular purpose are disclaimed.

In no event shall the author <MyName> be liable for any

direct, indirect, incidental, special, exemplary, or consequential

damages (including, but not limited to, procurement of substitute

goods or services; loss of use, data, or profits; or business

interruption) however caused and on any theory of liability,

whether in contract, strict liability, or tort (including negligence

or otherwise) arising in any way out of the use of this software,

even if advised of the possibility of such damage.

*/

// =================================================================

// REVISION HISTORY

// =================================================================

/*

08-07-2000 V1.00 Original version.

*/

// =================================================================

// GLOBAL DATA

// =================================================================

PRESET_UNICODE_STRING (usDeviceName, CSTRING (DRV_DEVICE));

PRESET_UNICODE_STRING (usSymbolicLinkName, CSTRING (DRV_LINK ));

PDEVICE_OBJECT gpDeviceObject = NULL;

PDEVICE_CONTEXT gpDeviceContext = NULL;

// =================================================================

// DISCARDABLE FUNCTIONS

// =================================================================

NTSTATUS DriverInitialize (PDRIVER_OBJECT pDriverObject,

PUNICODE_STRING pusRegistryPath);

NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject,

PUNICODE_STRING pusRegistryPath);

// -----------------------------------------------------------------

#ifdef ALLOC_PRAGMA

#pragma alloc_text (INIT, DriverInitialize)

#pragma alloc_text (INIT, DriverEntry)

#endif

// =================================================================

// DEVICE REQUEST HANDLER

// =================================================================

NTSTATUS DeviceDispatcher (PDEVICE_CONTEXT pDeviceContext,

PIRP pIrp)

{

PIO_STACK_LOCATION pisl;

DWORD dInfo = 0;

NTSTATUS ns = STATUS_NOT_IMPLEMENTED;

pisl = IoGetCurrentIrpStackLocation (pIrp);

switch (pisl->MajorFunction)

{

case IRP_MJ_CREATE:

case IRP_MJ_CLEANUP:

case IRP_MJ_CLOSE:

{

ns = STATUS_SUCCESS;

break;

}

}

pIrp->IoStatus.Status = ns;

pIrp->IoStatus.Information = dInfo;

IoCompleteRequest (pIrp, IO_NO_INCREMENT);

return ns;

}

// =================================================================

// DRIVER REQUEST HANDLER

// =================================================================

NTSTATUS DriverDispatcher (PDEVICE_OBJECT pDeviceObject,

PIRP pIrp)

{

return (pDeviceObject == gpDeviceObject

? DeviceDispatcher (gpDeviceContext, pIrp)

: STATUS_INVALID_PARAMETER_1);

}

// -----------------------------------------------------------------

void DriverUnload (PDRIVER_OBJECT pDriverObject)

{

IoDeleteSymbolicLink (&usSymbolicLinkName);

IoDeleteDevice (gpDeviceObject);

return;

}

// =================================================================

// DRIVER INITIALIZATION

// =================================================================

NTSTATUS DriverInitialize (PDRIVER_OBJECT pDriverObject,

PUNICODE_STRING pusRegistryPath)

{

PDEVICE_OBJECT pDeviceObject = NULL;

NTSTATUS ns = STATUS_DEVICE_CONFIGURATION_ERROR;

if ((ns = IoCreateDevice (pDriverObject, DEVICE_CONTEXT_,

&usDeviceName, FILE_DEVICE_CUSTOM,

0, FALSE, &pDeviceObject))

== STATUS_SUCCESS)

{

if ((ns = IoCreateSymbolicLink (&usSymbolicLinkName,

&usDeviceName))

== STATUS_SUCCESS)

{

gpDeviceObject = pDeviceObject;

gpDeviceContext = pDeviceObject->DeviceExtension;

gpDeviceContext->pDriverObject = pDriverObject;

gpDeviceContext->pDeviceObject = pDeviceObject;

}

else

{

IoDeleteDevice (pDeviceObject);

}

}

return ns;

}

// -----------------------------------------------------------------

NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject,

PUNICODE_STRING pusRegistryPath)

{

PDRIVER_DISPATCH *ppdd;

NTSTATUS ns = STATUS_DEVICE_CONFIGURATION_ERROR;

if ((ns = DriverInitialize (pDriverObject, pusRegistryPath))

== STATUS_SUCCESS)

{

ppdd = pDriverObject->MajorFunction;

ppdd [IRP_MJ_CREATE ] =

ppdd [IRP_MJ_CREATE_NAMED_PIPE ] =

ppdd [IRP_MJ_CLOSE ] =

ppdd [IRP_MJ_READ ] =

ppdd [IRP_MJ_WRITE ] =

ppdd [IRP_MJ_QUERY_INFORMATION ] =

ppdd [IRP_MJ_SET_INFORMATION ] =

ppdd [IRP_MJ_QUERY_EA ] =

ppdd [IRP_MJ_SET_EA ] =

ppdd [IRP_MJ_FLUSH_BUFFERS ] =

ppdd [IRP_MJ_QUERY_VOLUME_INFORMATION] =

ppdd [IRP_MJ_SET_VOLUME_INFORMATION ] =

ppdd [IRP_MJ_DIRECTORY_CONTROL ] =

ppdd [IRP_MJ_FILE_SYSTEM_CONTROL ] =

ppdd [IRP_MJ_DEVICE_CONTROL ] =

ppdd [IRP_MJ_INTERNAL_DEVICE_CONTROL ] =

ppdd [IRP_MJ_SHUTDOWN ] =

ppdd [IRP_MJ_LOCK_CONTROL ] =

ppdd [IRP_MJ_CLEANUP ] =

ppdd [IRP_MJ_CREATE_MAILSLOT ] =

ppdd [IRP_MJ_QUERY_SECURITY ] =

ppdd [IRP_MJ_SET_SECURITY ] =

ppdd [IRP_MJ_POWER ] =

ppdd [IRP_MJ_SYSTEM_CONTROL ] =

ppdd [IRP_MJ_DEVICE_CHANGE ] =

ppdd [IRP_MJ_QUERY_QUOTA ] =

ppdd [IRP_MJ_SET_QUOTA ] =

ppdd [IRP_MJ_PNP ] = DriverDispatcher;

pDriverObject->DriverUnload = DriverUnload;

}

return ns;

}

// =================================================================

// END OF PROGRAM

// =================================================================

列表3-3. 驱动程序骨架的源代码

// TestDrv.h

// 08-07-2000 <MyName>

// Copyright @2005 <MyCompany>

// =================================================================

// PROGRAM IDENTIFICATION

// =================================================================

#define DRV_BUILD 1

#define DRV_VERSION_HIGH 1

#define DRV_VERSION_LOW 0

// -----------------------------------------------------------------

#define DRV_DAY 07

#define DRV_MONTH 02

#define DRV_YEAR 2005

// -----------------------------------------------------------------

// Customize these settings by editing the configuration file

// D:\etc32\w2k_wiz.ini

#define DRV_MODULE TestDrv

#define DRV_NAME <SBS Windows 2000 Code Wizard Project>

#define DRV_COMPANY <MyCompany>

#define DRV_AUTHOR <MyName>

#define DRV_EMAIL <my@email>

#define DRV_PREFIX <MyPrefix>

// =================================================================

// HEADER FILES

// =================================================================

#include "drvinfo.h" // defines more DRV_* items

////////////////////////////////////////////////////////////////////

#ifndef _RC_PASS_

////////////////////////////////////////////////////////////////////

// =================================================================

// CONSTANTS

// =================================================================

#define FILE_DEVICE_CUSTOM 0x8000

// =================================================================

// STRUCTURES

// =================================================================

typedef struct _DEVICE_CONTEXT

{

PDRIVER_OBJECT pDriverObject;

PDEVICE_OBJECT pDeviceObject;

}

DEVICE_CONTEXT, *PDEVICE_CONTEXT, **PPDEVICE_CONTEXT;

#define DEVICE_CONTEXT_ sizeof (DEVICE_CONTEXT)

////////////////////////////////////////////////////////////////////

#endif // #ifndef _RC_PASS_

////////////////////////////////////////////////////////////////////

// =================================================================

// END OF FILE

// =================================================================

列表3-4. 驱动程序骨架的头文件

........................待续.........................

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有