码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-04-24 16:12:54      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:

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

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

//替换分发函数  来实现过滤
#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 = 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\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,
    0,
    *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, 
    0, 
    *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=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\n",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\n",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(); 
}

技术分享

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

标签:

原文地址:http://www.cnblogs.com/zwt1234/p/4453597.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!