过滤驱动容易让新手纠结的几个函数

来源:互联网 发布:seo综合查询5118 编辑:程序博客网 时间:2024/06/05 04:07

1. IoAttachDevice

[cpp] view plaincopyprint?
  1. NTSTATUS  
  2. IoAttachDevice( 
  3.      IN PDEVICE_OBJECT SourceDevice, 
  4. IN PUNICODE_STRING TargetDevice,
  5.      OUT PDEVICE_OBJECT *AttachedDevice 
  6. ); 

将【指定指针】的设备对象附加到【指定名称】的设备对象所在的【设备对象栈】顶层,并返回【附加之前的栈顶设备对象指针】。


2. IoAttachDeviceToDeviceStack
  
[cpp] view plaincopyprint?
  1. PDEVICE_OBJECT  
  2. IoAttachDeviceToDeviceStack( 
  3.      IN PDEVICE_OBJECT SourceDevice, 
  4.      IN PDEVICE_OBJECT TargetDevice 
  5. ); 

将【指定指针】的设备对象附加到【指定指针】的设备对象所在的【设备对象栈】顶层,并返回【附加之前的栈顶设备对象指针】。

3. IoGetDeviceObjectPointer
  
[cpp] view plaincopyprint?
  1. NTSTATUS  
  2. IoGetDeviceObjectPointer( 
  3.       IN PUNICODE_STRING ObjectName, 
  4.       IN ACCESS_MASK DesiredAccess, 
  5.       OUT PFILE_OBJECT *FileObject, 
  6.       OUT PDEVICE_OBJECT *DeviceObject 
  7. ); 

通过【设备对象的名字】,打开【文件对象】,根据返回的【文件句柄】获取【文件对象指针】,并根据【文件对象指针】得到该【文件对象的设备指针】。

它的源代码:


[cpp] view plaincopyprint?
  1. NTSTATUS 
  2. IoGetDeviceObjectPointer( 
  3.                          IN PUNICODE_STRING ObjectName, 
  4.                          IN ACCESS_MASK DesiredAccess, 
  5.                          OUT PFILE_OBJECT *FileObject, 
  6.                          OUT PDEVICE_OBJECT *DeviceObject 
  7.                          ) 
  8.     PFILE_OBJECT fileObject; 
  9.     OBJECT_ATTRIBUTES objectAttributes; 
  10.     HANDLE fileHandle; 
  11.     IO_STATUS_BLOCK ioStatus; 
  12.     NTSTATUS status; 
  13.  
  14.     PAGED_CODE(); 
  15.  
  16.     // 
  17.     // Initialize the object attributes to open the device. 
  18.     // 
  19.  
  20.     InitializeObjectAttributes( &objectAttributes, 
  21.         ObjectName, 
  22.         OBJ_KERNEL_HANDLE, 
  23.         (HANDLE) NULL, 
  24.         (PSECURITY_DESCRIPTOR) NULL ); 
  25.  
  26.     status = ZwOpenFile( &fileHandle, 
  27.         DesiredAccess, 
  28.         &objectAttributes, 
  29.         &ioStatus, 
  30.         0, 
  31.         FILE_NON_DIRECTORY_FILE ); 
  32.  
  33.     if (NT_SUCCESS( status )) { 
  34.  
  35.         // 
  36.         // The open operation was successful. Dereference the file handle 
  37.         // and obtain a pointer to the device object for the handle. 
  38.         // 
  39.  
  40.         status = ObReferenceObjectByHandle( fileHandle, 
  41.             0, 
  42.             IoFileObjectType, 
  43.             KernelMode, 
  44.             (PVOID *) &fileObject, 
  45.             NULL ); 
  46.         if (NT_SUCCESS( status )) { 
  47.  
  48.             *FileObject = fileObject; 
  49.  
  50.             // 
  51.             // Get a pointer to the device object for this file. 
  52.             // 
  53.             *DeviceObject = IoGetRelatedDeviceObject( fileObject ); 
  54.         } 
  55.         (VOID) ZwClose( fileHandle ); 
  56.     } 
  57.     return status; 

注意:
    (1) IoGetDeviceObjectPointer函数中 ObReferenceObjectByHandle增加了其所对应的文件对象的引用,因此该函数调用后,调用ObDereferenceObject减小引用计数。 
    (2) IoGetDeviceObjectPointer函数中 IoGetRelatedDeviceObject的调用是里面的重点。 看IoGetRelatedDeviceObject的说明,就能理解这个函数参数3,参数4的关系。

特别注意:
     WDK文档里面特别强调了以下信息
            The IoGetDeviceObjectPointer routine returns a pointer to the top object in the named device object's stack and a pointer to the corresponding file object
       这里,就是大家经常有疑惑的参数3和4(DeviceObject和FileObject->DeviceObject)问题的答案了

      (1) DeviceObject 返回的是【Attach】在这个【有名设备对象】所在【栈】的【栈顶设备对象指针】,如果没有Attach的设备,就是【有名设备对象指针】了。
      (2) FileObject->DeviceObject 返回的是【有名设备对象指针】:
             如果是文件系统,还需要考虑到Vpb的问题,具体信息可以参考下面IoGetRelatedDeviceObject的实现。
