分层驱动模型
一、简介
IRP是在设备栈上进行传递的,由高层传递给底层,而每一层的设备都会对应一个IO_STACK_LOCATION类型的IO堆栈用来记录IRP到达本层设备时所作的操作。而当IRP被某一层设备完成时,IO堆栈会一层一层地弹出,这称之为设备栈的回卷。

我们现在看见了,IRP在传递的时候,会经过好几层的设备,每一层同样对于一个驱动,这就称之为分层驱动模型。而正是这种分层的方式,使得我们可以在设备栈上添加一个设备,以达到Hook IRP。
二、Hook IRP
要做到Hook IRP,我们需要先了解一个内核API.
PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
[in] PDEVICE_OBJECT SourceDevice,
[in] PDEVICE_OBJECT TargetDevice
);
[in] SourceDevice
指向调用方创建的设备对象的指针。
[in] TargetDevice
指向另一个驱动程序的设备对象的指针,例如之前调用 IoGetDeviceObjectPointer 返回的指针。
此函数正好可以用来将一个设备放置到某个设备栈的最顶层,这样我们的驱动就会第一个捕获到传递到设备栈的IRP。同时此内核API返回原本设备栈最高层的设备。

要将DeviceC插入到设备栈最顶层,那么函数中SourceDevice为DeviceC,TargetDevice为DeviceB。返回值为DeviceB,即原本设备栈最顶层的设备。
三、完成例程
使用IoSetCompleteRoutine对IRP设置完成例程,当IRP向上回卷时,本层若是设置了完成例程,则会进入到完成例程中。但完成例程的使用需要注意以下几点:
1、如果设置了完成例程,则IRP使用IoCallDriver就不能使用IoSkipCurrentIrpStackLocation,必须使用IoCopyCurrentIrpStackLocationToNext。
2.完成例程中返回的是STATUS_SUCCESS或者STATUS_CONTINUE_COMPLETION(SUCCESS别名),则IRP继续向上回卷,驱动不会再获取控制权。返回STATUS_MORE_PROCESSING_REQUIRED,本层驱动会获得控制权,并且设备栈不会向上回卷。而且还需要在本层调用IoCompleteRequest完成IRP
返回STATUS_SUCCESS示例
NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
//进入此函数标志底层驱动设备将IRP完成
KdPrint(("Enter MyIoCompletion\n"));
if (Irp->PendingReturned)
{
//传播pending位
IoMarkIrpPending( Irp );
}
return STATUS_SUCCESS;//同STATUS_CONTINUE_COMPLETION
}
#pragma PAGEDCODE
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
KdPrint(("DriverB:Enter B HelloDDKRead\n"));
NTSTATUS ntStatus = STATUS_SUCCESS;
//将自己完成IRP,改成由底层驱动负责
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
//将当前IRP堆栈拷贝底层堆栈
IoCopyCurrentIrpStackLocationToNext(pIrp);
//设置完成例程
IoSetCompletionRoutine(pIrp,MyIoCompletion,NULL,TRUE,TRUE,TRUE);
//调用底层驱动
ntStatus = IoCallDriver(pdx->TargetDevice, pIrp);
//当IoCallDriver后,并且完成例程返回的是STATUS_SUCCESS
//IRP就不在属于派遣函数了,就不能对IRP进行操作了
if (ntStatus == STATUS_PENDING)
{
KdPrint(("STATUS_PENDING\n"));
}
ntStatus = STATUS_PENDING;
KdPrint(("DriverB:Leave B HelloDDKRead\n"));
return ntStatus;
}
返回STATUS_MORE_PROCSSING_REQUIRED
NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
if (Irp->PendingReturned == TRUE)
{
//设置事件
KeSetEvent((PKEVENT)Context,IO_NO_INCREMENT,FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
#pragma PAGEDCODE
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
KdPrint(("DriverB:Enter B HelloDDKRead\n"));
NTSTATUS ntStatus = STATUS_SUCCESS;
//将自己完成IRP,改成由底层驱动负责
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
//将本层的IRP堆栈拷贝到底层堆栈
IoCopyCurrentIrpStackLocationToNext(pIrp);
KEVENT event;
//初始化事件
KeInitializeEvent(&event, NotificationEvent, FALSE);
//设置完成例程
IoSetCompletionRoutine(pIrp,MyIoCompletion,&event,TRUE,TRUE,TRUE);
//调用底层驱动
ntStatus = IoCallDriver(pdx->TargetDevice, pIrp);
if (ntStatus == STATUS_PENDING)
{
KdPrint(("IoCallDriver return STATUS_PENDING,Waiting ...\n"));
KeWaitForSingleObject(&event,Executive,KernelMode ,FALSE,NULL);
ntStatus = pIrp->IoStatus.Status;
}
//虽然在底层驱动已经将IRP完成了,但是由于完成例程返回的是
//STATUS_MORE_PROCESSING_REQUIRED,因此需要再次调用IoCompleteRequest!
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
KdPrint(("DriverB:Leave B HelloDDKRead\n"));
return ntStatus;
}
分层驱动模型:等您坐沙发呢!
发表评论
