www.pudn.com > FsDriver.rar > HookDevice.cpp
/*++
Copyright (c) 2003 By LiGen
Module Name:
HookDevice.cpp
Abstract:
Environment:
kernel mode only
Notes:
See readme.txt
Revision History:
Author:
Li Gen
E-mail : 13574849558@hnmcc.com
--*/
#include "FsTPM.h"
VOID
FsTPMIoGetRelatedDeviceObject(
IN PFILE_OBJECT FileObject,
OUT PDEVICE_OBJECT *ppDeviceObject,
OUT PVPB *ppVpb
)
{
PDEVICE_OBJECT deviceObject = NULL;
PVPB pVpb = NULL;
//
// If the file object was taken out against the mounted file system, it
// will have a Vpb. Traverse it to get to the DeviceObject. Note that in
// this case we should never follow FileObject->DeviceObject, as that
// mapping may be invalid after a forced dismount.
//
if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) {
ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
deviceObject = FileObject->Vpb->DeviceObject;
pVpb = FileObject->Vpb;
//
// If a driver opened a disk device using direct device open and
// later on it uses IoGetRelatedTargetDeviceObject to find the
// device object it wants to send an IRP then it should not get the
// filesystem device object. This is so that if the device object is in the
// process of being mounted then vpb is not stable.
//
} else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
FileObject->DeviceObject->Vpb != NULL &&
FileObject->DeviceObject->Vpb->DeviceObject != NULL) {
deviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
pVpb = FileObject->DeviceObject->Vpb;
//
// This is a direct open against the device stack (and there is no mounted
// file system to strain the IRPs through).
//
} else {
deviceObject = FileObject->DeviceObject;
}
ASSERT( deviceObject != NULL );
if (deviceObject->AttachedDevice != NULL) {
deviceObject = IoGetAttachedDevice( deviceObject );
}
//
// Check to see whether or not the device has any associated devices.
// If so, return the highest level device; otherwise, return a pointer
// to the device object itself.
//
*ppDeviceObject = deviceObject;
*ppVpb = pVpb;
}
NTSTATUS
HookDevice(
IN ULONG DiskNum,
IN PDRIVER_OBJECT DriverObject
)
//++
// Function: HookDrive
//
// Description:
// 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.
//
// Arguments:
// DiskNum - 0 stand for Driver A, 1 stand for Driver B, ect.
// DriverObject - Passed from I/O Manager
//
// Return value:
// STATUS_SUCCESS if successful,
// STATUS_UNSUCCESSFUL otherwise
//--
{
IO_STATUS_BLOCK ioStatus;
HANDLE ntFileHandle;
OBJECT_ATTRIBUTES objectAttributes;
PDEVICE_OBJECT fileSysDevice;
PDEVICE_OBJECT hookDevice;
UNICODE_STRING fileNameUnicodeString;
// ULONG fileFsAttributesSize;
WCHAR filename[] = L"\\DosDevices\\A:\\";
NTSTATUS ntStatus;
ULONG i;
PFILE_OBJECT fileObject;
PHOOK_EXTENSION hookExtension;
PVPB pVpb;
//
// Is it a legal drive letter?
//
if( DiskNum >= 26 ) {
return STATUS_UNSUCCESSFUL;
}
//
// Has this drive already been hooked?
//
if( DriveHookDevices[DiskNum] == NULL ) {
//
// Frob the name to make it refer to the drive specified in the input
// parameter.
//
filename[12] = (WCHAR) ('A'+DiskNum);
//
// 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 ) ) {
FsTPM_DbgPrint(("FsTPM: Could not open drive %c: %x\n", 'A'+DiskNum, ntStatus ));
return ntStatus;
}
FsTPM_DbgPrint(("FsTPM: 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, (void**)&fileObject, NULL );
if( !NT_SUCCESS( ntStatus )) {
FsTPM_DbgPrint(("FsTPM: Could not get fileobject from handle: %c. I have added some codes: '(void**)'\n", 'A'+DiskNum ));
ZwClose( ntFileHandle );
return ntStatus;
}
//
// Next, find out what device is associated with the file object by getting its related
// device object
//
FsTPMIoGetRelatedDeviceObject( fileObject, &fileSysDevice, &pVpb);
if( ! fileSysDevice ) {
FsTPM_DbgPrint(("FsTPM: Could not get related device object: %c\n", 'A'+DiskNum ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return STATUS_UNSUCCESSFUL;
}
//
// 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[ DiskNum ] = fileSysDevice;
FsTPM_DbgPrint(("DiskNum %c has already been hooked.\n",'A'+DiskNum));
return STATUS_SUCCESS;
}
}
//
// 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) ) {
FsTPM_DbgPrint(("FsTPM: failed to create associated device: %c\n", 'A'+DiskNum ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return STATUS_UNSUCCESSFUL;
}
//
// 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;
if ( fileSysDevice->Flags & DO_BUFFERED_IO ) {
hookDevice->Flags |= DO_BUFFERED_IO;
}
if ( fileSysDevice->Flags & DO_DIRECT_IO ) {
hookDevice->Flags |= DO_DIRECT_IO;
}
//
// Finally, attach to the device. The second we're successfully attached, we may
// start receiving IRPs targetted at the device we've hooked.
//
PDEVICE_OBJECT Ret;
Ret = IoAttachDeviceToDeviceStack( hookDevice, fileSysDevice );
//
// Setup the device extensions. The drive letter and file system object are stored
// in the extension.
//
hookExtension = (PHOOK_EXTENSION)hookDevice->DeviceExtension;
hookExtension->LogicalDrive = 'A'+(unsigned char)DiskNum;
hookExtension->Vcb.RealDevice = fileSysDevice; // 要作修改 , 应该是 VPB->REALDEVICE
hookExtension->Vcb.pVpb = pVpb;
hookExtension->Vcb.NextLowerDevice = Ret;
hookExtension->Hooked = TRUE;
hookExtension->Type = STANDARD;
hookExtension->thisDriver = FsTPMDriverObject;
FsTPM_DbgPrint(("%c: the AttachDevice = 0x%x NextLowerDeviceObject = 0x%x Vpb.RealDevice = 0x%x Vpb.DeviceObject = 0x%x \n ",'A'+(unsigned char)DiskNum,fileSysDevice, Ret, pVpb->RealDevice, pVpb->DeviceObject ));
if( NULL==Ret ) {
//
// Couldn' attach for some reason
//
FsTPM_DbgPrint(("FsTPM: Connect with Filesystem failed: %c (%x) =>%x\n",
'A'+DiskNum, fileSysDevice, ntStatus ));
//
// Derefence the object and get out
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return ntStatus;
} else {
//
// Make a new drive group for the device,l if it does not have one
// already
//
FsTPM_DbgPrint(("FsTPM: Successfully connected to Filesystem device %c\n", 'A'+DiskNum ));
}
//
// Determine if this is a NTFS drive
//
// fileFsAttributesSize = sizeof( FILE_FS_ATTRIBUTE_INFORMATION) + MAXPATHLEN;
// hookExtension->FsAttributes = (PFILE_FS_ATTRIBUTE_INFORMATION) ExAllocatePoolWithTag( NonPagedPool,
// fileFsAttributesSize,TAGS );
// 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[DiskNum] = hookDevice;
} else {
hookExtension = (PHOOK_EXTENSION)DriveHookDevices[DiskNum]->DeviceExtension;
hookExtension->Hooked = TRUE;
}
return STATUS_SUCCESS;
}
VOID
UnhookDevice(
IN ULONG DiskNum
)
//++
// Function: UnhookDevice
//
// Description:
// Unhook a previously hooked driver.
//
// Arguments:
// DiskNum - 0 stand for Driver A, 1 stand for Driver B, ect.
//
// Return value:
// None
//
// Notice :
// this function is just to change the value of "extension->hook"
// if you want to unload & detach a hooked device , please see: UnlockDetach()
//--
{
PHOOK_EXTENSION hookExt;
//
// If the driver has been hooked, unhook it and delete the hook
// device object
//
if( DriveHookDevices[DiskNum] ) {
hookExt =(PHOOK_EXTENSION)DriveHookDevices[DiskNum]->DeviceExtension;
hookExt->Hooked = FALSE;
}
}
VOID
UnloadDetach(
VOID
)
//++
// Function: UnloadDetach
//
// Description:
// Detaches from all devices for an unload
//
// Arguments:
// None
//
// Return value:
// None
//
// Notice :
// This function is used to unload a hooked device.
// Unloading the filter driver is dangerous.
// You can use this function in Debug Mode.
//--
{
ULONG drive, i;
PDEVICE_OBJECT device;
PHOOK_EXTENSION hookExt;
//
// Detach from file system devices
//
for( drive = 0; drive < 26; drive++ ) {
if( DriveHookDevices[drive] ) {
FsTPM_DbgPrint(("Unload %c:",'A'+drive));
device = DriveHookDevices[drive];
hookExt = (PHOOK_EXTENSION)device->DeviceExtension;
IoDetachDevice( hookExt->Vcb.RealDevice );
IoDeleteDevice( device );
for( i =0; i < 26; i++ ) {
if( DriveHookDevices[i] == device ) {
DriveHookDevices[i] = NULL;
}
}
}
}
}
ULONG
HookDeviceSet(
IN ULONG DriveSet,
IN PDRIVER_OBJECT DriverObject
)
//++
// Function: HookDriveSet
//
// Description:
// Hook/Unhook a set of drives specified by user. Return the set
// that is currently hooked.
//
// Arguments:
// DriveSet - A bitmask.If you want to hook Driver C, do it like this: DriveSet | (1<<2)
// DriverObject - Passed from I/O Manager
//
// Return value:
// Return set of drives currently hooked
//--
{
// PHOOK_EXTENSION hookExt; not being used
ULONG drive, i;
ULONG bit;
//
// Scan the drive table, looking for hits on the DriveSet bitmask
//
for ( drive = 0; drive < 26; ++drive ) {
bit = 1 << drive;
//
// Are we supposed to hook this drive?
//
if( (bit & DriveSet) &&
!(bit & CurrentDriveSet) ) {
//
// Try to hook drive
//
if( !HookDevice( drive, DriverObject ) ) {
//
// Remove from drive set if can't be hooked
//
DriveSet &= ~bit;
} else {
//
// hook drives in same drive group
//
for( i = 0; i < 26; i++ ) {
if( DriveHookDevices[i] == DriveHookDevices[ drive ] ) {
DriveSet |= ( 1<