我们平时看sfilter的时候,发现它一方面面面俱到,一方面弄乱了我们的脑子。特别是绑定卷的那一部分,到底是怎么实现的,总觉得七拐八拐,拐弯太多。能不能写一个比较简单的绑定函数?比如我指定只要过滤c盘,那么我只要绑定c盘就够了。我试着写了一个,本文介绍我的这部分代码。我定义了一个函数:
BOOLEAN Attach2C_Volume(PUNICODE_STRING nameString)
nameString指定了要绑定的卷名。如果要绑定c盘,则
nameString应是:
//DosDevices//C://。
InitializeObjectAttributes( &objectAttributes, &nameString,
OBJ_CASE_INSENSITIVE, NULL, NULL );
ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS,
&objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE,
NULL, 0 );
if( !NT_SUCCESS( ntStatus ) )
{
//DbgPrint(("Filemon: Could not open drive %c: /n", 'C'+0));
return FALSE;
}
// Got the file handle, so now look-up the file-object it refers to
//
ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,
NULL, KernelMode, &fileObject, NULL );
if( !NT_SUCCESS( ntStatus )) {
//DbgPrint(("Filemon: Could not get fileobject from handle: %c/n", 'C'));
ZwClose( ntFileHandle );
return FALSE;
}
//
// Next, find out what device is associated with the file object by getting its related
// device object
//
fileSysDevice = IoGetRelatedDeviceObject( fileObject );
if( ! fileSysDevice ) {
//DbgPrint(("Filemon: Could not get related device object: %c/n", 'A'+Drive ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
上面代码的作用是打开卷设备,保存在fileSysDevice中。我们来一步步地看它是怎么做的。我们知道,在应用层里面,CreateFile函数的作用不仅可以打开一个File,还可以打开管道,邮件槽,磁盘。这里的ZwCreateFile就是CreateFile在内核的实现,现在调用它打开磁盘并取得句柄ntFileHandle,通过这个句柄可以找到它所对应的文件对象。形象地来说明句柄和文件对象的关系吧,文件对象就象一只古董瓷瓶,珍贵易碎,而句柄则是一只细心包裹着这只瓷瓶的皮箱,保护着它。我们在介绍古董瓷瓶的时候,只是让别人知道,它正放在箱子里面,有图片在此请看云云。
好,找到文件对象的方法是ObReferenceObjectByHandle,调用它就可以了。继续调用IoGetRelatedDeviceObject,这个函数可以让你进一步通过文件对象获得设备对象,也就是C盘的设备对象,正是我们绑定的时候要用到的。对上面的这一个过程,请你记住就行了,不必特别的研究,他们之间的关系都是一顺的,好像通过爷爷找孙子一样,有既定的脉络关系。接下来:
ntStatus = IoCreateDevice( gSFilterDriverObject,
sizeof(SFILTER_DEVICE_EXTENSION),
NULL,
fileSysDevice->DeviceType,
0,
FALSE,
&VolumeDeviceObject );
if( !NT_SUCCESS(ntStatus) ) {
//DbgPrint(("Filemon: failed to create associated device: %c/n", 'A'+0 ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
// Clear the device's init flag as per NT DDK KB article on creating device
// objects from a dispatch routine
//
VolumeDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
这段代码用来创建一个新的设备对象,过会我就用它来绑定到刚才取得的c盘设备对象上去。之后要设置一下新设备对象的标志位,使它的初始化位为空。
现在,我们已把一切准备工作都完成啦。是不是很快?!最后的一步就是完成绑定,代码如下:
attachedObject = IoAttachDeviceToDeviceStack( VolumeDeviceObject, fileSysDevice );
if( NULL == attachedObject )
{
//DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x/n",
// 'C', fileSysDevice, (LONG)ntStatus ));
// Derefence the object and get out
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
//
// Setup the device extensions. The drive letter and file system object are stored
// in the extension.
//
sfExtention = VolumeDeviceObject->DeviceExtension;
sfExtention->AttachedToDeviceObject = attachedObject;//fileSysDevice;
最后还有一定后继的东西:
// Close the file and update the hooked drive list by entering a
// pointer to the hook device object in it.
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return TRUE;
结束了!代码真的很简洁。把
Attach2C_Volume
放在
DriverEntry
最后的结束的地方进行调用,如果你的程序没有别的问题的话,就能轻松的实现指定盘符的绑定了。