当前位置:文档之家› (转载)Windows文件系统过滤驱动开发教程

(转载)Windows文件系统过滤驱动开发教程

(转载)Windows文件系统过滤驱动开发教程
(转载)Windows文件系统过滤驱动开发教程

作者,楚狂人自述

我长期网上为各位项目经理充当“技术实现者”的角色。我感觉Windows文件系统驱动的开发能找到的资料比较少。为了让技术经验不至于遗忘和引起大家交流的兴趣我以我的工作经验撰写本教程。

我的理解未必正确,有错误的地方望多多指教。有问题欢迎与我联系。我们也乐于接受各种驱动项目的开发。邮箱为MFC_Tan_Wen@https://www.doczj.com/doc/1c13597342.html,,QQ为16191935。

对于这本教程,您可以免费获得并随意修改,向任何网站转贴。但是不得剽窃任何内容作为任何赢利出版物的全部或者部分。

1. 概述,钻研目的和准备

我经常在网上碰到同行请求开发文件系统驱动。windows的pc机上以过滤驱动居多。其目的不外乎有以下几种:

一是用于防病毒引擎。希望在系统读写文件的时候,捕获读写的数据内容,然后检测其中是否含有病毒代码。

二是用于加密文件系统,希望在文件写过程中对数据进行加密,在读的过程中进行解密。

三是设计透明的文件系统加速。读写磁盘的时候,合适的cache算法是可以大大提高磁盘的工作效率。windows本身的cache算法未必适合一些特殊的读写

磁盘操作(如流媒体服务器上读流媒体文件)。设计自己的cache算法的效果,我已在工作中有所感受。

如果你刚好有以上此类的要求,你可以阅读本教程。

文件系统驱动是windows系统中最复杂的驱动种类之一。不能对ifsddk中的帮助抱太多希望,以我的经验看来,文件系统相关的ddk帮助极其简略,很多重要的部分仅仅轻描淡写的带过。如果安装了ifsddk,应该阅读srcfilesysOSR_docs下的文档。而不仅仅是ddk帮助。

文件系统驱动开发方面的书籍很少。中文资料我仅仅见过侯捷翻译过的一本驱动开发的书上有两三章涉及,也仅仅是只能用于9x的vxd驱动。NT文件系统我见过一本英文书。我都不记得这两本书的书名了。

如果您打算开发9x或者nt文件系统驱动,建议你去网上下载上文提及的书。那两本书都有免费的电子版本下载。如果你打算开发Windows2000WindowsXPWindow2003的文件系统驱动,你可以阅读本教程。虽然本教程仅仅讲述文件系统过滤驱动。但是如果您要开发一个全新的文件系统驱动的话,本教程依然对你有很大的帮助。

学习文件系统驱动开发之前,应该在机器上安装ifsddk。ddk版本越高级,其中头文件中提供的系统调用也越多。经常有人询问如xpddk编译的驱动能不能在2000上运行等等的问题。我想可以这样解释:高级版本的ddk应该总是可以编译低级驱动的代码,而且得到的二进制版本也总是可以在低级系统上运行。但是反过来就未必可以了。如果在高级系统上编写用于低级系统上的驱动,要非常认真的注意仅仅调用低级系统上有的系统调用。

ifsddk可以在某些ftp上免费下载。

我的使用的是ifs ddk for xp,但是我实际用来开发的两台机器有一台是windows 2000,另一台是windows 2003.我尽量使我编译出来的驱动,可以在2000xp2003三种系统上都通过测试。

安装配置ddk和在vc中开发驱动的方法网上有很多的介绍。ifsddk安装之后,src目录下的filesys目录下有文件系统驱动的示例。阅读这些代码你就可以快速的学会文件系统驱动开发。

filter目录下的sfilter是一个文件系统过滤驱动的例子。另一个filespy完全是用这个例子的代码加工得更复杂而已。

如何用ddk编译这个例子请自己查看相关的资料。

文件系统过滤驱动编译出来后你得到的是一个扩展名为sys的文件。同时你需要写一个.inf 文件来实现这个驱动的安装。我这里不讨论.inf文件的细节,你可以直接用sfilter目录下的inf文件修改。

对inf文件点鼠标右键弹出菜单选择“安装”,即可安装这个过滤驱动。但是必须重新启动系统才生效。

如果重启后蓝屏无法启动,可以用其他方式引导系统后到system32drivers目录下删除你的.sys文件再重启即可。我尝试这种情况下用安全模式结果还是蓝屏。所以我后来不得不在机器上装了两个2000系统。双系统情况下,一个系统崩溃了用另一个系统启动,删除原来的驱动即可。

如果要调试代码,请安装softice.

打开sfilter目录下的文件sources(这个文件没有扩展名),加入一行

BROWSER_INFO=1

然后打开Symbol Loader,File->Open选中你编译出来的xxx.sys,Modul->Load,Modul->Translate,然后就可以调试了。

打开softice,输入file *就可以看见代码。

如果准备好了,我们就可以开始琢磨windows文件系统过滤驱动的开发了。

1. hello world,驱动对象与设备对象

这里所说的驱动对象是一种数据结构,在DDK中名为DRIVER_OBJECT。任何驱动程序都对应一个DRIVER_OBJECT.如何获得本人所写的驱动对应的DRIVER_OBJECT呢?驱动程序的入口函数为DriverEntry,因此,当你写一个驱动的开始,你会写下如下的代码:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )

{

}

这个函数就相当与喜欢c语言的你所常用的main().IN是无意义的宏,仅仅表明后边的参数是一种输入,而对应的OUT则代表这个参数是一种返回。这里没有使用引用,因此如果想在参数中返回结果,一律传入指针。

DriverObject就是你所写的驱动对应的DRIVER_OBJECT,是系统在加载你的驱动时候所分配的。RegisteryPath是专用于你记录你的驱动相关参数的注册表路径。

DriverObject重要之处,在于它拥有一组函数指针,称为dispatch functions.

开发驱动的主要任务就是亲手撰写这些dispatch functions.当系统用到你的驱动,会向你的DO发送IRP(这是windows所有驱动的共同工作方式)。你的任务是在dispatch function中处理这些请求。你可以让irp失败,也可以成功返回,也可以修改这些irp,甚至可以自己发出irp。

设备对象则是指DEVICE_OBJECT.下边简称DO.

但是实际上每个irp都是针对DO发出的。只有针对由该驱动所生成的DO的IRP,

才会发给该驱动来处理。

当一个应用程序打开文件并读写文件的时候,windows系统将这些请求变成irp发送给文件系统驱动。

文件系统过滤驱动将可以过滤这些irp.这样,你就拥有了捕获和改变文件系统操作的能力。

象Fat32,NTFS这样的文件系统(File System,简称FS),可能生成好几种设备。首先文件系统驱动本身往往生成一个控制设备(CDO).这个设备的主要任务是修改整个驱动的内部配置。因此一个Driver只对应一个CDO.

另一种设备是被这个文件系统Mount的V olume。一个FS可能有多个Volume,也可能一个都没有。解释一下,如果你有C:,D:,E:,F:四个分区。C:,D:为NTFS,E:,F:为Fat32.那么C:,D:则是Fat的两个Volume设备对象.

实际上"C:"是该设备的符号连接(Symbolic Link)名。而不是真正的设备名。可以打开Symbolic Links Viewer,能看到:

C: DeviceHarddiskV olume1

因此该设备的设备名为“DeviceHarddiskV olume1”.

这里也看出来,文件系统驱动是针对每个Volume来生成一个DeviceObject,而不是针对每个文件的。实际上对文件的读写的irp,都发到V olume设备对象上去了。并不会生成一个“文件设备对象”。

掌握了这些概念的话,我们现在用简单的代码来生成我们的CDO,作为我们开发文件系统驱动的第一步牛刀小试。

我不喜欢用微软风格的代码。太长而且难看。我对大部分数据结构和函数进行了重定义。为此我写了一个名为wdf.h的头文件帮助我转换。有兴趣的读者可以发邮件向索取这个文件。没有也没有关系,我总是会写出wd_xxx系列的东西在DDK中的原形。

// -----------------wdf_filter.c中的内容-------------------------

#include "wdf.h"

wd_stat wdff_cdo_create(in wd_drv *driver,

in wd_size exten_len,

in wd_ustr *name,

out wd_dev **device)

{

return wd_dev_create(

driver,

exten_len,

name,

wd_dev_disk_fs,

wdf_dev_secure_open,

wd_false,

device);

}

wd_stat wd_main(in wd_drv* driver,

in wd_ustr* reg_path)

