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<