1、 Hook Dispatch例程。
首先通过ObReferenceObjectByName等函数拿到被Hook设备的DriverObject。有了这个之后,我们就可以用指向自己例程的指针改写MajorFunction数组里面的指针。
NTSTATUS ntStatus = STATUS_SUCCESS;
UNICODE_STRING wszDriverName;
PDRIVER_OBJECT pDriverObject = NULL;
PDRIVER_DISPATCH pOrgDispatch = NULL;
RtlInitUnicodeString( &wszDriverName, DRIVER_NAME);
ntStatus = ObReferenceObjectByName( &wszDriverName,
0,
NULL,
0,
*IoDriverObjectType,
//NULL,
KernelMode,
NULL,
(PVOID*)&pDriverObject);
if( !NT_SUCCESS(ntStatus))
{
DbgPrint( "ObReferenceObjectByName Fail.\r\n");
return FALSE;
}
pOrgDispatch = (PDRIVER_DISPATCH) InterlockedExchange( ( PLONG)&pDriverObject->MajorFunction[IRP_MJ_READ], (LONG)&DispatchMyRead);
……
卸载的时候同样这样修改回去即可。
这种方法比较方便,由于只需要改写一个函数指针,避免了inline hook的很多不稳定因素。另外,在调用原来的Dispatch例程的时候也只需要直接call它就行了。
但是,如果有些IRP不能立即完成的,例如键盘鼠标驱动的IRP,用这种方法就拿不到完成时候的数据了。因此我们还需要第二种方式J
2、 Hook Completion Routine。
在Hook掉的Dispatch里面,我们已经拿到了发到下层驱动的IRP。想在完成时再获得控制权,很简单,只需要再Hook掉Completion Routine。
NTSTATUS DispatchMyRead ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp);
//需要保存一下旧的完成例程信息
g_RecentIrpInfo.ComplettionRoutine = irpSp->CompletionRoutine;
g_RecentIrpInfo.Context = irpSp->Context;
g_RecentIrpInfo.Control = irpSp->Control;
g_RecentIrpInfo.irpSp = irpSp;
//安装自己的完成例程
irpSp->CompletionRoutine = MyIoCompletion;
irpSp->Context = NULL;
irpSp->Control = SL_INVOKE_ON_SUCCESS;
//OK,call下去。
ntStatus = g_ pOrgDispatch ( pDeviceObject, Irp);
return ntStatus;
}
在MyIoCompletion当然就是同样的标准hook操作咯,处理数据,call原来的IoCompletion。需要注意的是很多Irp并没有安装完成例程。