{

wd_ustr name;

wd_stat status = wd_stat_suc;

// 然后我生成控制设备,虽然现在我的控制设备什么都不干

wd_ustr_init(&name,L"\FileSystem\Filters\our_fs_filter");

status = wdff_cdo_create(driver,0,&name,&g_cdo);

if(!wd_suc(status))

{

if(status == wd_stat_path_not_found)

{

// 这种情况发生于FileSystemFilters路径不存在。这个路径是

// 在xp上才加上的。所以2000下会运行到这里

wd_ustr_init(&name,L"\FileSystem\our_fs_filter");

status = wdff_cdo_create(driver,0,&name,&g_cdo);

};

if(!wd_suc(status))

{

wd_printf0("error: create cdo failed.rn");

return status;

}

}

wd_printf0("success: create cdo ok.rn");

return status;

}

为了让代码看起来象上边的那样,我不得不做了很多转换。如

#define DriverEntry wd_main

一种爽的感觉,终于可以在写看起来更象是main()的函数中工作了。wd_dev_create 这个函数内部调用的是IoCreateDevice.而wd_suc实际上是SUCCESS()这样的宏。

// ----------------------wdf.h中的内容------------------------------

#include "ntifs.h"

#define in IN

#define out OUT

#define optional OPTIONAL

#define wd_ustr UNICODE_STRING

#define wdp_ustr PUNICODE_STRING

#define wd_main DriverEntry

// 设备、驱动对象类型

typedef DRIVER_OBJECT wd_drv;

typedef DEVICE_OBJECT wd_dev;

typedef DRIVER_OBJECT wd_pdrv;

typedef PDEVICE_OBJECT wd_pdev;

enum {

wd_dev_disk_fs = FILE_DEVICE_DISK_FILE_SYSTEM,

wd_dev_cdrom_fs = FILE_DEVICE_CD_ROM_FILE_SYSTEM,

wd_dev_network_fs = FILE_DEVICE_NETWORK_FILE_SYSTEM

};

// 状态相关的类型和宏

typedef NTSTATUS wd_stat;

enum {

wd_stat_suc = STATUS_SUCCESS,

wd_stat_path_not_found = STA TUS_OBJECT_PA TH_NOT_FOUND,

wd_stat_insufficient_res = STA TUS_INSUFFICIENT_RESOURCES,

wd_stat_invalid_dev_req = STA TUS_INV ALID_DEVICE_REQUEST,

wd_stat_no_such_dev = STA TUS_NO_SUCH_DEVICE,

wd_stat_image_already_loaded = STATUS_IMAGE_ALREADY_LOADED, wd_stat_more_processing = STA TUS_MORE_PROCESSING_REQUIRED, wd_stat_pending = STA TUS_PENDING

};

_inline wd_bool wd_suc(wd_stat state)

{

return NT_SUCCESS(state);

}

#define wd_printf0 DbgPrint

_inline wd_void wd_ustr_init(in out wd_ustr* str,

in const wd_wchar* chars)

{

RtlInitUnicodeString(str,chars);

};

_inline wd_void wd_ustr_init_em(

in out wd_ustr*str,

in wd_wchar *chars,

in wd_size size)

{

RtlInitEmptyUnicodeString(str,chars,size);

};

wdf.h这个文件我仅仅节选了需要的部分。以上您已经拥有了一个简单的“驱动”的完整的代码。它甚至可以编译,安装(请修改sfilter.inf文件,其方法不过是将多处sfilter改为"our_fs_filter",希望这个过程中您不会出现问题)。然后把wdf.h和wdf_filter.c放在您新建立的目录下,这个目录下还应该有另两个文件。一个是Makefile,请从sfilter目录下拷贝。另一个是SOURCES,请输入如下内容:

TARGETNAME=our_fs_filter

TARGETPATH=obj

TARGETTYPE=DRIVER

DRIVERTYPE=FS

BROWSER_INFO=1

SOURCES=wdf_filter.c

使用ddk编译之后您将得到our_fs_filter.sys.把这个文件与前所描述的inf文件同一目录,按上节所叙述方法安装。

这个驱动不起任何作用,但是你已经成功的完成了"hello world".

2. 分发例程,fast io

上一节仅仅生成了控制设备对象。但是不要忘记,驱动开发的主要工作是撰写分发例程(dispatch functions.).接上一接,我们已经知道自己的DriverObject保存在上文代码的driver 中。现在我写如下一个函数来指定一个默认的dispatch function给它。

//-----------------wdf.h中的代码----------------------

typedef PDRIVER_DISPA TCH wd_disp_fuc;

_inline wd_void wd_drv_set_dispatch(in wd_drv* driver,

in wd_disp_fuc disp)

{

wd_size i;

for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)

driver->MajorFunction = disp;

}

在前边的wd_main中,我只要加

wd_drv_set_dispatch(driver,my_dispatch_func);

就为这个驱动指定了一个默认的Dispatch Function.所有的irp请求,都会被发送到这个函数。但是,我可能不希望这个函数处理过于复杂,而希望把一些常见的请求独立出来,如Read,Write,Create,Close,那我又写了几个函数专门用来设置这几个Dispatch Functions.

//-----------------wdf.h中的代码----------------------

_inline wd_void wd_drv_set_read(

in wd_drv* driver,

in wd_disp_fuc read)

{

driver->MajorFunction[IRP_MJ_READ] = read;

}

_inline wd_void wd_drv_set_write(

in wd_drv* driver,

in wd_disp_fuc write)

{

driver->MajorFunction[IRP_MJ_WRITE] = write;

}

wd_void wd_drv_set_create(in wd_drv* driver,

in wd_disp_fuc create)

{

driver->MajorFunction[IRP_MJ_CREATE] = create;

driver->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = create;

driver->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = create;

}

wd_void wd_drv_set_file_sys_control(in wd_drv* driver,

in wd_disp_fuc control)

{

driver->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = control;

}

wd_void wd_drv_set_clean_up(in wd_drv* driver,

in wd_disp_fuc clean_up)

{

driver->MajorFunction[IRP_MJ_CLEANUP] = clean_up;

}

wd_void wd_drv_set_close(in wd_drv* driver,

in wd_disp_fuc close)

{

driver->MajorFunction[IRP_MJ_CLOSE] = close;

}

别看我罗列n多代码,其实就是在设置driver->MajorFunction这个数组而已。因此在wd_main 对dispatch functions的设置,就变成了下边这样的:

// 开始设置几个分发例程

wd_drv_set_dispatch(driver,my_disp_default);

wd_drv_set_create(driver,my_disp_create);

wd_drv_set_clean_up(driver,my_disp_clean_up);

wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl);

wd_drv_set_close(driver,my_disp_close);

wd_drv_set_read(driver,my_disp_read);

wd_drv_set_write(driver,my_disp_write);

下面的任务都在写my_xxx系列的这些函数了。但是对于这个DriverObject的设置,还并不是仅仅这么简单。

由于你的驱动将要绑定到文件系统驱动的上边,文件系统除了处理正常的IRP之外,还要处理所谓的FastIo.FastIo是Cache Manager调用所引发的一种没有irp的请求。换句话说,除了正常的Dispatch Functions之外,你还得为DriverObject撰写另一组Fast Io Functions.这组函数的指针在driver->FastIoDispatch.我不知道这个指针留空会不会导致系统崩溃。在这里本来是没有空间的,所以为了保存这一组指针,你必须自己分配空间。

下面是我常用的内存分配函数。

//-----------------wdf.h中的代码----------------------

// 最简单的分配内存的函数,可以指定分页非分页

_inline wd_pvoid wd_malloc(wd_bool paged,wd_size size)

{

if(paged)

return ExAllocatePool(PagedPool,size);

else

return ExAllocatePool(NonPagedPool,size);

}

// 释放内存

_inline wd_void wd_free(wd_pvoid point)

{

ExFreePool(point);

}

_inline wd_void wd_memzero(

wd_pvoid point,

wd_size size)

{

RtlZeroMemory(point,size);

}

有了上边的基础,我就可以自己写一个初始化FastIoDispatch指针的函数。

//-----------------wdf.h中的代码----------------------

wd_bool wd_fio_disp_init(wd_drv *driver,wd_ulong size)

{

wd_fio_disp *disp = wd_malloc(wd_false,size);

if(disp == wd_null)

return wd_false;

wd_memzero((wd_pvoid)disp,size);

driver->FastIoDispatch = disp;

driver->FastIoDispatch->SizeOfFastIoDispatch = size;

return wd_true;

}

这个函数为FastIoDispacth指针分配足够的空间并填写它的大小。下面是再写一系列的函数来设置这个函数指针数组。实际上,FastIo接口函数实在太多了,所以我仅仅写出这些设置函数的几个作为例子:

//-----------------wdf.h中的代码----------------------

_inline wd_void wd_fio_disp_set_query_standard(

wd_drv *driver,

wd_fio_query_standard_func func)

{

driver->FastIoDispatch->FastIoQueryStandardInfo = func;

}

_inline wd_void wd_fio_disp_set_io_lock(

wd_drv *driver,

wd_fio_io_lock_func func)

{

driver->FastIoDispatch->FastIoLock = func;

}

