介绍
主要是用来过滤键盘按键,或者修改按键用的
原理
本质是通过创建过滤设备来绑定\Driver\Kbdclass中的所有设备来实现过滤
绑定
先通过ObReferenceObjectByName来获取目标设备的驱动对象
//获取驱动对象
status = ObReferenceObjectByName(
&ObjName,
OBJ_CASE_INSENSITIVE,
NULL,
0,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID*)&pKbdclassDriver);
if (status != STATUS_SUCCESS)
{
KdPrint(("ObReferenceObjectByName failed: %x", status));
return status;
}
//解引用
ObDereferenceObject(pKbdclassDriver);
然后再遍历该驱动对象下所有设备,全部进行绑定,再设置设备扩展
//遍历设备
pTargetDevObj = pKbdclassDriver->DeviceObject;
while (pTargetDevObj)
{
//创建过滤设备
status = IoCreateDevice(
pDriver,
sizeof(DEV_EXT),
NULL,
pTargetDevObj->DeviceType,
pTargetDevObj->Characteristics,
FALSE,
&pFltDevObj
);
if (status != STATUS_SUCCESS)
{
KdPrint(("ObReferenceObjectByName failed"));
return status;
}
//绑定设备
status = IoAttachDeviceToDeviceStackSafe(pFltDevObj, pTargetDevObj, &pLowerDevObj);
if (status != STATUS_SUCCESS)
{
KdPrint(("IoAttachDeviceToDeviceStackSafe failed"));
IoDeleteDevice(pFltDevObj);
return status;
}
//获取设备扩展
pDevExt = (PDEV_EXT)(pFltDevObj->DeviceExtension);
//初始化设备扩展
InitDevExt(pDevExt, pFltDevObj, pTargetDevObj, pLowerDevObj);
pFltDevObj->DeviceType = pLowerDevObj->DeviceType;
pFltDevObj->Characteristics = pLowerDevObj->Characteristics;
pFltDevObj->StackSize = pLowerDevObj->StackSize + 1;
pFltDevObj->Flags |= pLowerDevObj->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
//继续下一个设备
pTargetDevObj = pTargetDevObj->NextDevice;
}
分发
这之后你还需要写几个分发函数,大概是以下几种
常规分发
直接下发即可,不用管
//常规分发
NTSTATUS DispatchGeneral(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
PDEV_EXT pDevExt = (PDEV_EXT)pDevObj->DeviceExtension;
PDEVICE_OBJECT pLowerDevObj = pDevExt->pLowerDevObj;
KdPrint(("DispatchGeneral"));
IoSkipCurrentIrpStackLocation(pIrp);
return IoCallDriver(pLowerDevObj, pIrp);
}
电源分发
单独处理就行,也是直接下发
NTSTATUS DispatchPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
PDEV_EXT pDevExt = (PDEV_EXT)pDevObj->DeviceExtension;
KdPrint(("DispatchPower"));
PoStartNextPowerIrp(pIrp);
IoSkipCurrentIrpStackLocation(pIrp);
return PoCallDriver(pDevExt->pTargetDevObj, pIrp);
}
即插即用分发
这里主要是处理有设备移除的时候,解绑并且删除过滤设备
NTSTATUS DispatchPNP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
PIO_STACK_LOCATION stack;
PDEV_EXT pDevExt = NULL;
NTSTATUS status = STATUS_SUCCESS;
pDevExt = (PDEV_EXT)pDevObj->DeviceExtension;
stack = IoGetCurrentIrpStackLocation(pIrp);
switch (stack->MajorFunction)
{
//移除
case IRP_MN_REMOVE_DEVICE:
//先发送请求下去
IoSkipCurrentIrpStackLocation(pIrp);
IoCallDriver(pDevExt->pLowerDevObj, pIrp);
//解除绑定
IoDetachDevice(pDevExt->pLowerDevObj);
//删除过滤设备
IoDeleteDevice(pDevObj);
break;
default:
//直接下发
IoSkipCurrentIrpStackLocation(pIrp);
IoCallDriver(pDevExt->pLowerDevObj, pIrp);
break;
}
return status;
}
读分发
这里不是直接下发,而是设置个回调,当下层完成请求时,调用该回调,咱再进行处理
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
PDEV_EXT pDevExt = NULL;
PIO_STACK_LOCATION stack;
NTSTATUS status = STATUS_SUCCESS;
if (pIrp->CurrentLocation == 1)
{
KdPrint(("pIrp->CurrentLocation == 1"));
status = STATUS_INVALID_DEVICE_REQUEST;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
g_nCount++;
pDevExt = (PDEV_EXT)pDevObj->DeviceExtension;
stack = IoGetCurrentIrpStackLocation(pIrp);
//复制IRP
IoCopyCurrentIrpStackLocationToNext(pIrp);
//设置完成回调
IoSetCompletionRoutine(pIrp, ReadComplete, pDevObj, TRUE, TRUE, TRUE);
//下发
return IoCallDriver(pDevExt->pLowerDevObj, pIrp);
}
读完成回调
这里就是处理
NTSTATUS
ReadComplete(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP pIrp,
__in_xcount_opt("varies") PVOID Context
)
{
ULONG i;
PKEYBOARD_INPUT_DATA pKey;
ULONG uKeySize;
PIO_STACK_LOCATION stack;
stack = IoGetCurrentIrpStackLocation(pIrp);
//判断是否成功
if (pIrp->IoStatus.Status != STATUS_SUCCESS)
{
if (pIrp->PendingReturned)
{
IoMarkIrpPending(pIrp);
}
return pIrp->IoStatus.Status;
}
//获取缓冲区和大小
pKey = (PKEYBOARD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;
//获取键个数
uKeySize = pIrp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);
//打印
for (i = 0; i < uKeySize; i++)
{
KdPrint(("ScanCode: %x", pKey->MakeCode));
KdPrint(("%s", pKey->Flags ? "up" : "down"));
//s修改为d
if (pKey->MakeCode == 0x1F)
{
pKey->MakeCode = 0x20;
}
}
g_nCount--;
if (pIrp->PendingReturned)
{
IoMarkIrpPending(pIrp);
}
return pIrp->IoStatus.Status;
}
动态卸载
卸载直接放在源码里了,可以自行下载
完整代码
下载地址: 完整代码