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