_inline wd_void wd_fio_disp_set_io_unlock_s(

wd_drv *driver,

wd_fio_unlock_single_func func)

{

driver->FastIoDispatch->FastIoUnlockSingle = func;

}

...

好,如果你坚持读到了这里,应该表示祝贺了。我们回顾一下,wd_main中,应该做哪些工作。

a.生成一个控制设备。当然此前你必须给控制设置指定名称。

b.设置Dispatch Functions.

c.设置Fast Io Functions.

// ----------------wd_main 的近况----------------------------

...

wd_dev *g_cdo = NULL;

wd_stat wd_main(in wd_drv* driver,

in wd_ustr* reg_path)

{

wd_ustr name;

wd_stat status = wd_stat_suc;

// 然后我生成控制设备,虽然现在我的控制设备什么都不干wd_ustr_init(&name,L"\FileSystem\Filters\our_fs_filters"); status = wdff_cdo_create(driver,0,&name,&g_cdo);

if(!wd_suc(status))

{

if(status == wd_stat_path_not_found)

{

// 这种情况发生于FileSystemFilters路径不存在。这个路径是// 在xp上才加上的。所以2000下可能会运行到这里

wd_ustr_init(&name,L"\FileSystem\our_fs_filters");

status = wdff_cdo_create(driver,0,&name,&g_cdo);

};

if(!wd_suc(status))

{

wd_printf0("error: create cdo failed.rn");

return status;

}

}

wd_printf0("success: create cdo ok.rn");

// 开始设置几个分发例程

wd_drv_set_dispatch(driver,my_disp_default);

wd_drv_set_create(driver,my_disp_create);

wd_drv_set_clean_up(driver,my_disp_clean_up);

wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl);

wd_drv_set_close(driver,my_disp_close);

wd_drv_set_read(driver,my_disp_read);

wd_drv_set_write(driver,my_disp_write);

// 指定fast io处理函数

if(!wd_fio_disp_init(driver,sizeof(wd_fio_disp)))

{

wd_dev_del(g_cdo);

wd_printf0("error: fast io disp init failed.rn");

return wd_stat_insufficient_res;

}

// 下面指定的这些函数都定义在wdf_filter_fio.h中,其实这些函数都统

// 一的返回了false

wd_fio_disp_set_check(

driver,

my_fio_check);

wd_fio_disp_set_read(

driver,

my_fio_read);

wd_fio_disp_set_write(

driver,

my_fio_write);

wd_fio_disp_set_query_basic(

driver,

my_fio_query_basic_info);

...

}

FastIo函数个数数量不明,我只觉得很多。因此不打算全部罗列,以"..."敷衍之。某些读者可能会认为这些代码无法调试安装。其实您可以参考sfilter中的示例自己完成这些代码。

使用Fast I/O

在这里我们将讲述Fast I/O的基本原理,简单描述各种各样的Fast I/O调用,以及得出如何使用此接口来提高程序性能的建议性结论。

Windows NT内核模式开发的标准做法是采用IRP作为基本的与驱动程序通信的手段,它的优点是IRP封装了上下文所需的详细操作并且允许从驱动程序的众多操作细节中分离出来。

这个方法在windos NT的分层设备体系中非常通用,有相当多的上层操作请求需要快速响应,在这种情况下,上层操作生成IRP决定了整个操作的成本并会导致系统性能的下降。鉴于此,NT系统引入的Fast I/O的概念。这种方法被用在文件系统驱动,如NTFS,HPFS,

FAT和CDFS以及被WinSock使用的传输驱动AFD。

任何驱动都可以注册一系列Fast I/O接口,但使用起来还有很大的限制—在这些接口被调之前需要满足合适的条件。例如,读操作和写操作的Fast I/O接口只有当Windows NT cache 管理器保留了文件的信息时才被调用。我们在接下的论述中将会讲述这些限制。

当然,Windows NT的Fast I/O最让人郁闷的是关于它的资料很少,即使文件系统开发包也没有讲述Fast I/O是如何工作和怎样来使用Fast I/O。

原理

提供了Fast I/O是非常方便的---许多I/O操作可以对相同的数据进行重复操作。例如和许多流行的操作系统一样,Windows NT用虚拟内存集成了文件系统的缓冲,这样的系统无论是在使用上还是在感觉上都很有效率。

这种集成的另一原因是Windows NT支持内存映射文件。支持读写和内存映射相同的数据要么需要代价很高的cache一致性策略,要么使用NT的策略---将所有数据存储在虚拟内存中。这样,即便是两个程序用不同的技术访问相同的数据,也确保了数据的一致性。

这种紧密的集成意味着无论是读还是写都经常是对cache中的数据来操作。在查找过程中,这种策略用来调用一个特殊的程序,此程序将虚拟机(VM)的cache中的数据移到用户内存中,反之亦然。这样就避免了生成IRP,并且不需要请求底层的驱动了。这就是Fast I/O操作的基本功能。

一旦在程序中定义了Fast I/O读写接口,那么同时还需要进行一步添加其它的通用Fast I/O 操作到Fast I/O链中,Fast I/O链中有13个接口(在NT3.51中)。在我们接下来要讲的各接口过程中,你会明显地发现各接口是互相关联的。这些接口包含在FAST_IO_DISPATCH结构中,此结构在ntddk.h中有定义。这个结构的第一个元素表示结构的大小,为以后在结构添加新接口提供了一种向上兼容的机制。

I/O管理器和Fast I/O

I/O管理器在必要的时候负责调用Fast I/O接口。Fast I/O调用返回TRUE或FALSE表示Fast I/O操作是否完成。如果Fast I/O没有被完成或无效,则会产生一个IPR并发送到上层驱动,但是FAST_IO_DISPA TCH结构中最近的三个接口却不是这样的,它们为I/O管理员提供了不同的服务,接下来我们将讨论它们。

FastIoCheckIfPossible

这是在FAST_IO_DISPA TCH结构中第一个调用的,仅被用来作为一般的文件系统库操作(以FsRtl开头的函数)。原型如下:

typedef BOOLEAN (*PFAST_IO_CHECK_IF_POSSIBLE)(

IN Struct _FILE_OBJECT *FileObject,

IN PLARGE_INTEGER FileOffset,

IN ULONG Length,

IN BOOLEAN Wait,

IN ULONG LockKey,

IN BOOLEAN CheckForReadOperation,

OUT PIO_STATUS_BLOCK IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject

);

这个函数被FsRtl库中提供的通用的Fast I/O函数调用,仅用在读写操作中,以获取使用了通用文件缓存管理系统中的读和写是否能在文件缓存中被响应(由参数CheckForReadOperation的值决定)。注意,除了这个函数没有分配任何数据空间外其它参数和读写的Fast I/O接口参数相似。

FastIoRead and FastIoWrite

当对一个已经分配了有效数据缓存的文件进行读请求时,这个函数被I/O管理器调用。原型如下:

typedef BOOLEAN (*PFAST_IO_READ)(

IN struct _FILE_OBJECT *FileObject,

IN PLARGE_INTEGER FileOffset,

IN ULONG Length,

IN BOOLEAN Wait,

IN ULONG LockKey,

OUT PVOID Buffer,

OUT PIO_STATUS_BLOCK IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject

);

正如前面所讲的,基本的调用参数和FastIoCheckIfPossible相似,就是多了一个必要的数据缓存参数。要保证所有Fast I/O调用接口的参数有效,例如上面的Buffer指针,必需是有效的并且在读线程的上下文中能使用此指针。

Fast I/O函数可以完成以下两件事情之一:第一,当操作完成时设置IoStatus的返回值并给I/O管理器返回TRUE,这时I/O管理器会完成对应的I/O操作。第二,直接返回FALSE给I/O管理器使其构造一个IRP从而调用标准的分派例程。

要注意的是返回TRUE并不能保证数据被传输了。例如,一个从文件结束处开始的读请求会设置IoStatus.Results为STA TUS_END_OF_FILE,并且没有数据被复制。但是当一个读操作读到了文件的结尾,这时会将IoStatus.Results设置为STATUS_END_OF_FILE,返回TRUE,并且将读到的数据复制到Buffer里。

同样,返回FALSE并不能说明所有的数据没有被处理。例如,当然很少有这种可能,数据已经被成功处理了,但抛出一个I/O错误,或者内存不可访问。

以上任何一种情况出现都会导致不良影响。例如,从缓存读数据时,可能要读的数据并不在缓存中,这时会导致一个页错误,从而会请求文件系统来处理这个页面错误。

Fast I/O的写函数与读函数不同之处仅仅在于Buffer参数一个是输入型而不是输出型的,其它的基本操作很相似。当然,一些错误可能不同---介质已经满,需要分配新页等等。

FastIoQueryBasicInfo and FastIoQueryStandardInfo

