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

1. IoAttachDevice

NTSTATUS 
IoAttachDevice(
     IN PDEVICE_OBJECT SourceDevice,
     IN PUNICODE_STRING TargetDevice,
     OUT PDEVICE_OBJECT *AttachedDevice
);

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


2. IoAttachDeviceToDeviceStack
   
PDEVICE_OBJECT 
IoAttachDeviceToDeviceStack(
     IN PDEVICE_OBJECT SourceDevice,
     IN PDEVICE_OBJECT TargetDevice
);

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

3. IoGetDeviceObjectPointer
   
NTSTATUS 
IoGetDeviceObjectPointer(
      IN PUNICODE_STRING ObjectName,
      IN ACCESS_MASK DesiredAccess,
      OUT PFILE_OBJECT *FileObject,
      OUT PDEVICE_OBJECT *DeviceObject
);

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

它的源代码:


NTSTATUS
IoGetDeviceObjectPointer(
						 IN PUNICODE_STRING ObjectName,
						 IN ACCESS_MASK DesiredAccess,
						 OUT PFILE_OBJECT *FileObject,
						 OUT PDEVICE_OBJECT *DeviceObject
						 )
{
	PFILE_OBJECT fileObject;
	OBJECT_ATTRIBUTES objectAttributes;
	HANDLE fileHandle;
	IO_STATUS_BLOCK ioStatus;
	NTSTATUS status;

	PAGED_CODE();

	//
	// Initialize the object attributes to open the device.
	//

	InitializeObjectAttributes( &objectAttributes,
		ObjectName,
		OBJ_KERNEL_HANDLE,
		(HANDLE) NULL,
		(PSECURITY_DESCRIPTOR) NULL );

	status = ZwOpenFile( &fileHandle,
		DesiredAccess,
		&objectAttributes,
		&ioStatus,
		0,
		FILE_NON_DIRECTORY_FILE );

	if (NT_SUCCESS( status )) {

		//
		// The open operation was successful. Dereference the file handle
		// and obtain a pointer to the device object for the handle.
		//

		status = ObReferenceObjectByHandle( fileHandle,
			0,
			IoFileObjectType,
			KernelMode,
			(PVOID *) &fileObject,
			NULL );
		if (NT_SUCCESS( status )) {

			*FileObject = fileObject;

			//
			// Get a pointer to the device object for this file.
			//
			*DeviceObject = IoGetRelatedDeviceObject( fileObject );
		}
		(VOID) ZwClose( fileHandle );
	}
	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
  
PDEVICE_OBJECT 
IoGetRelatedDeviceObject(
     IN PFILE_OBJECT FileObject
);

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

 它的实现如下:


PDEVICE_OBJECT
IoGetRelatedDeviceObject(
			 IN PFILE_OBJECT FileObject
						 )
{
	PDEVICE_OBJECT deviceObject;

	//
	// 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;


		//
		// 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;

			//
			// 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 );

	//
	// 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.
	//

	if (deviceObject->AttachedDevice != NULL) {
		if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {

			PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =
				(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);

			ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));

			if (fileObjectExtension->TopDeviceObjectHint != NULL &&
				IopVerifyDeviceObjectOnStack(deviceObject, fileObjectExtension->TopDeviceObjectHint)) {
					return fileObjectExtension->TopDeviceObjectHint;
			}
		}
		deviceObject = IoGetAttachedDevice( deviceObject );
	}

	return deviceObject;
}

5. IoGetBaseFileSystemDeviceObject 得到与文件对象相关的卷设备对象(是由文件系统在打开卷时创建的).
    
PDEVICE_OBJECT IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
{
	PDEVICE_OBJECT deviceObject;
	// If the file object has a mounted Vpb, use its DeviceObject.
	if(FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL)
	{
		deviceObject = FileObject->Vpb->DeviceObject;
		// Otherwise, if the real device has a VPB that indicates that it is mounted,
		// then use the file system device object associated with the VPB.
	}
	else if(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
		FileObject->DeviceObject->Vpb != NULL &&
		FileObject->DeviceObject->Vpb->DeviceObject != NULL )
	{
		deviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
		// Otherwise, just return the real device object.
	}
	else
	{
		deviceObject = FileObject->DeviceObject;
	}
	ASSERT(deviceObject != NULL);
	// Simply return the resultant file object.
	return deviceObject;
}

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


7. 关闭X64的驱动签名
bcdedit/set testsigning on

你可能感兴趣的:(object,File,null,extension,Descriptor,attributes)