(a) 在DEVICE_OBJECT和FILE_OBJECT结构中都存在Vpb字段,它是文件对象与相应磁盘卷设备直接的桥梁,一般Vpb中的RealDevice就指向了该对象的相应磁盘卷(块)设备,而vpb中的DeviceObject指向的是文件系统卷设备。比如将C盘下一个文件的FileObject传递给IoGetBaseFileSystemDeviceObject,那么若c盘是ntfs分区的,得到的文件系统卷设备DEVICE_OBJECT所属的驱动对象DRIVER_OBJECT就是\FileSystem\Ntfs;如果把该FileOjbect传递给IoGetRelatedDeviceObject,那么得到的deviceobject是附加在这个文件系统卷设备所在设备栈的顶层设备。

(b) 如果文件系统没有挂接,返回的是【磁盘系统卷设备】,否则返回的是【文件系统卷设备】.
(c) 如果文件系统已经挂接,返回的是【文件系统卷设备】

4. IoGetRelatedDeviceObject
 
[cpp] view plaincopyprint?
  1. PDEVICE_OBJECT  
  2. IoGetRelatedDeviceObject( 
  3.      IN PFILE_OBJECT FileObject 
  4. ); 

通过文件对象指针,使用它的Vpb域,获取对应的设备对象所在设备栈顶层的设备对象指针(文件和设备的关联关系)

它的实现如下:


[cpp] view plaincopyprint?
  1. PDEVICE_OBJECT 
  2. IoGetRelatedDeviceObject( 
  3.              IN PFILE_OBJECT FileObject 
  4.                          ) 
  5.     PDEVICE_OBJECT deviceObject; 
  6.  
  7.     // 
  8.     // If the file object was taken out against the mounted file system, it 
  9.     // will have a Vpb. Traverse it to get to the DeviceObject. Note that in 
  10.     // this case we should never follow FileObject->DeviceObject, as that 
  11.     // mapping may be invalid after a forced dismount. 
  12.     // 
  13.  
  14.     if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) { 
  15.  
  16.         ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 
  17.         deviceObject = FileObject->Vpb->DeviceObject; 
  18.  
  19.  
  20.         // 
  21.         // If a driver opened a disk device using direct device open and 
  22.         // later on it uses IoGetRelatedTargetDeviceObject to find the 
  23.         // device object it wants to send an IRP then it should not get the 
  24.         // filesystem device object. This is so that if the device object is in the 
  25.         // process of being mounted then vpb is not stable. 
  26.         // 
  27.  
  28.     } elseif (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 
  29.         FileObject->DeviceObject->Vpb != NULL && 
  30.         FileObject->DeviceObject->Vpb->DeviceObject != NULL) { 
  31.  
  32.             deviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 
  33.  
  34.             // 
  35.             // This is a direct open against the device stack (and there is no mounted 
  36.             // file system to strain the IRPs through). 
  37.             // 
  38.  
  39.     } else
  40.  
  41.         deviceObject = FileObject->DeviceObject; 
  42.     } 
  43.  
  44.     ASSERT( deviceObject != NULL ); 
  45.  
  46.     // 
  47.     // Check to see whether or not the device has any associated devices. 
  48.     // If so, return the highest level device; otherwise, return a pointer 
  49.     // to the device object itself. 
  50.     // 
  51.  
  52.     if (deviceObject->AttachedDevice != NULL) { 
  53.         if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) { 
  54.  
  55.             PIOP_FILE_OBJECT_EXTENSION fileObjectExtension = 
  56.                 (PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1); 
  57.  
  58.             ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 
  59.  
  60.             if (fileObjectExtension->TopDeviceObjectHint != NULL && 
  61.                 IopVerifyDeviceObjectOnStack(deviceObject, fileObjectExtension->TopDeviceObjectHint)) { 
  62.                     return fileObjectExtension->TopDeviceObjectHint; 
  63.             } 
  64.         } 
  65.         deviceObject = IoGetAttachedDevice( deviceObject ); 
  66.     } 
  67.  
  68.     return deviceObject; 

5. IoGetBaseFileSystemDeviceObject 得到与文件对象相关的卷设备对象(是由文件系统在打开卷时创建的).
   
[cpp] view plaincopyprint?
  1. PDEVICE_OBJECT IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject) 
  2.     PDEVICE_OBJECT deviceObject; 
  3.     // If the file object has a mounted Vpb, use its DeviceObject. 
  4.     if(FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) 
  5.     { 
  6.         deviceObject = FileObject->Vpb->DeviceObject; 
  7.         // Otherwise, if the real device has a VPB that indicates that it is mounted, 
  8.         // then use the file system device object associated with the VPB. 
  9.     } 
  10.     elseif(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 
  11.         FileObject->DeviceObject->Vpb != NULL && 
  12.         FileObject->DeviceObject->Vpb->DeviceObject != NULL ) 
  13.     { 
  14.         deviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 
  15.         // Otherwise, just return the real device object. 
  16.     } 
  17.     else 
  18.     { 
  19.         deviceObject = FileObject->DeviceObject; 
  20.     } 
  21.     ASSERT(deviceObject != NULL); 
  22.     // Simply return the resultant file object. 
  23.     return deviceObject; 

6. ObReferenceObjectByName
(1)ObReferenceObjectByName 可以返回任意对象地址。它的本质是使用ObpLookupObjectName对 “\A\B\C”逐级解析。
(2)IoGetDeviceObjectPointer 只能返回设备对象地址。它的本质是调用ZwOpenFile得到设备句柄,然后调用ObReferenceObjectByHandle得到设备对应的文件对象指针,再调用IoGetRelatedDeviceObject根据文件对象指针得到设备对象指针。