驱动对象和设备对象

驱动对象与设备对象

DRIVER_OBJECTDEVICE_OBJECT的关系

DRIVER_OBJECT是驱动程序在内核中的数据结构,每个驱动程序有唯一DRIVER_OBJECTIO管理器使用驱动程序对象代表每个设备驱动程序,驱动程序描述了驱动程序的载入到内存什么地方,驱动程序的大小和它的主要入口点(MajorFunction数组);驱动程序对象有一个DeviceObject域指向一个设备对象链表,每个设备对象代表一个设备。
DEVICE_OBJECT是物理设备或逻辑设备在内核中的数据结构,跟这个概念相关的有PDOFDOPDO对应于具体的硬件设备,每个硬件设备对应一个PDO,而一个PDO可以对应多个FDOPDOFDO都是DEVICE_OBJECT的实体;同一个设备驱动程序对象下的所有设备通过NextObject域连接成一个链表(即上述驱动程序设备对象的一个域);AttachedDevice域是针对早期驱动的(Window NT4以前的版本,在以后的版本中也可以正常使用);DriverObject域指向与该设备相关的驱动程序对象。


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

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

DriverObject就是你所写的驱动对应的DRIVER_OBJECT, 是系统在加载你的驱动时候所分配的
RegisteryPath专用于你记录你的驱动相关参数的注册表路径这两者都由系统分配并通过这两个参数传递给你

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

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

设备对象则是指DEVICE_OBJECT.下边简称DO.
但是实际上每个irp都是针对DO发出的。只有针对由该驱动所生成的DOIRP, 才会发给该驱动来处理。具体的分发函数,决定于DO下的DriverObject域。

当一个应用程序打开文件并读写文件的时候,windows 系统将这些请求变成irp 发送给文件系统驱动文件系统过滤驱动可以过滤这些irp.这样,你就拥有了捕获和改变文件系统操作能力
Fat32,NTFS这样的文件系统(File System,简称FS),可能生成好几种设备。首先文件系统驱动本身往往生成一个控制设备(CDO.这个设备的主要任务是修改整个驱动的内部配置。因此一个Driver对应一个CDO.
另一种设备是被这个文件系统Mount Volume。一个FS可能有多个Volume,可能一个都没有。解释一下,如果你有C:,D:,E:,F:四个分区。C:,D:NTFS,E:,F:Fat32.那么E:,F:则是Fat 的两个Volume设备对象.实际上"C:"是该设备的符号连接(Symbolic Link)名而不是真正的设备名可以打开Symbolic Links Viewer,能看到:

C:\Device\HarddiskVolume1
因此该设备的设备名为“\Device\HarddiskVolume1”.
这里也看出来,文件系统驱动是针对每个Volume 来生成一个DeviceObject,而不是针对每个文件的。实际上对文件的读写的irp,发到Volume设备对象上去了。并不会生成一个文件设备对象。掌握了这些概念的话,我们现在用简单的代码来生成我们的CDO,作为我们开发文件系统驱动的第一步牛刀小试。

NTSTATUS
DriverEntry(
INPDRIVER_OBJECT
DriverObject,
INPUNICODE_STRING
RegistryPath
)
{
// 定义一个Unicode 字符串。

UNICODE_STRING nameString;
RtlInitUnicodeString
( &nameString,L"\\FileSystem\\Filters\\SFilter" );

// 生成控制设备

status = IoCreateDevice( DriverObject,
0,
//has no device extension

&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN,

FALSE,
&gSFilterControlDeviceObject );

// 如果因为路径没找到而生成失败
if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
// 这是因为一些低版本的操作系统没有\FileSystem\Filters\这个目录


//
如果没有,我们则改变位置,生成到\FileSystem\.
RtlInitUnicodeString
( &nameString,L"\\FileSystem\\SFilterCDO" );

status =
IoCreateDevice
( DriverObject,
0,&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM
,
FILE_DEVICE_SECURE_OPEN
,
FALSE,
&gSFilterControlDeviceObject );

// 成功后,用KdPrint 打印一个log.

if (!NT_SUCCESS( status )) {
KdPrint
(( "SFilter!DriverEntry: Errorcreating control device object \"%wZ\",
status=%08x\n", &nameString, status ));
return
status;
}
}
else if (!NT_SUCCESS(
status )) {
// 失败也打印一个。并直接返回错误

KdPrint(( "SFilter!DriverEntry: Errorcreating control device object \"%wZ\",
status=%08x\n", &nameString, status ));
}
return
status;
}
sfilter.sys.
把这个文件与前所描述的inf 文件同一目录,按上节所叙述方法安装。

这个驱动不起任何作用,但是你已经成功的完成了"helloworld".
初次看这些代码可能有一些慌乱。但是只要注意了以下几点,你就会变得轻松了
:

1
习惯使用UNICODE_STRING 字符串。这些字符串用Rtl…系列的函数来操作。你应该阅读DDK 帮助,然后熟悉这些字符串的用法。

2KdPrint(())来代替printf 输出信息。这些信息可以在DbgView 中看到。KdPrint(())自身是一个宏,为了完整传入参数所以使用了两重括弧。这个比DbgPrint 调用要稍好。因为在free 版不被编译。

3查看DDK 帮助了解生成设备对象IoCreateDevice 的用法。
请注意CDO 生成后,保存在gSFilterControlDeviceObject 中。这样以后我们得到一个DEVICE_OBJECT 时,
就很容易判断是否是我们的控制设备。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值