这两个操作为标准的NtQueryInformationFile API操作提供了支持,而FastIoQueryBasicInfo 也经常被用来处理NtCreateFile的特定操作。文件的基本属性包括创建时间、访问时间和修改时间,以及隐藏、文件夹或其它属性等。文件的标准属性包括文件占用的空间、文件的大小、文件的硬连接号、被请求删除的标志,是否是文件夹的标识。

由于这些信息经常在缓存中,所以它是FAST I/O操作的最佳候选。其实许多程序用这种方法来获取文件基本的信息,因为这种方法提高了操作的效率和程序的性能,如文件管理器程序(winfile.exe)。

这两个Fast I/O例程有相同的接口:

typedef BOOLEAN (*PFAST_IO_QUERY_ABSIC_INFO)(

IN struct _FILE_OBJECT *FileObject,

IN BOOLEAN Wait,

OUT PFILE_BASIC_INFORMA TION Buffer,

OUT PIO_STATUS_BLOCK IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject);

Wait参数表示调用者是否阻塞以等待获取信息的返回,如果设置为FALSE,则调用要么立刻完成,要么返回FALSE,如果返回FALSE,则会生成一个包含整个操作必要的上下文件的IRP。有趣的是在NT3.51中当Wait设置为FALSE时这两个例程将不被调用,当然这在以后的版本中会修改。

这两个例程一但被调用,它们会查询文件对象第一次打开时保存的信息,这些信息也可能被实时变化,例如,文件的最近访问时间属性会被文件系统设置的当前的系统时间,当然设置这些属性取决于文件系统的实现。

FastIoLock,FastIoUnLockSingle,FastIoUnLockAll,and FastIoUnLockAllByKey

这些例程被用来控制特殊文件的加锁状态。对文件的加锁以字节为单位,所以可以对文件的多个字节进行加密。标准的NT文件系统使用文件系统运行时开发包(FsRtl函数)所提供的通用代码来验证锁权限并存储文件的加锁范围。锁状态通过调用NT API函数NtLockFile和NtUnLockFile来控制。

在Windows NT中有两种锁,一种是排它锁,是写锁,说明加锁的地放要进行修改;另一种

是共享锁,是读锁,说明加锁的地放用来的读的。多个共享锁在重叠操作中可以被授权,并且一直保存到释放为止。将各种加锁的信息存储起来在访问这些信息的时候会提高速度。FastIoLock的原型:

Typedef BOOLEAN (*PFAST_IO_LOCK)(

IN struct _FILE_OJBECT *FileObject,

IN PLARGE_INTEGER FileOffset,

IN PLARGE_INTEGER Length,

PEPROCESS ProcessId,

ULONG Key,

BOOLEAN FailImmediately,

BOOLEAN ExclusiveLock,

OUT PIO_STATUS_BLOCK IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject

);

FileOffset 和Length参数对应加锁的范围,ProcessId标识加锁的进程,如果进行退出,锁将会清除。Key参数提供一个非透明的值,用来关联多个锁,例如调用FastIoUnLockAllByKey 可以快速访问多个锁。FailImmediately用来标识当锁无效时是立刻返回失败还是阻塞直到锁可用。对于FsRtl函数,如果是无效的锁则忽略FailImmediately参数,函数返回FALSE。ExclusiveLock参数用来标识是排它锁还是共享锁。

FastUnlockSingle例程被用来释放对文件的加锁,原型如下:

Typedef BOOLEAN (*PFAST_IO_UNLOCK_SINGLE)(

IN struct _FILE_OBJECT *FileObject,

IN PLARGE_INTEGER FileOffset,

IN PLARGE_INTEGER Length,

PEPROCESS ProcessId,

ULONG Key,

OUT PIO_STATUS_BLOCK IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject

);

对大多文件系统来说,如果文件没有加锁,此例程总是返回TRUE,即使朝无效的锁,操作也会完成,因为用IRP来操作也同样会产生相同的错误。

如果这个解锁操作成功,那么FileOffset,Length,ProcessId,和Key必须和相应的锁信息匹配,否则操作会返回错误STA TUS_RANGE_NOT_LOCKED。FastIoUnlockAll例程用来释放特殊文件所有的锁,函数原型如下:

typedef BOOLEAN(*PFAST_IO_UNLOCK_ALL)(

IN struct _FILE_OBJECT *FileObject,

PEPROCESS ProcessId,

OUT PIO_STATUS_BLOCK IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject

);

在这种情况下,Fast I/O例程查找进程ProcessId所操作的文件所有的锁,并删除,无论是排它锁还是共享锁。这个例程常用在当系统由于关掉程序或终止程序而调用NtCloseFile时。

FastIoUnlockAllByKey操作用来通过一些特殊的键值来删除一系列锁。原型如下:Typedef BOOLEAN (*PFAST_IO_UNLOCK_ALL_BY_KEY)(

IN struct _FILE_OBJECT *FileObject,

PVOID ProcessId,

ULONG Key,

OUT PIO_STATUS_BLOCK_IoStatus,

IN struct _DEVICE_OBJECT *DeviceObject

);

提供这个例程是为了便于文件服务如SRV。在NT3.51的I/O管理器中没有出现这个调用。键值用来文件服务给远程客户机文件加锁时分配的。因为许多远程客户端,仅有ProcessId 是远远不够的。同样,对于多文件服务器,仅使用键值也会在其它的文件服务器释放时导致错误。二者同时使用以确保正确操作并允许远程加锁。

4.设备栈,过滤,文件系统的感知

前边都在介绍文件系统驱动的结构,却还没讲到我们的过滤驱动如何能捕获所有发给文件系统驱动的irp,让我们自己来处理?前面已经解释过了设备对象。现在来解释一下设备栈。

任何设备对象都存在于某个设备栈中。设备栈自然是一组设备对象。这些设备对象是互相关联的,也就是说,如果得到一个DO指针,你就可以知道它所处的设备栈。

任何来自应用的请求,最终被windows io mgr翻译成irp的,总是发送给设备栈的顶端那个设备。

原始irp irp irp irp

--------------> ------> -------> ----->

DevTop Dev2 ... DevV olumne ... ???

<-------------- <------ <------- <-----

原始irp(返回)irp irp irp

上图向右的箭头表示irp请求的发送过程,向左则是返回。可见irp是从设备栈的顶端开始,逐步向下发送。DevV olumue表示我们实际要过滤的Volume设备,DevTop表示这个设备栈的顶端。我们只要在这个设备栈的顶端再绑定一个设备,那发送给Volume的请求,自然会先发给我们的设备来处理。

有一个系统调用可以把我们的设备绑定到某个设备的设备栈的顶端。这个调用是IoAttachDeviceToDeviceStack,这个调用2000以及以上系统都可以用(所以说到这点,是因为还有一个IoAttachDeviceToDeviceStackSafe,是2000所没有的。这常常导致你的filter在2000下不能用。)

我自己写了一个函数来帮我实现绑定功能:

//----------------------wdf.h中的内容----------------------------------

// 这个例程把源设备绑定到目标设备的设备栈中去,并返回源设备所直

// 接绑定的设备。注意源设备未必直接绑定在目标设备上。它应绑定在

// 目标设备的设备栈的顶端。

_inline wd_stat wd_dev_attach(in wd_dev *src,

in wd_dev *dst,

in out wd_dev **attached)

{

*attached = dst;

*attached = IoAttachDeviceToDeviceStack(src,dst);

if(*attached == NULL)

return wd_stat_no_such_dev;

return wd_stat_suc;

}

到这里,我们已经知道过滤对V olume的请求的办法。比如“C:”这个设备,我已经知道符号连接为“C:”,不难得到设备名。得到设备名后,又不难得到设备。这时候我们IoCreateDevice()生成一个Device Object,然后调用wd_dev_attach绑定,不是一切ok吗?所有发给“C:”的irp,就必然先发送给我们的驱动,我们也可以捕获所有对文件的操作了!

这确实是很简单的处理方法。我得到的FileMon的代码就是这样处理的,如果不想处理动态的Volume,你完全可以这样做。但是我们这里有更高的要求。当你把一个U盘插入usb口,一个“J:”之类的Volume动态诞生的时候,我们依然要捕获这个事件,并生成一个Device 来绑定它。

一个新的存储媒质被系统发现并在文件系统中生成一个Volume的过程称为Mounting.其过程开始的时候,FS的CDO将得到一个IRP,其Major Function Code为IRP_MJ_FILE_SYSTEM_CONTROL,Minor Function Code为IRP_MN_MOUNT。换句话说,如果我们已经生成了一个设备绑定文件系统的CDO,那么我们就可以得到这样的IRP,在其中知道一个新的V olume正在Mount.这时候我们可以执行上边所说的操作。

现在的问题是如何知道系统中有那些文件系统,还有就是我应该在什么时候绑定它们的控制设备。

IoRegisterFsRegistrationChange()是一个非常有用的系统调用。这个调用注册一个回调函数。当系统中有任何文件系统被激活或者是被注销的时候,你注册过的回调函数就会被调用。

