据msdn上说绑定设备最开始是用的是IoAttachDeviceByPointer,其原型为
NTSTATUS IoAttachDeviceByPointer(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice
);
第一个参数为待绑定的设备,第二个参数为绑定的目标设备,返回值确定是否成功
而取代IoAttachDeviceByPointer的则是IoAttachDeviceToDeviceStack与IoAttachDeviceToDeviceStackSafe
IoAttachDeviceToDeviceStack的原型为
PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
__in PDEVICE_OBJECT SourceDevice,
__in PDEVICE_OBJECT TargetDevice
);
IoAttachDeviceToDeviceStack函数参数和IoAttachDeviceByPointer一样,
但是返回值由NTSTATUS改为了PDEVICE_OBJECT,
返回成功挂载后的下一层设备,这个和第二个参数有区别...假如a--b--c--d--e依次为设备栈的底到顶,若将f挂载到a上面的
话,调用IoAttachDeviceToDeviceStack(f,a),挂载之后返回的指针指向e,与第二个参数不同,此时的设备栈为a--b--c--d--e--f,
f被挂载在设备栈的顶层.
逆向xp sp3下的IoAttachDeviceToDeviceStack后发现,它本质上还是调用了IoAttachDeviceToDeviceStackSafe
8050cb42 8bff mov edi,edi
8050cb44 55 push ebp
8050cb45 8bec mov ebp,esp
8050cb47 6a00 push 0 ;第三个参数为0
8050cb49 ff750c push dword ptr [ebp+0Ch] ;压入第二个参数
8050cb4c ff7508 push dword ptr [ebp+8] ;压入第一个参数
8050cb4f e8caf2ffff call nt!IopAttachDeviceToDeviceStackSafe (8050be1e) ;调用
8050cb54 5d pop ebp
8050cb55 c20800 ret 8
IoAttachDeviceToDeviceStack函数参数和IoAttachDeviceByPointer一样,
但是返回值由NTSTATUS改为了PDEVICE_OBJECT,
返回成功挂载后的下一层设备,这个和第二个参数有区别...
NTSTATUS IoAttachDeviceToDeviceStackSafe(
__in PDEVICE_OBJECT SourceDevice,
__in PDEVICE_OBJECT TargetDevice,
__out PDEVICE_OBJECT *AttachedToDeviceObject
);
而IoAttachDeviceToDeviceStackSafe的返回值为NTSTATUS,并且第三个参数返回挂载成功后的下一层设备.NTSTATUSNTAPI
IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
IN OUT PDEVICE_OBJECT *AttachedToDeviceObject)
{
/* Call the internal function */
if (!IopAttachDeviceToDeviceStackSafe(SourceDevice, TargetDevice,
AttachedToDeviceObject))
{
/* Nothing found */
return STATUS_NO_SUCH_DEVICE;
}
return STATUS_SUCCESS;
}
PDEVICE_OBJECT NTAPI
IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL)
{
PDEVICE_OBJECT AttachedDevice;
PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
/* Get the Attached Device and source extension */
AttachedDevice = IoGetAttachedDevice(TargetDevice);
SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
ASSERT(SourceDeviceExtension->AttachedTo == NULL);
/* Make sure that it's in a correct state */
if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) ||
(IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
(DOE_UNLOAD_PENDING | DOE_DELETE_PENDING |
DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED)))
{ //尚在初始化的过程中,或者已在卸载的过程中,不再堆叠
/* Device was unloading or being removed */
AttachedDevice = NULL;
}
else
{ //堆叠,这里的AttachedDevice是粘贴的目标,SourceDevice是被粘贴对象
/* Update atached device fields */
AttachedDevice->AttachedDevice = SourceDevice; //向上指向被粘贴对象
AttachedDevice->Spare1++;
/* Update the source with the attached data */
SourceDevice->StackSize = AttachedDevice->StackSize + 1; //堆叠的深度增加了
SourceDevice->AlignmentRequirement = AttachedDevice->AlignmentRequirement;
SourceDevice->SectorSize = AttachedDevice->SectorSize;
/* Check for pending start flag */
if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
DOE_START_PENDING)
{
/* Propagate */
IoGetDevObjExtension(SourceDevice)->ExtensionFlags |=
DOE_START_PENDING;
}
/* Set the attachment in the device extension */
SourceDeviceExtension->AttachedTo = AttachedDevice; //向下指向粘贴目标
}
/* Return the attached device */ //使自定义的向下指针也指向粘贴目标
if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice;
return AttachedDevice;
}
两个函数运行的IRQL<=DISPATCH_LEVEL.IoDetachDevice,取消挂载的设备,原型为VOID IoDetachDevice(__inout PDEVICE_OBJECT TargetDevice);其取消TargetDevice的引用计数,当引用计数为0后就卸载