通过修改i8042prt端口驱动中类驱动Kbdclass的回调函数地址,达到过滤键盘操作的例子

时间:2022-02-15 15:18:41

同样也是寒江独钓的例子,但只给了思路,现贴出实现代码

原理是通过改变端口驱动中本该调用类驱动回调函数的地方下手

//替换分发函数  来实现过滤
#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...\n"));
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\n",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 = ;
PBYTE UsingDeviceExt = NULL;
ULONG i=;
PVOID pTemp;
PDEVICE_OBJECT pAttachedKbdDevice;
//这部分代码打开PS/2键盘的驱动对象
RtlInitUnicodeString(&uniNtNameString,PS2_DRIVER_NAME);
status = ObReferenceObjectByName(
&uniNtNameString,
OBJ_CASE_INSENSITIVE,
NULL,
,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID*)&Kbd8042DriverObject
);
if (!NT_SUCCESS(status))
{
DbgPrint("Couldn't get the PS/2 driver Object\n");
}
else
{
//解除引用
ObDereferenceObject(Kbd8042DriverObject);
DbgPrint("Got the PS/2 driver Object\n");
} //打开USB 键盘的端口驱动
RtlInitUnicodeString(&uniNtNameString,USB_DRIVER_NAME);
status = ObReferenceObjectByName(
&uniNtNameString,
OBJ_CASE_INSENSITIVE,
NULL,
,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID*)&KbdhidDriverObject
);
if (!NT_SUCCESS(status))
{
DbgPrint("Couldn't get the USB driver Object\n");
}
else
{
ObDereferenceObject(KbdhidDriverObject);
DbgPrint("Got the USB driver Object\n");
} //如果同时有两个键盘,使用i8042prt
if (Kbd8042DriverObject && KbdhidDriverObject)
{
DbgPrint("More than one keyboard!\n");
} //两种键盘都没有 也返回失败
if (!Kbd8042DriverObject && KbdhidDriverObject)
{
DbgPrint("Not found keyboard!\n");
return STATUS_UNSUCCESSFUL;
} //找到合适的驱动对象
UsingDriverObject = Kbd8042DriverObject ? Kbd8042DriverObject : KbdhidDriverObject; RtlInitUnicodeString(&uniNtNameString, KBD_DRIVER_NAME);
status = ObReferenceObjectByName (
&uniNtNameString,
OBJ_CASE_INSENSITIVE,
NULL,
,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID*)&KbdDriverObject
);
// 如果失败了就直接返回
if(!NT_SUCCESS(status))
{
DbgPrint("Couldn't get the MyTest Device Object\n");
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\n",pAttachedKbdDevice); UsingDeviceExt=(PBYTE)pUsingDeviceObject->DeviceExtension;
//遍历找到的端口驱动设备扩展下的每个指针
for (i=;i<;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\n",pTemp); pTemp = *(PVOID*)(UsingDeviceExt+);
if ((pTemp > KbdDriverStart)&&(pTemp < (PBYTE)KbdDriverStart+KbdDriverSize)&&MmIsAddressValid(pTemp))
{
//记录回调函数的地址
g_KbdCallBack.serviceCallBack = (KEYBOARDCLASSSERVICECALLBACK)pTemp;
g_KbdCallBack.bSearch=TRUE;
status=STATUS_SUCCESS;
DbgPrint("serviceCallBack :%8x\n",pTemp); DbgPrint("替换函数");
pOldFucAddr=(PVOID*)(UsingDeviceExt+);
InterlockedExchangePointer((PVOID*)(UsingDeviceExt+),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();
}

通过修改i8042prt端口驱动中类驱动Kbdclass的回调函数地址,达到过滤键盘操作的例子