//----------------------wdf.h中的内容----------------------------------

wd_stat wdff_reg_notify(

in wd_drv *driver,

in wdff_notify_func func

)

{

return IoRegisterFsRegistrationChange(driver,func);

}

你有必要为此写一个回调函数。

//-------------------我的回调处理函数----------------------------------

wd_void my_fs_notify(

in wd_dev *dev,

in wd_bool active)

{

wd_wchar name_buf[wd_dev_name_max_len];

wd_ustr name;

wd_ustr_init_em(&name,name_buf,wd_dev_name_max_len);

// 如果注册了,就应该得到通知

wd_printf0("notify: a file sys have been acitved!!! rn");

// 得到文件系统对象的名字,然后打印出来

wd_obj_get_name(dev,&name);

wd_printf0("notify : file sys name = %wZrn",&name);

if(active)

{

wd_printf0("notify: try to attach.rn");

// ... 请在这里绑定文件系统的控制设备

}

else

{

wd_printf0("notify: unactive.rn");

// ...

}

}

应该如何绑定一个文件系统CDO?我们在下面的章节再详细描述。现在我们应该再在wd_main函数中加上下边的内容:

if(wdff_reg_notify(driver,my_fs_notify) != wd_stat_suc)

{

wd_printf0("error: reg notify failed.rn");

wd_fio_disp_release(driver);

wd_dev_del(g_cdo);

g_cdo = wd_null;

return wd_stat_insufficient_res;

};

wd_printf0("success: reg notify ok.n");

我们再次回顾一下,wd_main中,应该做哪些工作。

a.生成一个控制设备。当然此前你必须给控制设置指定名称。

b.设置Dispatch Functions.

c.设置Fast Io Functions.

d.编写一个my_fs_notify回调函数,在其中绑定刚激活的FS CDO.

e.使用wdff_reg_notify调用注册这个回调函数。

5.绑定FS CDO,文件系统识别器,设备扩展

上一节讲到我们打算绑定一个刚刚被激活的FS CDO.前边说过简单的调用wd_dev_attach可以很容易的绑定这个设备。但是,并不是每次my_fs_notify调用发现有新的fs激活,我就直接绑定它。

首先判断是否我需要关心的文件系统类型。我用下面的函数来获取设备类型。

// ------------------wdf.h中的内容-------------------

_inline wd_dev_type wd_dev_get_type(in wd_dev *dev)

{

return dev->DeviceType;

}

文件系统的CDO的设备类型有下边的几种可能,你的过滤驱动可能只对其中某些感兴趣。

enum {

wd_dev_disk_fs = FILE_DEVICE_DISK_FILE_SYSTEM,

wd_dev_cdrom_fs = FILE_DEVICE_CD_ROM_FILE_SYSTEM,

wd_dev_network_fs = FILE_DEVICE_NETWORK_FILE_SYSTEM

};

你应该自己写一个函数来判断该fs是否你所关心的。

// -------------一个函数,判断是否我所关心的fs---------------

windows驱动开发和调试环境搭建

Windows驱动开发和环境搭建 【文章标题】: Windows驱动开发和调试的环境设置 【文章作者】: haikerenwu 【使用工具】: VC6.0,VMware6.0.3,Windbg 【电脑配置】: 惠普笔记本xp sp3 (一)VMWare安装篇 VMWare的安装一路Next即可,关于其序列号,百度一下就能找到,虚拟机安装完成之后,需要安装操作系统,我在虚拟机中安装的是windows xp sp2系统。 点击“文件”----“新建”----“虚拟机” 进入新建虚拟机的向导,配置虚拟系统参数

选择虚拟系统文件的兼容格式(新手推荐选择默认选项) 按照默认设置继续点击下一步,选择好您需要的操作系统,此处我选择的是Windows XP Prefessional。 设置虚拟机名称和虚拟操作系统安装路径,我单独空出来一个F 盘,将虚拟机和虚拟操作系统全部装在该盘。

配置网络模式(推荐选择NA T,一般主机不用做任何的设置虚拟机就可以利用主机上网)。 配置虚拟磁盘的容量。在这里可以直接单击完成,来完成基本操作设置,磁盘默认空间是8GB,用户可以根据自己的实际使用情况来调整大小,也可以自定义分区。

操作完成之后,在“VM”菜单下有个“setting。。。”菜单,点击此菜单,在CD-ROM中选择合适的选项,我使用的是Use ISO image 选项,将我的xp sp2操作系统的ISO映像路径设置好,安装操作系统。点击ok之后,启动虚拟机,即开始安装操作系统,安装过程跟普通装机过程相同。安装完成之后,启动操作系统,然后在VM菜单下点击“Install VMWare Tools”,把虚拟操作系统的驱动装好。 (二)VMWare设置篇

Windows驱动开发培训

Windows驱动开发培训 培训流程: 一、基础知识 在开始驱动开发之前,您应该知道操作系统原理以及驱动程序是如何在操作系统中进行工作的,了解这些基本原理将有助于您做出正确的设计决策并简化您的开发过程。 1、了解Windows操作系统构造\\ 可以链接进去 2、安装WDK,参考相关文档,熟悉WDK的内容\\ 可以链接进去 二、Windows驱动开发\\ 可以链接进去 一、基础知识 在开始驱动开发之前,您应该知道操作系统原理以及驱动程序是如何在操作系统中进行工作的,了解这些基本原理将有助于您做出正确的设计决策并简化您的开发过程。 1、了解Windows操作系统构造 (1)培训目标 深入了解Windows操作系统的系统结构以及工作原理 (2)培训内容 阅读书籍《深入解析Windows操作系统》的第3、4、6、7、9章,重点关注第九章“I/O系统” (3)培训任务 ①掌握Windows操作系统的系统结构 ②理解ISR、IRP、IRQL、DCP等概念的含义 ③了解注册表的用法,掌握注册表数据的查看和修改方法 ④了解进程和线程的内部机理以及线程的调度策略 ⑤了解I/O系统的内容,理解I/O请求以及I/O处理过程 注:以上相关内容,请在一周内完成。

2、安装WDK,参考相关文档,熟悉WDK的内容 (1)培训目标 了解WDK的安装过程,熟悉WDK的编译环境,掌握如何使用WDK的相关帮助文档;了解WDM驱动程序的基本结构 (2)培训内容 ①.阅读文档\\10.151.131.12\book\windows\MSWDM.chm,掌握WDM驱动程序的基本结构以及基本的编程技术。 ②.参考WDK的帮助文档:WDK documentation ,了解WDK的基本内容 (3)培训任务 ①理解分层驱动结构的含义,掌握设备和驱动程序的层次结构 ②理解“驱动对象”和“设备对象”的概念 ③理解2个基本例程:DriverEntry 和addDevice ④了解IRP的结构以及IRP处理的流程 ⑤初步了解I/O的控制操作 注:以上相关内容,请在一周内完成。 二、Windows驱动开发 学习如何基于WDK进行驱动程序的开发 1、培训目标 (1)学会根据WDK开发一个基本的Windows驱动程序和测试程序 (2)学会利用不同的IOCTL方式在内核模式和用户模式之间进行通讯 (3)学会如何在内核模式下和用户模式下访问注册表 (4)利用WinDbg跟踪程序,学会使用WinDbg进行调试 2、培训内容 (1)阅读\src\general\ioctl中的示例代码 (2)build并运行应用程序和驱动程序

Windows驱动开发入门

接触windows驱动开发有一个月了,感觉Windows驱动编程并不像传说中的那么神秘。为了更好地为以后的学习打下基础,记录下来这些学习心得,也为像跟我一样致力于驱动开发却苦于没有门路的菜鸟朋友们抛个砖,引个玉。 我的开发环境:Windows xp 主机+ VMW ARE虚拟机(windows 2003 server系统)。编译环境:WinDDK6001.18002。代码编辑工具:SourceInsight。IDE:VS2005/VC6.0。调试工具:WinDBG,DbgView.exe, SRVINSTW.EXE 上面所有工具均来自互联网。 对于初学者,DbgView.exe和SRVINSTW.EXE是非常简单有用的两个工具,一定要装上。前者用于查看日志信息,后者用于加载驱动。 下面从最简单的helloworld说起吧。Follow me。 驱动程序的入口函数叫做DriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING pRegisgryString)。两个参数,一个是驱动对象,代表该驱动程序;另一个跟注册表相关,是驱动程序在注册表中的服务名,暂时不用管它。DriverEntry 类似于C语言中的main函数。它跟main的差别就是,main完全按照顺序调用的方法执行,所有东西都按照程序员预先设定的顺序依次发生;而DriverEntry则有它自己的规则,程序员只需要填写各个子例程,至于何时调用,谁先调,由操作系统决定。我想这主要是因为驱动偏底层,而底层与硬件打交道,硬件很多都是通过中断来与操作系统通信,中断的话就比较随机了。但到了上层应用程序,我们是看不到中断的影子的。说到中断,驱动程序中可以人为添加软中断,__asm int 3或者Int_3();前者是32位操作系统用的,后者是64位用的。64位驱动不允许内嵌汇编。下面是我的一个helloworld的源码:

