#include
//键盘过滤驱动
//IoDriverObjectType 是全局变量,但是头文件中没有,所以在这里声明
extern POBJECT_TYPE *IoDriverObjectType;
//KbdClass 驱动的名字
#define KBD_DRIVER_NAME L"\\Driver\\Kbdclass"
//ObReferenceObjectByName 未导出文档,先声明
NTSTATUS ObReferenceObjectByName(
PUNICODE_STRING ObjectName,
ULONG Attributes,
PACCESS_STATE AccessState,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID ParseContext,
PVOID *Object
);
//全局变量
ULONG gC2pKeyCount = 0;
PDRIVER_OBJECT gDriverObject = NULL;
//设备扩展, 专门定义的一个结构
typedef struct _C2P_DEV_EXT{
//这个结构的大小
ULONG NodeSize;
//过滤设备对象
PDEVICE_OBJECT pFilterDeviceObject;
//绑定时的设备对象
PDEVICE_OBJECT TargetDeviceObject;
//绑定前底层设备对象
PDEVICE_OBJECT LowerDeviceObject;
}C2P_DEV_EXT, *PC2P_DEV_EXT;
void c2pUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS c2pDispatchGeneral(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS c2pDispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS c2pPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS c2pPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS c2pReadComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
NTSTATUS c2pAttachDevices(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
NTSTATUS c2pDevExtInit(IN PC2P_DEV_EXT devExt, IN PDEVICE_OBJECT pFilterDeviceObject, IN PDEVICE_OBJECT pTargetDeviceObject, IN PDEVICE_OBJECT pLowerDeviceObject);
//驱动入口
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){
ULONG i;
NTSTATUS status;
KdPrint(("misaka: entering driverentry\n"));
//填写所有的分发函数指针
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++){
DriverObject->MajorFunction[i] = c2pDispatchGeneral;
DbgPrint("misaka: test %d..\r\n",i);
}
//单独填写一个读分发函数,因为重要的是读取按键的信息,其他都不重要
DriverObject->MajorFunction[IRP_MJ_READ] = c2pDispatchRead;
//单独填写一个 IRP_MJ_POWER 函数,这是因为这类请求中间要调用一个 PoCallDriver 和 PoStartNextPowerIrp 比较特殊
DriverObject->MajorFunction[IRP_MJ_POWER] = c2pPower;
//我们想知道什么时候绑定过的设备被卸载了(比如从机器上拔掉),专门写一个 PNP(即插即用)分发函数
DriverObject->MajorFunction[IRP_MJ_PNP] = c2pPnP;
//卸载函数
DriverObject->DriverUnload = c2pUnload;
//绑定所有的键盘设备
status = c2pAttachDevices(DriverObject, RegistryPath);
return status;
}
//卸载函数
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000)
void c2pUnload(IN PDRIVER_OBJECT DriverObject){
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT OldDeviceObject;
PC2P_DEV_EXT devExt;
LARGE_INTEGER lDelay;
PRKTHREAD CurrentThread;
lDelay = RtlConvertLongToLargeInteger(100 * DELAY_ONE_MILLISECOND);
CurrentThread = KeGetCurrentThread();
//把当前线程设置为低实时模式,以便尽可能少的影响其他程序
KeSetPriorityThread(CurrentThread, LOW_REALTIME_PRIORITY);
UNREFERENCED_PARAMETER(DriverObject);
KdPrint(("misaka: driverentry unloading...\n"));
//遍历所有设备并一律解除绑定,删除所有的设备
DeviceObject = DriverObject->DeviceObject;
while (DeviceObject){
PC2P_DEV_EXT devExt;
devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
//只解除绑定
IoDetachDevice(devExt->TargetDeviceObject);
devExt->TargetDeviceObject = NULL;
DbgPrint("misaka: detach finished\r\n");
DeviceObject = DeviceObject->NextDevice;
}
DbgPrint("misaka: ------------------------------------ %d.\r\n", gC2pKeyCount);
//gC2pKeyCount全局变量,等待请求完成才卸载
while (gC2pKeyCount){
KeDelayExecutionThread(KernelMode, FALSE, &lDelay);
}
//删除过滤设备
DeviceObject = DriverObject->DeviceObject;
if (DeviceObject == NULL){
DbgPrint("misaka: DeviceObject and null\r\n");
return;
}
while (DeviceObject){
PC2P_DEV_EXT devExt;
devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
IoDeleteDevice(devExt->pFilterDeviceObject);
devExt->pFilterDeviceObject = NULL;
DbgPrint("misaka: unload filter device object success\r\n");
DeviceObject = DeviceObject->NextDevice;
}
//这个是产出驱动对象的,但是好像没有效果,只要停止驱动之后就不能再次启动了.可能是驱动没有卸载干净
//但是如果照着教程写的话,如果停止直接蓝屏...
//目前的情况是在win7 64位系统中启动驱动后可以获取按键消息...
//IoDeleteDevice(pDeviceObject);
//devExt->pFilterDeviceObject = NULL;
//DbgPrint("misaka: detach finished\r\n");
//讲道理这里应该要删除设备对象了
DbgPrint("misaka: bye ,driver unload successfully.\r\n");
return;
}
//键盘请求的处理 - 通常处理 - 直接跳过,发送到真实设备对象上
NTSTATUS c2pDispatchGeneral(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
KdPrint(("misaka: other diapatch!\n"));
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(((PC2P_DEV_EXT)DeviceObject->DeviceExtension)->LowerDeviceObject, Irp);
}
//键盘请求的处理 - 读请求
NTSTATUS c2pDispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
NTSTATUS status = STATUS_SUCCESS;
PC2P_DEV_EXT devExt;
PIO_STACK_LOCATION currentIrpStack;
KEVENT waitEvent;
KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);
if (Irp->CurrentLocation == 1){
ULONG ReturnedInformation = 0;
KdPrint(("misaka: dispatch encountered bogus current location\n"));
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = ReturnedInformation;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return (status);
}
//全局变量计数器+1
gC2pKeyCount++;
//得到设备扩展,获得下一个设备的指针
devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
//设置回掉函数并把IRP传递下去,读处理结束,等待读请求完成
currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, c2pReadComplete, DeviceObject, TRUE, TRUE, TRUE);
DbgPrint("read : number = %d\r\n", gC2pKeyCount);
return IoCallDriver(devExt->LowerDeviceObject, Irp);
}
//键盘请求的处理 - 电源相关请求
NTSTATUS c2pPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
KdPrint(("misaka: Power\n"));
PC2P_DEV_EXT devExt;
devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(devExt->LowerDeviceObject, Irp);
}
//键盘请求的处理 - 档设备被拔出时,解除绑定,并删除过滤设备
NTSTATUS c2pPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
PC2P_DEV_EXT devExt;
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_SUCCESS;
//获得真实设备
devExt = (PC2P_DEV_EXT)(DeviceObject->DeviceExtension);
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->MinorFunction){
case IRP_MN_REMOVE_DEVICE:
KdPrint(("misaka: IRP_MN_REMOVE_DEVICE\n"));
//先把请求下发
IoSkipCurrentIrpStackLocation(Irp);
IoCallDriver(devExt->LowerDeviceObject, Irp);
//然后解除绑定
IoDetachDevice(devExt->LowerDeviceObject);
//删除生成的虚拟设备
IoDeleteDevice(DeviceObject);
status = STATUS_SUCCESS;
break;
default:
//其他类型的IRP,全部直接下发
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(devExt->LowerDeviceObject, Irp);
}
return status;
}
//读请求完成后的回掉函数
NTSTATUS c2pReadComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context){
PIO_STACK_LOCATION IrpSp;
ULONG buf_len = 0;
PUCHAR buf = NULL;
size_t i;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
//如果请求成功执行(如果失败则没有获取的意义了)
if (NT_SUCCESS(Irp->IoStatus.Status)){
//获得读请求完成后的输出缓冲区
buf = Irp->AssociatedIrp.SystemBuffer;
//获得这个缓冲区的长度,一般来说,不管返回值有多长都保存在 Information 中
buf_len = (ULONG)Irp->IoStatus.Information;
//这里可以进一步处理,这里只是简单的打印出所有的扫描码
for (i = 0; i < buf_len; ++i){
DbgPrint("misaka: read %2x\r\n", buf[i]);
}
}
gC2pKeyCount--;
if (Irp->PendingReturned){
IoMarkIrpPending(Irp);
}
DbgPrint("call : number = %d\r\n", gC2pKeyCount);
return Irp->IoStatus.Status;
}
//打开驱动对象 KbdClass,绑定其下的所有设备
NTSTATUS c2pAttachDevices(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){
NTSTATUS status = 0;
UNICODE_STRING uniNtNameString;
PC2P_DEV_EXT devExt;
PDEVICE_OBJECT pFilterDeviceObject = NULL;
PDEVICE_OBJECT pTargetDeviceObject = NULL;
PDEVICE_OBJECT pLowerDeviceObject = NULL;
PDRIVER_OBJECT KbdDriverObject = NULL;
KdPrint(("misaka:my attach\n"));
//初始化字符串,就是KbdClass驱动的名字
RtlInitUnicodeString(&uniNtNameString, KBD_DRIVER_NAME);
//打开驱动对象
status = ObReferenceObjectByName(
&uniNtNameString,
OBJ_CASE_INSENSITIVE,
NULL,
0,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID*)&KbdDriverObject
);
//如果打开失败直接返回
if (!NT_SUCCESS(status)){
KdPrint(("misaka:couldn't get the device object\n"));
return (status);
} else{
//调用 ObReferenceObjectByName 对导致对驱动对象的引用计数增加,这里进行解引用
//改: 应该是打开设备对象的指针,而不是驱动对象
ObDereferenceObject(KbdDriverObject);
DbgPrint("misaka: open filter driver ok\r\n");
}
//设备链中的第一个设备
pTargetDeviceObject = KbdDriverObject->DeviceObject;
//遍历设备链
while (pTargetDeviceObject){
//生成一个过滤设备,也就是对所有设备创建过滤设备
status = IoCreateDevice(
IN DriverObject,
IN sizeof(PC2P_DEV_EXT),
IN NULL,
IN pTargetDeviceObject->DeviceType,
IN pTargetDeviceObject->Characteristics,
IN FALSE,
OUT &pFilterDeviceObject
);
//如果创建过滤设备失败,直接退出
if (!NT_SUCCESS(status)){
KdPrint(("misaka: couldn't create the filter device object\n"));
return (status);
}
DbgPrint("misaka: create filter driver ok\r\n");
//绑定 pLowerDeviceObject 是绑定之后得到的下一个设备(真实的设备)
pLowerDeviceObject = IoAttachDeviceToDeviceStack(pFilterDeviceObject, pTargetDeviceObject);
//如果绑定失败则放弃之前的操作,退出
if (!pLowerDeviceObject){
KdPrint(("misaka: couldn't attach to device object\n"));
IoDeleteDevice(pFilterDeviceObject);
pFilterDeviceObject = NULL;
return (status);
}
DbgPrint("misaka: attach filter driver ok\r\n");
//过滤设备扩展 保存着目标设备对象和真实设备对象的指针
devExt = (PC2P_DEV_EXT)(pFilterDeviceObject->DeviceExtension);
c2pDevExtInit(
devExt,
pFilterDeviceObject,
pTargetDeviceObject,
pLowerDeviceObject
);
//
pFilterDeviceObject->DeviceType = pLowerDeviceObject->DeviceType;
pFilterDeviceObject->Characteristics = pLowerDeviceObject->Characteristics;
pFilterDeviceObject->StackSize = pLowerDeviceObject->StackSize + 1;
pFilterDeviceObject->Flags |= pLowerDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
//移动到下一个设备,继续遍历
pTargetDeviceObject = pTargetDeviceObject->NextDevice;
}
return status;
}
//c2p驱动扩展设置函数
NTSTATUS c2pDevExtInit(IN PC2P_DEV_EXT devExt, IN PDEVICE_OBJECT pFilterDeviceObject, IN PDEVICE_OBJECT pTargetDeviceObject, IN PDEVICE_OBJECT pLowerDeviceObject){
memset(devExt, 0, sizeof(C2P_DEV_EXT));
devExt->NodeSize = sizeof(C2P_DEV_EXT);
devExt->pFilterDeviceObject = pFilterDeviceObject;
devExt->TargetDeviceObject = pTargetDeviceObject;
devExt->LowerDeviceObject = pLowerDeviceObject;
return (STATUS_SUCCESS);
}