同样也是寒江独钓的例子,但只给了思路,现贴出实现代码
原理是通过改变端口驱动中本该调用类驱动回调函数的地方下手
//替换分发函数 来实现过滤 #include <wdm.h> #include <ntddk.h> #include <Ntddkbd.h> #include <windef.h> // Kbdclass驱动的名字 #define KBD_DRIVER_NAME L"\Driver\Kbdclass" //ps2的端口驱动 #define PS2_DRIVER_NAME L"\Driver\i8042prt" //usb的端口驱动 #define USB_DRIVER_NAME L"\Driver\Kbdhid" // 这个函数是事实存在的,只是文档中没有公开。声明一下 // 就可以直接使用了。 PVOID pOldFucAddr; PVOID pOldValue; NTSTATUS ObReferenceObjectByName( PUNICODE_STRING ObjectName, ULONG Attributes, PACCESS_STATE AccessState, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, PVOID ParseContext, PVOID *Object ); BOOLEAN MmIsAddressValid( PVOID VirtualAddress ); extern POBJECT_TYPE *IoDriverObjectType; //定义要查找的回调函数的类型 typedef VOID(_stdcall *KEYBOARDCLASSSERVICECALLBACK) (IN PDEVICE_OBJECT DeviceObject, IN PKEYBOARD_INPUT_DATA InputDataStart, IN PKEYBOARD_INPUT_DATA InputDataEnd, IN OUT PULONG InputDataConsumed); typedef struct _KBD_CALLBACK { PDEVICE_OBJECT classDeviceObject; KEYBOARDCLASSSERVICECALLBACK serviceCallBack; BOOLEAN bSearch; }KBD_CALLBACK,PKBD_CALLBACK; KBD_CALLBACK g_KbdCallBack; #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) { KdPrint(("DriverEntry unLoading... ")); InterlockedExchangePointer(pOldFucAddr,g_KbdCallBack.serviceCallBack); } VOID _stdcall MyCallBackFun (IN PDEVICE_OBJECT DeviceObject, IN PKEYBOARD_INPUT_DATA InputDataStart, IN PKEYBOARD_INPUT_DATA InputDataEnd, IN OUT PULONG InputDataConsumed) { DbgPrint("makecode %d flags %d ",InputDataStart->MakeCode,InputDataStart->Flags); g_KbdCallBack.serviceCallBack(DeviceObject,InputDataStart,InputDataEnd,InputDataConsumed); } NTSTATUS SearchKbdDevice() { //定义一些局部变量 NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING uniNtNameString; PDEVICE_OBJECT pUsingDeviceObject = NULL;//目标设备 PDRIVER_OBJECT KbdDriverObject = NULL;//类驱动 PDRIVER_OBJECT KbdhidDriverObject = NULL;//USB 端口驱动 PDRIVER_OBJECT Kbd8042DriverObject = NULL;//PS/2 端口驱动 PDRIVER_OBJECT UsingDriverObject = NULL; PVOID KbdDriverStart = NULL;//类驱动起始地址 ULONG KbdDriverSize = 0; PBYTE UsingDeviceExt = NULL; ULONG i=0; PVOID pTemp; PDEVICE_OBJECT pAttachedKbdDevice; //这部分代码打开PS/2键盘的驱动对象 RtlInitUnicodeString(&uniNtNameString,PS2_DRIVER_NAME); status = ObReferenceObjectByName( &uniNtNameString, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*)&Kbd8042DriverObject ); if (!NT_SUCCESS(status)) { DbgPrint("Couldn't get the PS/2 driver Object "); } else { //解除引用 ObDereferenceObject(Kbd8042DriverObject); DbgPrint("Got the PS/2 driver Object "); } //打开USB 键盘的端口驱动 RtlInitUnicodeString(&uniNtNameString,USB_DRIVER_NAME); status = ObReferenceObjectByName( &uniNtNameString, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*)&KbdhidDriverObject ); if (!NT_SUCCESS(status)) { DbgPrint("Couldn't get the USB driver Object "); } else { ObDereferenceObject(KbdhidDriverObject); DbgPrint("Got the USB driver Object "); } //如果同时有两个键盘,使用i8042prt if (Kbd8042DriverObject && KbdhidDriverObject) { DbgPrint("More than one keyboard! "); } //两种键盘都没有 也返回失败 if (!Kbd8042DriverObject && KbdhidDriverObject) { DbgPrint("Not found keyboard! "); return STATUS_UNSUCCESSFUL; } //找到合适的驱动对象 UsingDriverObject = Kbd8042DriverObject ? Kbd8042DriverObject : KbdhidDriverObject; RtlInitUnicodeString(&uniNtNameString, KBD_DRIVER_NAME); status = ObReferenceObjectByName ( &uniNtNameString, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*)&KbdDriverObject ); // 如果失败了就直接返回 if(!NT_SUCCESS(status)) { DbgPrint("Couldn't get the MyTest Device Object "); return STATUS_UNSUCCESSFUL; } else { // 这个打开需要解应用。 ObDereferenceObject(KbdDriverObject); } //如果成功,找到Kbdclass开始地址和大小 KbdDriverStart =KbdDriverObject->DriverStart; KbdDriverSize = KbdDriverObject->DriverSize; //遍历UsingDriverObject下的设备对象,找到Kbdclass Attach的那个设备对象 pUsingDeviceObject = UsingDriverObject->DeviceObject; while (pUsingDeviceObject) { Label_Continue: pAttachedKbdDevice=KbdDriverObject->DeviceObject; while(pAttachedKbdDevice) { PDEVICE_OBJECT pAttached=pUsingDeviceObject->AttachedDevice; while(pAttached) { if(pAttachedKbdDevice==pAttached) { DbgPrint("pAttachedKbdDevice :%8x ",pAttachedKbdDevice); UsingDeviceExt=(PBYTE)pUsingDeviceObject->DeviceExtension; //遍历找到的端口驱动设备扩展下的每个指针 for (i=0;i<4096;i++,UsingDeviceExt += sizeof(PBYTE)) { if (!MmIsAddressValid(UsingDeviceExt)) { pUsingDeviceObject=pUsingDeviceObject->AttachedDevice; goto Label_Continue; } //在端口驱动的设备扩展中,找到了类驱动的设备对象,填好类驱动设备对象后继续 pTemp = *(PVOID*)UsingDeviceExt; if (pTemp == pAttachedKbdDevice) { g_KbdCallBack.classDeviceObject = (PDEVICE_OBJECT)pTemp; DbgPrint("classDeviceObject %8x ",pTemp); pTemp = *(PVOID*)(UsingDeviceExt+4); if ((pTemp > KbdDriverStart)&&(pTemp < (PBYTE)KbdDriverStart+KbdDriverSize)&&MmIsAddressValid(pTemp)) { //记录回调函数的地址 g_KbdCallBack.serviceCallBack = (KEYBOARDCLASSSERVICECALLBACK)pTemp; g_KbdCallBack.bSearch=TRUE; status=STATUS_SUCCESS; DbgPrint("serviceCallBack :%8x ",pTemp); DbgPrint("替换函数"); pOldFucAddr=(PVOID*)(UsingDeviceExt+4); InterlockedExchangePointer((PVOID*)(UsingDeviceExt+4),MyCallBackFun); goto Label_Exit; } break; } } pUsingDeviceObject=pUsingDeviceObject->AttachedDevice; goto Label_Continue; } pAttached=pAttached->AttachedDevice; } pAttachedKbdDevice=pAttachedKbdDevice->NextDevice; } pUsingDeviceObject=pUsingDeviceObject->NextDevice; } Label_Exit: //如果成功找到,可以返回了 return status; } //驱动程序入口 NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { // 卸载函数。 DriverObject->DriverUnload = c2pUnload; return SearchKbdDevice(); }