操作系统与驱动开发试题

河北科技大学硕士学位研究生 2014——2015学年第1学期 《操作系统与驱动开发》课程期末考试试卷 学院信息学院专业电路与系统姓名程莉学号 2201414007 题号一二三四五六总分 得分 一.单项选择题(每小题1分,共10分) 1.操作系统的 D 管理部分负责对进程进行调度。 A.主存储器 B.控制器 C.运算器 D.处理机 2.分时操作系统通常采用 B 策略为用户服务。 A.可靠性和灵活性 B.时间片轮转 C.时间片加权分配 D.短作业优先 3.很好地解决了“零头”问题的存储管理方法是 A 。 A 页式存储管理 B 段式存储管理 C 多重分区管理 D 可变式分区管理 4.用WAIT、SIGNAL操作管理临界区时,信号量的初值应定义为 B 。 A.-1 B.0 C.1 D.任意值 5.在进程管理中,当 C 时,进程从阻塞状态变为就绪状态。 A.进程被进程调度程序选中 B.等待某一事件 C.等待的事件发生 D.时间片用完 6.某系统中有3个并发进程,都需要同类资源4个,试问该系统不会发生死锁的最少资源数 B 。 A.9 B.10 C.11 D.12 7.虚拟存储器管理系统的基础是程序的 B 理论。 A.全局性 B.局部性 C. 动态性 D.虚拟性 8.从用户的角度看,引入文件系统的主要目的是 D A.实现虚拟存储 B.保存系统文档

C.保存用户和系统文档 D.实现对文件的按名存取 9.操作系统中采用多道程序设计技术提高CPU和外部设备的 A A.利用率 B.可靠性 C.稳定性 D.兼容性 10.缓冲技术中缓冲池在 C 中。 A.主存 B. 外存 C. ROM D. 时间片轮转 二.填空(每空0.5分,共15分)。 11.进程存在的唯一标志是PCB 。 12.通常进程实体是由程序块、进程控制块和数据块三部分组成。 13.磁盘访问时间由寻道时间、旋转延迟时间和传输时间组成。 14.作业调度是从后备作业队列中选一些作业,为它们分配资源,并为它们创建进程。 15.文件的物理组织有顺序、链接和索引。 16.若一个进程已经进入临界区,则其它欲要进入临界区的进程必须___等待____。 17.信号量的物理意义是,当信号量值大于零时其值表示可分配资源的个数;当信号 量值小于零时,其绝对值表示等待使用该资源的进程的个数。 18.静态重定位在程序装入时进行; 而动态重定位在程序运行时进行。 19.分区管理中采用“最佳适应”分配算法时,宜把空闲区按长度递增次序登记在空闲 区表中。 20.所谓系统调用,就是用户在程序中调用操作系统所提供的一些子功能。 21.把逻辑地址映射为物理地址的工作称为地址映射。 22.设备管理中采用的数据结构有设备控制表、控制器控制表、通道控制表、 系统设备表等四种。 23.从资源管理(分配)的角度,I/O设备可分为独占设备、共享设备和虚 拟设备三种。 24.设备与控制器之间的接口信号主要包括数据、状态和控制。 25.DMA控制器由三部分组成,分别为主机与DMA控制器的接口、 DMA控制器与块设备的接 口和 I/O控制逻辑。 三.名词解释(每小题2.5分,共10分)。 26.虚拟存储器 答:虚拟存储器是指在具有层次结构存储器的计算机系统中,自动实现部分装入和部分替换功能,能从逻辑上为用户提供一个比物理贮存容量大得多,可寻址的“主存储器”。

Windows驱动程序开发环境配置

Windows驱动程序开发笔记 一、WDK与DDK环境 最新版的WDK 微软已经不提供下载了这里:https://https://www.doczj.com/doc/1c13597342.html,/ 可以下并且这里有好多好东东! 不要走进一个误区:下最新版的就好,虽然最新版是Windows Driver Kit (WDK) 7_0_0,支持windows7,vista 2003 xp等但是它的意思是指在windows7操作系统下安装能编写针对windows xp vista的驱动程序, 但是不能在xp 2003环境下安装Windows Driver Kit (WDK) 7_0_0这个高版本,否则你在build的时候会有好多好多的问题. 上文build指:首先安装好WDK/DDK,然后进入"开始"->"所有程序"->"Windows Driver Kits"->"WDK XXXX.XXXX.X" ->"Windows XP"->"x86 Checked Build Environment"在弹出来的命令行窗口中输入"Build",让它自动生成所需要的库 如果你是要给xp下的开发环境还是老老实实的找针对xp的老版DDK吧,并且xp无WDK 版只有DDK版build自己的demo 有个常见问题: 'jvc' 不是内部或外部命令,也不是可运行的程序。 解决办法:去掉build路径中的空格。 二、下载 WDK 开发包的步骤 1、访问Microsoft Connect Web site站点 2、使用微软 Passport 账户登录站点 3、登录进入之后,点击站点目录链接 4、在左侧的类别列表中选择开发人员工具,在右侧打开的类别:开发人员工具目录中找到Windows Driver Kit (WDK) and Windows Driver Framework (WDF)并添加到您的控制面板中 5、添加该项完毕后,选择您的控制面板,就可以看到新添加进来的项了。 6、点击Windows Driver Kit (WDK) and Windows Driver Framework (WDF),看到下面有下载链接,OK,下载开始。下载后的文件名为: 6.1.6001.18002.081017-1400_wdksp-WDK18002SP_EN_DVD.iso将近600M大小。

WINDOWS驱动编程

