Windows文件系统过滤驱动开发教程Word文档格式.docx
- 文档编号:18693479
- 上传时间:2022-12-31
- 格式:DOCX
- 页数:51
- 大小:53.28KB
Windows文件系统过滤驱动开发教程Word文档格式.docx
《Windows文件系统过滤驱动开发教程Word文档格式.docx》由会员分享,可在线阅读,更多相关《Windows文件系统过滤驱动开发教程Word文档格式.docx(51页珍藏版)》请在冰豆网上搜索。
ifsddk可以在某些ftp上免费下载。
我的使用的是ifs
ddk
for
xp,但是我实际用来开发的两台机器有一台是windows
2000,另一台是windows
2003.我尽量使我编译出来的驱动,可以在2000\xp\2003三种系统上都通过测试。
安装配置ddk和在vc中开发驱动的方法网上有很多的介绍。
ifsddk安装之后,src目录下的filesys目录下有文件系统驱动的示例。
阅读这些代码你就可以快速的学会文件系统驱动开发。
filter目录下的sfilter是一个文件系统过滤驱动的例子。
另一个filespy完全是用这个例子的代码加工得更复杂而已。
如何用ddk编译这个例子请自己查看相关的资料。
文件系统过滤驱动编译出来后你得到的是一个扩展名为sys的文件。
同时你需要写一个.inf文件来实现这个驱动的安装。
我这里不讨论.inf文件的细节,你可以直接用sfilter目录下的inf文件修改。
对inf文件点鼠标右键弹出菜单选择“安装”,即可安装这个过滤驱动。
但是必须重新启动系统才生效。
如果重启后蓝屏无法启动,可以用其他方式引导系统后到system32\drivers目录下删除你的.sys文件再重启即可。
我尝试这种情况下用安全模式结果还
是蓝屏。
所以我后来不得不在机器上装了两个2000系统。
双系统情况下,一个系统崩溃了用另一个系统启动,删除原来的驱动即可。
如果要调试代码,请安装softice.
打开sfilter目录下的文件sources(这个文件没有扩展名),加入一行
BROWSER_INFO=1
然后打开Symbol
Loader,File->
Open选中你编译出来的xxx.sys,Modul->
Load,Modul->
Translate,然后就可以调试了。
打开softice,输入file
*就可以看见代码。
如果准备好了,我们就可以开始琢磨windows文件系统过滤驱动的开发了。
2.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的Volume。
一个FS可能有多个Volume,也可能一个都没有。
解释一下,如果你有C:
D:
E:
F:
四个分区。
C:
为NTFS,E:
为Fat32。
那么C:
,D:
则是Fat的两个Volume设备对象。
实际上"
"
是该设备的符号连接(Symbolic
Link)名。
而不是真正的设备名。
可以打开Symbolic
Links
Viewer,能看到:
DeviceHarddiskVolume1
因此该设备的设备名为“DeviceHarddiskVolume1”.
这里也看出来,文件系统驱动是针对每个Volume来生成一个DeviceObject,而不是针对每个文件的。
实际上对文件的读写的irp,都发到Volume设备对象上去了。
并不会生成一个“文件设备对象”。
掌握了这些概念的话,我们现在用简单的代码来生成我们的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,
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_main(in
wd_drv*
driver,
wd_ustr*
reg_path)
name;
status
=
wd_stat_suc;
然后我生成控制设备,虽然现在我的控制设备什么都不干
wd_ustr_init(&
name,L"
\FileSystem\Filters\our_fs_filter"
);
wdff_cdo_create(driver,0,&
name,&
g_cdo);
if(!
wd_suc(status))
if(status
==
wd_stat_path_not_found)
这种情况发生于FileSystemFilters路径不存在。
这个路径是
在xp上才加上的。
所以2000下会运行到这里
\FileSystem\our_fs_filter"
};
wd_printf0("
error:
create
cdo
failed.rn"
status;
}
success:
ok.rn"
为了让代码看起来象上边的那样,我不得不做了很多转换。
如
#define
DriverEntry
wd_main
一种爽的感觉,终于可以在写看起来更象是main()的函数中工作了。
wd_dev_create
这个函数内部调用的是IoCreateDevice.而wd_suc实际上是SUCCESS()这样的宏。
----------------------wdf.h中的内容------------------------------
ntifs.h"
IN
OUT
optional
OPTIONAL
UNICODE_STRING
wdp_ustr
PUNICODE_STRING
wd_main
DriverEntry
设备、驱动对象类型
typedef
DRIVER_OBJECT
wd_drv;
DEVICE_OBJECT
wd_dev;
wd_pdrv;
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
状态相关的类型和宏
wd_stat;
wd_stat_suc
STATUS_SUCCESS,
wd_stat_path_not_found
STATUS_OBJECT_PATH_NOT_FOUND,
wd_stat_insufficient_res
STATUS_INSUFFICIENT_RESOURCES,
wd_stat_invalid_dev_req
STATUS_INVALID_DEVICE_REQUEST,
wd_stat_no_such_dev
STATUS_NO_SUCH_DEVICE,
wd_stat_image_already_loaded
STATUS_IMAGE_ALREADY_LOADED,
wd_stat_more_processing
STATUS_MORE_PROCESSING_REQUIRED,
wd_stat_pending
STATUS_PENDING
(inline的使用是有所限制的,inline
函数一般必须在头文件内,inline只适合函数体内代码简单的函数使用,不能包含复杂的结构控制语句例如while
switch,并且不能内联函数本身不能是直接递归函数(自己内部还调用自己的函数)。
)
_inline
wd_bool
wd_suc(wd_stat
state)
//内聯函數
NT_SUCCESS(state);
wd_printf0
DbgPrint
wd_void
wd_ustr_init(in
str,
const
wd_wchar*
chars)
RtlInitUnicodeString(str,chars);
wd_ustr_init_em(in
*str
in
wd_wchar
*chars,
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"
.
Windows文件系统过滤驱动开发教程
3.分发例程,fast
io
上一节仅仅生成了控制设备对象。
但是不要忘记,驱动开发的主要工作是撰写分发例程(dispatch
functions.).接上一接,我们已经知道自己的DriverObject保存在上文代码的driver中。
现在我写如下一个函数来指定一个默认的dispatch
function给它。
//-----------------wdf.h中的代码----------------------
PDRIVER_DISPATCH
wd_disp_fuc;
wd_drv_set_dispatch(in
wd_disp_fuc
disp)
{
i;
(i
0;
i
<
IRP_MJ_MAXIMUM_FUNCTION;
i++)
driver->
MajorFunction[i]
disp;
在前边的wd_main中,我只要加
wd_drv_set_dispatch(driver,my_dispatch_func);
就为这个驱动指定了一个默认的Dispatch
Function.所有的irp请求,都会被发送到这个函数。
但是,我可能不希望这个函数处理过于复杂,而希望把一些常见的请求独立出来,如Read,Write,Create,Close,那我又写了几个函数专门用来设置这几个Dispatch
Functions.
wd_drv_set_read(
read)
MajorFunction[IRP_MJ_READ]
read;
wd_drv_set_write(
write)
MajorFunction[IRP_MJ_WRITE]
write;
wd_drv_set_create(in
create)
MajorFunction[IRP_MJ_CREATE]
create;
MajorFunction[IRP_MJ_CREATE_NAMED_PIPE]
MajorFunction[IRP_MJ_CREATE_MAILSLOT]
wd_drv_set_file_sys_control(in
control)
MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL]
control;
wd_drv_set_clean_up(in
clean_up)
MajorFunction[IRP_MJ_CLEANUP]
clean_up;
wd_drv_set_close(in
close)
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.我不知道这个指针留空会不会导致系统崩溃。
在这里本来是没有空间的,所以为了保存这一组指针,你必须自己分配空间。
下面是我常用的内存分配函数。
最简单的分配内存的函数,可以指定分页非分页
wd_pvoid
wd_malloc(wd_bool
paged,wd_size
size)
if(paged)
ExAllocatePool(PagedPool,size);
else
ExAllocatePool(NonPagedPool,size);
释放内存
wd_free(wd_pvoid
point)
ExFreePool(point);
wd_memzero(
point,
RtlZeroMemory(point,size);
有了上边的基础,我就可以自己写一个初始化FastIoDispatch指针的函数。
wd_fio_disp_init(wd_drv
*driver,wd_ulong
wd_fio_disp
*disp
wd_malloc(wd_false,size);
if(disp
wd_null)
wd_false;
wd_memzero((wd_pvoid)disp,size);
FastIoDispatch
FastIoDispatch->
SizeOfFastIoDispatch
size;
wd_true;
这个函数为FastIoDispacth指针分配足够的空间并填写它的大小。
下面是再写一系列的函数来设置这个函数指针数组。
实际上,FastIo接口函数实在太多了,所以我仅仅写出这些设置函数的几个作为例子:
wd_fio_disp_set_query_standard(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Windows 文件系统 过滤 驱动 开发 教程