//----------------------------------------------------------------------
//
// HookDrive
//
// Hook the drive specified by determining which device object to
// attach to. The algorithm used here is similar to the one used
// internally by NT to determine which device object a file system request
// is directed at.
//
//----------------------------------------------------------------------
BOOLEAN
HookDrive(
IN ULONG Drive,
IN PDRIVER_OBJECT DriverObject
)
{
IO_STATUS_BLOCK ioStatus;
HANDLE ntFileHandle;
OBJECT_ATTRIBUTES objectAttributes;
PDEVICE_OBJECT fileSysDevice;
PDEVICE_OBJECT hookDevice;
UNICODE_STRING fileNameUnicodeString;
PFILE_FS_ATTRIBUTE_INFORMATION fileFsAttributes;
ULONG fileFsAttributesSize;
WCHAR filename[] = L"
\\DosDevices\\A:\\
";
NTSTATUS ntStatus;
ULONG i;
PFILE_OBJECT fileObject;
PHOOK_EXTENSION hookExtension;
//
// Is it a legal drive letter?
//
if( Drive >= 26 ) {
return FALSE;
}
//
// Has this drive already been hooked?
//
if( DriveHookDevices[Drive] == NULL ) {
//
// Frob the name to make it refer to the drive specified in the input
// parameter.
//
filename[12] = (CHAR) ('A'+Drive);
//
// We have to figure out what device to hook - first open the volume's
// root directory
//
RtlInitUnicodeString( &fileNameUnicodeString, filename );
InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString,
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: %x\n", 'A'+Drive, ntStatus ));
return FALSE;
}
DbgPrint(("Filemon: opened the root directory!!! handle: %x\n", ntFileHandle));
//
// 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", 'A'+Drive ));
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;
}
//
// Check the device list to see if we've already attached to this particular device.
// This can happen when more than one drive letter is being handled by the same network
// redirecter
//
for( i = 0; i < 26; i++ ) {
if( DriveHookDevices[i] == fileSysDevice ) {
//
// If we're already watching it, associate this drive letter
// with the others that are handled by the same network driver. This
// enables us to intelligently update the hooking menus when the user
// specifies that one of the group should not be watched -we mark all
// of the related drives as unwatched as well
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
DriveHookDevices[ Drive ] = fileSysDevice;
return TRUE;
}
}
//
// The file system's device hasn't been hooked already, so make a hooking device
// object that will be attached to it.
//
ntStatus = IoCreateDevice( DriverObject,
sizeof(HOOK_EXTENSION),
NULL,
fileSysDevice->DeviceType,
0,
FALSE,
&hookDevice );
if( !NT_SUCCESS(ntStatus) ) {
DbgPrint(("Filemon: failed to create associated device: %c\n", 'A'+Drive ));
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
//
hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Setup the device extensions. The drive letter and file system object are stored
// in the extension.
//
hookExtension = hookDevice->DeviceExtension;
hookExtension->LogicalDrive = 'A'+Drive;
hookExtension->FileSystem = fileSysDevice;
hookExtension->Hooked = TRUE;
hookExtension->Type = STANDARD;
//
// Finally, attach to the device. The second we're successfully attached, we may
// start receiving IRPs targetted at the device we've hooked.
//
ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );
if( !NT_SUCCESS(ntStatus) ) {
//
// Couldn' attach for some reason
//
DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x\n",
'A'+Drive, fileSysDevice, ntStatus ));
//
// Derefence the object and get out
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
} else {
//
// Make a new drive group for the device,l if it does not have one
// already
//
DbgPrint(("Filemon: Successfully connected to Filesystem device %c\n", 'A'+Drive ));
}
//
// Determine if this is a NTFS drive
//
fileFsAttributesSize = sizeof( FILE_FS_ATTRIBUTE_INFORMATION) + MAXPATHLEN;
hookExtension->FsAttributes = (PFILE_FS_ATTRIBUTE_INFORMATION) ExAllocatePool( NonPagedPool,
fileFsAttributesSize );
if( hookExtension->FsAttributes &&
!NT_SUCCESS( IoQueryVolumeInformation( fileObject, FileFsAttributeInformation,
fileFsAttributesSize, hookExtension->FsAttributes,
&fileFsAttributesSize ))) {
//
// On failure, we just don't have attributes for this file system
//
ExFreePool( hookExtension->FsAttributes );
hookExtension->FsAttributes = NULL;
}
//
// Close the file and update the hooked drive list by entering a
// pointer to the hook device object in it.
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
DriveHookDevices[Drive] = hookDevice;
} else {
hookExtension = DriveHookDevices[Drive]->DeviceExtension;
hookExtension->Hooked = TRUE;
}
return TRUE;
}
以上摘自FileMon源码,作者在获得要hook的设备的DeviceObject的时候用了以下方式:
ZwCreateFile——》ObReferenceObjectByHandle——》IoGetRelatedDeviceObject
另外,这个设备对象也可以直接用一个函数获得IoGetDeviceObjectPointer,该函数原型如下:
NTSTATUS
IoGetDeviceObjectPointer(
IN PUNICODE_STRING
ObjectName
,
IN ACCESS_MASK
DesiredAccess
,
OUT PFILE_OBJECT
*
FileObject
,
OUT PDEVICE_OBJECT
*
DeviceObject
);
直接由名字获得设备对象和文件对象,而该函数内部的实现方式combojiang大侠也给出过c的逆向代码如下:
逆向为c的代码:
NTSTATUS
IoGetDeviceObjectPointer(
IN PUNICODE_STRING ObjectName,
IN ACCESS_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject
)
{
IO_STATUS_BLOCK ioStatus;
OBJECT_ATTRIBUTES objectAttributes;
//额外定义出来的栈变量。由于C与汇编的游戏规则不同。
PFILE_OBJECT fileObject;
HANDLE fileHandle;
NTSTATUS status;
InitializeObjectAttributes( &objectAttributes,
ObjectName,
OBJ_KERNEL_HANDLE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL );
status = ZwOpenFile( &fileHandle,
DesiredAccess,
&objectAttributes,
&ioStatus,
0,
0x40 );
if (status >= 0)
{
status = ObReferenceObjectByHandle( fileHandle,
0,
IoFileObjectType,
0,
(PVOID *) &fileObject,
0 );
if (status >= 0)
{
*FileObject = fileObject;
*DeviceObject = IoGetRelatedDeviceObject( fileObject );
}
ZwClose( fileHandle );
}
return status;
}
与FileMon的源码使用的方法类似,所以FileMon源码里面应该可以用这个函数直接替代,但是原作者没有直接调用这个函数,不知道原因是什么,难道是写FileMon的时候还没提供这个函数,所以要自己来实现吗?