WDM驱动程序开发之读写设备寄存器:KIoRange类 2009-11-09 14:05 WDM驱动程序开发之读写设备寄存器:KIoRange类收藏 KIoRange类: 一、Overview KIoRange类将一系列特殊的外围总线的地址映射到CPU总线的地址空间。CPU总线上的地址即可能在CPU的I/O空间,也可能在CPU的内存空间,这取决于平台和外围总线的控制方式。考虑到可移植性,所有对I/O周期(I/O cycle)进行译码的设备驱动程序必须用这个类对I/O的位置(location)进行正确的访问(access)。KIoRange是KPeripheralAddress类的派生类。 一旦映射关系建立起来,驱动程序就用KIoRange类的成员函数去控制设备的I/O寄存器。这个类提供了8位、16位和32位I/O访问控制的函数。这些函数是以内联(in-line)函数方式来使用的,它们调用系统内相应的宏来产生依赖于平台的代码。 对I/O位置(location)进行访问的另一种备选方案是创建一个KIoRegister 的实例。这要通过取得一个KIoRange对象的数组元素来实现。 为了访问一系列外围总线内存空间的地址,需要用KMemoryRange类。 二、Member Functions 1、KIoRange - Constructor (4 forms) 构造函数 【函数原型】 FORM 1: KIoRange( void ); FORM 2: (NTDDK Only) KIoRange( INTERFACE_TYPE IntfType, ULONG BusNumber , ULONGLONG BaseBusAddress, ULONG Count, BOOLEAN MapToSystemVirtual =TRUE ); FORM 3 (WDM): KIoRange( ULONGLONG CpuPhysicalAddress, BOOLEAN InCpuIoSpace, ULONG Count, BOOLEAN MapToSystemVirtual =TRUE

Windows 内核技术与驱动开发笔记(完整版)

Windows 内核技术与驱动开发笔记 1.简述Driver Entry例程 动程序的某些全局初始化操作只能在第一次被装入时执行一次,而Driver Entry例程就是这个目的。 * Driver Entry是内核模式驱动程序主入口点常用的名字。 * Driver Entry的第一个参数是一个指针,指向一个刚被初始化的驱动程序对象,该对象就代表你的驱动程序。WDM驱动程序的Driver Entry例程应完成对这个对象的初始化并返回。非WDM驱动程序需要做大量额外的工作,它们必须探测自己的硬件,为硬件创建设备对象(用于代表硬件),配置并初始化硬件使其正常工作。 * Driver Entry的第二个参数是设备服务键的键名。这个串不是长期存在的(函数返回后可能消失)。如果以后想使用该串就必须先把它复制到安全的地方。 * 对于WDM驱动程序的Driver Entry例程,其主要工作是把各种函数指针填入驱动程序对象,这些指针为操作系统指明了驱动程序容器中各种例程的位置。 2.简述使用VC进行内核程序编译的步骤 编译方式是使用VC++进行编译 1.用VC新建工程。 2.将两个源文件Driver.h和Driver.cpp拷贝到工程目录中,并添加到工程中。 3.增加新的编译版本。 4.修改工程属性,选择“project | setting”将IterMediate file和Output file 都改为MyDriver_Check。 5.选择C/C++选项卡,将原有的Project Options内容全部删除替换成相关参数。 6.选择Link选项卡,将原有的Project Options内容删除替换成相关Link。 7.修改VC的lib目录和include的目录。 8.在VC中选择tools | options,在弹出的对话框中选择“Directories”选项卡,在“Show directories for”下拉菜单中选择“Include file”菜单。添加DDK的相关路径。 3.简述单机内核调试技术 答:1.下载和安装WinDbg能够调试windows内核模块的调试工具不多,其中一个选择是微软提供的WinDbg 下载WinDbg后直接双击安装包执行安装。 2.安装好虚拟机以后必须把这个虚拟机上的windows设置为调试执行。在被调试系统2000、2003或是xp的情况下打开虚拟机中的windows系统盘。 3.将boot.ini文件最后一行复制一下,并加上新的参数使之以调试的方法启动。重启系统,在启动时就可以看到菜单,可以进入正常windows xp,也可以进入Debug模式的windows xp。 4.设置VMware管道虚拟串口。调试机与被调试机用串口相连,但是有被调试机是虚拟机的情况下,就不可能用真正的串口连接了,但是可以在虚拟机上生成一个用管道虚拟机的串口,从而可以继续内核调试。 4.请画出Windows架构简图

windows驱动开发 driverstudio 教程

前言 鉴于国内开发人员迫切需要学习驱动开发技术,而国内有关驱动开发工具DriverStudio的资料很少,大家在开发过程中遇到很多问题却没处问,没法问.而这些问题却是常见的,甚至是很基础的问题。 有感于此,本站联合北京朗维计算机应用公司编写了本教程。本教程的目的是让一个有一些核心态程序编写经验或对系统有所了解的人学习编写驱动程序。当然,本教程不是DDK中有关驱动方面内容的替换,而只是一个开发环境的介绍和指导。 学习本教程,你应该能熟练地使用本套工具编写基本的驱动程序。当然如果你想能顺利地编写各种各样的驱动的话,你应该有相关的硬件知道和系统核心知识并且要经过必要的训练才能胜任。 如果真心说一句话,DriverStudio并没有对驱动程序开发有什么实质的改变,它和DDk的关系不过是sdk和mfc的关系,但很多人选择了MFC,原因不言自明,方便二字何以说得完呀?你再也不用去关注繁琐的框架实现代码,也不用去考虑让人可怕的实现细节。封装完整的C++函数库让你专注于你要实现的程序逻辑。它包含一套完整调试和性能测试、增强工具,使你的代码更稳定。 说些题外话,作驱动开发很苦,不是一般的人能忍受的,那怕开发一个小小的驱动也要忍受无数次的宕机,有时甚至有些灾难性的事故等着你,所以要有充分的思想准备。当然,在开发的过程中你会有一种彻底控制计算机的满足感,调试开发完毕后的成就感是其它开发工作所不能体会到的。当然,就个人前途来说,作驱动开发能拿到别的开发所不能得到的薪水。而且开发的生命期也会长一些,你不用不断的学习新的开发工具,只需要不断的加深对系统的理解就行了。当然,还有一点是必需的,那就是英文要好,否则永远比国外同行慢半拍。 本人水平不高,所做的工作只要能提起大家学习驱动开发的兴趣,能带领大家入门便心满意足了。在此感谢北京朗维公司(DriverStduio 国内总代理)的大力赞助,特别是感谢技术部的王江涛,市场部的李强两位先生的大力支持。同时要感谢我的女友,可爱的小猫(我对她的呢称)的贴心照顾和支持(一些很好看的图片就出自她手:))。在此我也要感谢论坛各大版主的鼎力支持和广大网友的关怀。 DriverStudio工具包介绍: DriverStudio 是一套用来简化微软Windows 平台下设备驱动程序的开发,调试和测试的工具包。DriverStudio 当前的版本包括下列工具模块: DriverAgent DriverAgent 为Win32 应用程序提供直接访问硬件的功能。即使你没有任何设备驱动程序开发的经验或经历,你也能编写出DriverAgent应用程序来直接访问硬件设备。DriverAgent 应用程序可以运行在 Windows 98, Windows 95, Windows NT 和 Windows 2000平台上。(当前版本不支持Windows XP平台。) VToolsD VToolsD 是一个用来开发针对Win9X (Windows 95 和 Windows 98)操作系统下设备驱动程序(VxD)

Windows驱动程序框架理解_经典入门

标题: 【原创】Windows驱动程序框架 windows驱动程序入门比较坑爹一点,本文旨在降低入门的门槛。注:下面的主要以NT式驱动为例,部分涉及到WDM驱动的差别会有特别说明。 首先,肯定是配置好对应的开发环境啦,不懂的就百度下吧,这里不再次描述了。 在Console控制台下,我们的有一个入口函数main;在Windows图形界面平台下,有另外一个入口函数Winmain。我们只要在这入口函数里面调用其他相关的函数,程序就会按照我们的意愿跑起来了。在我们用IDE开发的时候,也许你不会发现这些细微之处是如何配置出来的,一般来说我们也不用理会,因为在新建工程的时候,IDE已经帮我们把编译器(Compiler)以及连接器(Linker)的相关参数设置好,在正式编程的时候,我们只要按照规定的框架编程就行了。 同样,在驱动程序也有一个入口函数DriverEntry,这并不是一定的,但这是微软默认的、推荐使用的。在我们配置开发环境的时候我们有机会指定入口函数,这是链接器的参数/entry:"DriverEntry"。 入口函数的声明 代码: DriverEntry主要是对驱动程序进行初始化工作,它由系统进程(System)创建,系统启动的时候System系统进程就被创建了。 驱动加载的时候,系统进程将会创建新的线程,然后调用执行体组件中的对象管理器,创建一个驱动对象(DRIVER_OBJECT)。另外,系统进程还得调用执行体组件中的配置管理程序,查询此驱动程序在注册表中对应项。系统进程在调用驱动程序的Driv erEntry的时候就会将这两个值传到pDriverObject和pRegistryPath。 接下来,我们介绍下上面出现的几个数据结构: typedef LONG NTSTATUS 在驱动开发中,我们应习惯于用NTSTATUS返回信息,NTSTATUS各个位有不同的含义,我们可以也应该用宏NT_SUCCESS来判断是否返回成功。 代码: NTSTAUS的编码意义: 其中 Ser是Serviity的缩写,代表严重程度。 00:成功01:信息10:警告11:错误 C是Customer的缩写,代表自定义的位。

Windows驱动开发技术详解 第六章的(Windows内核函数)自我理解

Windows驱动开发技术详解第六章的(Windows内核函数)自我理解 学习各种高级外挂制作技术,马上去百度搜索(魔鬼作坊),点击第一个站进入,快速成为做挂达人。 其实这章主要就是讲函数DDK有自己的函数跟SDK一样编写DDK使用DDK提供的函数就OK了 /////////////////////////////////////////////////////////////////////////////// ASCII字符串和宽字符串 ASCII字符构造 char*str1="abc"; 打印ASCII字符串 char*string="hello"; KdPrint("%s\n",string);\\注意是小写%s ///// UNICODE字符构造 wchar_t*str2=L"abc"; 打印宽字符串 WCHAR*string=L"hello"; KdPrint("%S\n",string);\\注意是大写%S /////////////////////////////////////////////////////////////////////////////// ANSI_STRING字符串和UNICODE_STRING字符串 ASCII字符串进行了封装 typedef struct_STRING{ USHORT Length;//字符的长度。 USHORT MaximumLength;//整个字符串缓冲区的最大长度。 PCHAR Buffer;//缓冲区的指针。 }STRING; 输出字符串 ANSI_STRING ansiString; KdPrint("%Z\n",&ansiString);//注意是%Z UNICODE_STRING宽字符串封装 typedef struct_UNICODE_STRING{ USHORT Length;//字符的长度,单位是字节。如果是N个字符,那么Length等于N的2倍。USHORT MaximumLength;//整个字符串缓冲区的最大长度,单位也是字节。 PWSTR Buffer;//缓冲区的指针。 }UNICODE_STRING*PUNICODE_STRING; 输出字符串 UNICODE_STRING ansiString; KdPrint("%wZ\n",&ansiString);//注意是%wZ ///////////////////////////////////////////////////////////////////////////////

Windows7+WDK+VS2010+VisualDDK驱动开发环境搭建

[置顶]Windows7+WDK+VS2010+VisualDDK驱动开发环境搭建(菜鸟的经验) 分类:驱动开发2011-08-12 23:30 863人阅读评论(3) 收藏举报 自己在研究驱动开发,第一步就是开发环境的搭建,网上已有很多的教程一,我也是按着教程一步一步搭建的,但在搭建过程的过程当中遇到一些问题,也花了我不少时间。 第一个难题就是,我是Windows7+VS2010+WDK的开发环境。 首先我参考了网上的一篇文章:https://www.doczj.com/doc/1c13597342.html,/guojingjia2006/archive/2011/03/19/142211.html WINDOWS 7 配置驱动开发环境(wdk7.60) 1. 安装VS2010,WDK7.60 (GRMWDK_EN_7600_1) 2. 新建VC 控制台项目(选择为空项目)

