在ntddk.h中定义了该函数原型:
#if (NTDDI_VERSION >= NTDDI_WINXP)
NTKERNELAPI
NTSTATUS
IoAttachDeviceToDeviceStackSafe(
__in PDEVICE_OBJECT SourceDevice,
__in PDEVICE_OBJECT TargetDevice,
__deref_out PDEVICE_OBJECT *AttachedToDeviceObject
);
#endif
我们加载微软的sfilter源码进行分析
1 创建sfilter的CDO
图1
驱动Sfilter.sys等待 文件系统驱动的加载 SfFsNotification
图2
我们可以看到 Ntfs.sys驱动的CDO地址是0x862c8270
这时候 我们的Sfilter即将创建一个FiDO附着在Ntfs的CDO上面
图3
新创建的FiDO的地址是0x86337998
而newDeviceObject->DriverObject的驱动地址正是我们的Sfilter的驱动地址
另外newDeviceObject->NextDevice是Sfilter!CDO的地址
这说明,IoCreateDevice的时候,新建的DeviceObject在会插在以往的DO之前 如图4
图4
下面的任务便是附着FiDO于Ntfs驱动的CDO之上
IoAttachDeviceToDeviceStackSafe(
newDeviceObject,
DeviceObject,
&devExt->AttachedToDeviceObject );
继续用winDBG查看
图5
FiDO的地址是0x86337998
FiDO->AttachedDevice的地址是0x00000000 此时FiDO在设备栈的最顶层
现在明了了 DeviceObject->AttachedDevice指向的是上层的设备
图6
图7
我们用winDBG验证一下
图8
我们查看WRK源码 IopAttachDeviceToDeviceStackSafe
PDEVICE_OBJECT
IopAttachDeviceToDeviceStackSafe(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL
)
{
PDEVICE_OBJECT deviceObject;
PDEVOBJ_EXTENSION sourceExtension;
KIRQL irql;
//
// Retrieve a pointer to the source device object's extension outside
// of the IopDatabaseLock, since it isn't protected by that.
//
sourceExtension = SourceDevice->DeviceObjectExtension;
//
// Get a pointer to the topmost device object in the stack of devices,
// beginning with the TargetDevice, and attach to it.
//
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
//
// Tell the Special IRP code the stack has changed. Code that will reexamine
// the stack takes the database lock, so we can place the call here. This
// also allows us to assert correct behavior *before* the stack is built up.
//
IOV_ATTACH_DEVICE_TO_DEVICE_STACK(SourceDevice, TargetDevice);
<strong> deviceObject = IoGetAttachedDevice( TargetDevice );</strong>
//
// Make sure that the SourceDevice object isn't already attached to
// something else, this is now illegal.
//
ASSERT( sourceExtension->AttachedTo == NULL );
//
// Now attach to the device, provided that it is not being unloaded,
// deleted or initializing.
//
if (deviceObject->Flags & DO_DEVICE_INITIALIZING ||
deviceObject->DeviceObjectExtension->ExtensionFlags &
(DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED)) {
//
// The device currently at the top of the attachment chain is being
// unloaded, deleted or initialized.
//
deviceObject = (PDEVICE_OBJECT) NULL;
} else {
//
// Perform the attachment. First update the device previously at the
// top of the attachment chain.
//
<strong>deviceObject->AttachedDevice = SourceDevice;</strong>
deviceObject->Spare1++;
//
// Now update the new top-of-attachment-chain.
//
<strong>SourceDevice->StackSize = (UCHAR) (deviceObject->StackSize + 1);</strong>
SourceDevice->AlignmentRequirement = deviceObject->AlignmentRequirement;
SourceDevice->SectorSize = deviceObject->SectorSize;
if (deviceObject->DeviceObjectExtension->ExtensionFlags & DOE_START_PENDING) {
SourceDevice->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING;
}
//
// Attachment chain is doubly-linked.
//
sourceExtension->AttachedTo = deviceObject;
}
//
// Atomically update this field inside the lock.
// The caller has to ensure that this location is in non-paged pool.
// This is required so that a filesystem filter can attach to a device and before it
// gets an IRP it can update its lower device object pointer.
//
if (AttachedToDeviceObject) {
*AttachedToDeviceObject = deviceObject;
}
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
return deviceObject;
}
deviceObject 会一直遍历 TargetDevice的设备栈,直到最上层的设备。这个deviceObject 也是最后返回的PDEVICE_OBJECT。
PDEVICE_OBJECT
IoGetAttachedDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
//
// Loop through all of the device object's attached to the specified
// device. When the last device object is found that is not attached
// to, return it.
//
while (DeviceObject->AttachedDevice) {
<strong>DeviceObject = DeviceObject->AttachedDevice;</strong>
}
return DeviceObject;
}
然后 deviceObject->AttachedDevice = SourceDevice; 将我们的SourceDevice附着在设备栈的最顶层。
最后SourceDevice->StackSize = (UCHAR) (deviceObject->StackSize + 1); stackSize增加1。