3. 新建项目配置“driver” ,点击下拉按钮-点击(配置管理器) 输入名称(driver)点击确定就可以了,其他的不要动哦!

完成后的效果! 点击确定按钮之后呈现出来的画面

鼠标右击新建的driver属性,会弹出以下窗口! 4. 设置VC++路径 <我把wdk安装在E盘下> a. 配置可执行文件目 录:E:\WinDDK\7600.16385.1\bin\x86;

b. 配置包含目录: E:\WinDDK\7600.16385.1\inc\ddk E:\WinDDK\7600.16385.1\inc\ E:\WinDDK\7600.16385.1\inc\api c. 配置库目 录: E:\WinDDK\7600.16385.1\lib\win7\i3865 新建C/C++文件不然无C/C++设置选项 <刚开始我们创建了一个空的项目所以项目里没有 c++文件,现在要做的就是在空的项目-源文件-添加一个新建项c++文件> 常规 目标文件扩展名:.sys //必选 6. 设置C/C++选项 常规选项卡 1 调试信息格式(C7 兼容(/Z7) //可选 2 警告等级(2 级(/W2) //可选 3 将警告视为错误(是(/wx) //可选

学习笔记windows驱动开发技术详解

<学习笔记>Windows驱动开发技术详解 派遣函数是Windows驱动程序中的重要概念。驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的。 用户模式下所有对驱动程序的I/O请求,全部由操作系统转换为一个叫做IRP数据结构,不同的IRP会被“派遣”到不同的派遣函数中。IRP与派遣函数 IRP的处理机制类似于Windows应用程序中的“消息处理”,驱动程序接收到不同的IRP后,会进入不同的派遣函数,在派遣函数中IRP得到处理。1.IRP 在Windows内核中,有一种数据结构叫做IRP(I/O Request Package),即输入输出请求包。上层应用程序与底层驱动程序通信时,应用程序会发出I/O请求。操作系统将I/O请求转化为相应的IRP数据,不同类型的IRP会被传递到不同的派遣函数中。 IRP有两个基本的重要属性,一个是MajorFunction,另一个MinorFunction,分别记录IRP的主类型和子类型,操作系统根据MajorFunction将IRP“派遣”到不同的派遣函数中,在派遣函数中还可以继续判断这个IRP属于哪种MinorFunction。 下面是HelloDDK的DriverEntry中关于派遣函数的注册:

view plaincopy to clipboardprint? #pragma INITCODE extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegisterPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry\n")); //设置卸载函数 pDriverObject->DriverUnload = HelloDDKUnload; //设置派遣函数 pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;

基于WINDOWSDDK的USB键盘驱动开发

基于WINDOWSDDK的USB键盘驱动开发 【摘要】USB接口具有方便快速等优点,已经发展成为一种比较普遍的计算机与外设的接口。基于微软windows系统DDK,本文介绍了一种非标准USB 键盘的windows设备驱动程序的开发过程与方法。 【关键词】设备驱动;驱动开发包;非标准键盘 1.引言 USB总线的成功关键是使用户感到了使用USB设备的方便。即插即用(PnP)概念的使用使某些硬件的安装过程得到了简化。USB规范中指出,适合迁移到USB1.1上的硬件限定于那些低速到中速的外设,包括键盘,鼠标等。即这些设备的数据传输速率低于12Mb/sec,并且能通过单一的PC接口被系统软件识别。现在标准的usb键盘设备只需要遵循一些hid设备的协议就可以被windows操作系统自动识别无需设备制造商开发驱动程序,但有些键盘带有特殊功能,所以需要设备驱动程序。 https://www.doczj.com/doc/1c13597342.html,b软件系统简介 USB设备对于USB系统来说是一个端点的集合,端点被分成组,一组端点实现一个接口,如图1所示。设备端点和主机软件之间利用管道进行数据交互。设备驱动程序就是通过这些接口和管道与设备进行通信的。 USB数据传输就是指发生在主机软件和USB设备上特定端点(endpoint)之间的数据交互,一个设备可以具有若干管道(pipe)。一般情况下,一个管道中数据传输与其他管道中的数据传输是相互独立的。这种发生在管道中的数据流动共有4种基本类型: (1)控制传输,一般发生在设备枚举阶段 (2)块传输,一般用于usb disk (3)中断传输,一般用于键盘鼠标类设备 (4)流传输,一般用于语音视频流设备 USB设备驱动程序都必须使用这些管道和接口来管理设备,而不是直接通过内存或I/O端口来存取来管理。 3.Windows驱动程序的工作原理 3.1 Windows驱动程序基本架构

Windows驱动学习笔记

版权声明 本书是免费的电子书,作者保留一切编辑、修改和发布的权利,在保证本书原文内容完整性(包括版权声明、作者简介、前言、正文内容、尾记)的前提下,欢迎读者以任何形式转载、复制本书,但务必不得将其用于赢利目的,否则将视为侵权行为进行追究。 本书(包括更新、勘误、技术支持)将在邪恶八进制社区(E.S.T)、泡面代码社区(iCoodle)以及作者博客同时发布,您可以在这三个站点进行下载、求助、讨论等操作,但请不要违反各论坛的有关规定。 邪恶八进制社区和泡面代码社区同时享有本书的任何处理权利。 作者简介 灰狐,又名grayfox、nokyo等,马甲众多,自2005年至2009年就读于成都信息工程学院,喜编程、擅灌水,以结识志同道合者为好,常混迹于各大BBS,潜水居多。 MSN:peiyaoqiang@https://www.doczj.com/doc/1c13597342.html, Gtalk:peiyaoqiang@https://www.doczj.com/doc/1c13597342.html, Email:peiyaoqiang@https://www.doczj.com/doc/1c13597342.html, QQ群:醉爱编程[iCoodle](群号:78298479) 个人主页:https://www.doczj.com/doc/1c13597342.html, 相关链接 灰狐's Blog:https://www.doczj.com/doc/1c13597342.html, Adly's Blog:https://www.doczj.com/doc/1c13597342.html, 泡面代码社区:https://www.doczj.com/doc/1c13597342.html, 邪恶八进制:https://www.doczj.com/doc/1c13597342.html, 关于iCoodle的一点说明 在您访问iCoodle的时候,可能还没有正式开放,因为我们苦于没有空间支持,免费的空间又总有这样那样的缺陷,希望能有好心的读者给予赞助一点服务器空间,我们只需要放置一个主页,发表原创性质的文章,仅需要您有Access数据库和支持ASP。 同时希望各位有心一起进步的会员加入到iCoodle来,我们共创一个灿烂的明天。

Windows文件系统过滤驱动开发教程

Windows文件系统过滤驱动开发教程 (转载) Windows文件系统过滤驱动开发教程 0. 作者,楚狂人自述 我长期网上为各位项目经理充当“技术实现者”的角色。我感觉Windows文件系统驱动的开发能找到的资料比较少。为了让技术经验不至于遗忘和引起大家交流的兴趣我以我的工作经验撰写本教程。 我的理解未必正确,有错误的地方望多多指教。有问题欢迎与我联系。我们也乐于接受各种驱动项目的开发。邮箱为MFC_Tan_Wen@https://www.doczj.com/doc/1c13597342.html,,QQ为16191935。 对于这本教程,您可以免费获得并随意修改,向任何网站转贴。但是不得剽窃任何内容作为任何赢利出版物的全部或者部分。 1. 概述,钻研目的和准备 我经常在网上碰到同行请求开发文件系统驱动。windows的pc机上以过滤驱动居多。其目的不外乎有以下几种: 一是用于防病毒引擎。希望在系统读写文件的时候,捕获读写的数据内容,然后检测其中是否含有病毒代码。 二是用于加密文件系统,希望在文件写过程中对数据进行加密,在读的过程中进行解密。 三是设计透明的文件系统加速。读写磁盘的时候,合适的cache算法是可以大大提高磁盘的工作效率。windows本身的cache算法未必适合一些特殊的读写 磁盘操作(如流媒体服务器上读流媒体文件)。设计自己的cache算法的效果,我已在工作中有所感受。 如果你刚好有以上此类的要求,你可以阅读本教程。 文件系统驱动是windows系统中最复杂的驱动种类之一。不能对ifsddk中的帮助抱太多希望,以我的经验看来,文件系统相关的ddk帮助极其简略,很多重要的部分仅仅轻描淡写的带过。如果安装了ifsddk,应该阅读srcfilesysOSR_docs 下的文档。而不仅仅是ddk帮助。 文件系统驱动开发方面的书籍很少。中文资料我仅仅见过侯捷翻译过的一本驱动

相关主题
文本预览
相关文档 最新文档