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

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

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

//替换分发函数  来实现过滤
#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();
}

时间: 2024-10-07 13:33:33

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

通过修改CR0寄存器绕过SSDT驱动保护

为了安全起见,Windows XP及其以后的系统将一些重要的内存页设置为只读属性,这样就算有权力访问该表也不能随意对其修改,例如SSDT.IDT等.但这种方法很容易被绕过,我们只要将这些部分修改为可写属性就可以了,不过当我们的事情做完后记得把它们恢复为只读属性,不然会造成一些很难预料到的后果. cr0是系统内的控制寄存器之一.控制寄存器是一些特殊的寄存器,它们可以控制CPU的一些重要特性. 控制寄存器最初出现于低级的286处理器中,以前称之为机器状态字(machine status word),

微型驱动程序、微型端口驱动程序和驱动程序对

MSDN原文:https://msdn.microsoft.com/zh-cn/library/windows/hardware/hh439643(v=vs.85).aspx 微型驱动程序或微型端口驱动程序可以用作半个驱动程序对.诸如(微型端口.端口)的驱动程序对可以简化驱动程序开发.在驱动程序对中,一个驱动程序处理整个设备集合共同的常规任务,而另一个驱动程序处理特定于单个设备的任务.处理设备特定任务的驱动程序有多个名称,包括微型端口驱动程序.微型类驱动程序和微型驱动程序. Microsoft

(笔记)linux设备驱动--LED驱动

linux设备驱动--LED驱动 最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友一起学习技术,共同进步. 作者:liufei_learning(转载请注明出处) email:[email protected] IT学习交流群:160855096 转至:http://blog.csdn.net/liufei_learning/article/details/7025246 开发环

Windows系统修改远程端口批处理

Windows服务器默认端口为"3389",这一端口极易遭到黑客的扫描,一般装好服务器的系统后都会将系统的远程端口更改一下,这就需要在注册表中更改两个键的值,对于很多不知道的人或者说像省点事的话不如照着这个批处理文件来修改远程端口. 在桌面新建一个文本文档,将如下代码复制进去: @echo off color 0a ::技术支持韩阳修改 title 修改Windows 2003/2008远程桌面服务端口号 echo ***********************************

(转)驱动开发中使用安全字符串函数

参考链接:http://www.cppblog.com/aurain/archive/2009/09/27/97363.html 一.前言 大量的系统安全问题是由于薄弱的缓冲处理以及由此产生的缓冲区溢出造成的,而薄弱的缓冲区处理常常与字符串操作相关.c/c++语言运行库提供的标准字符串操作函数(strcpy, strcat, sprintf等)不能阻止在超出字符串尾端的写入. 基于Windows XP SP1以及随后的操作系统的Windows DDK版本提供了安全字符串函数(safe strin

windows 安装 wamp 小结 修改默认端口 修改默认目录

普及一下,wamp为windows下一键安装部署的php开发环境,包含(mysql apache php phpMyAdmin. 此贴参考了:http://blog.csdn.net/jj455909186/article/details/39253923 ==== 原帖内容 start ==== 安装目录 g:/wamp/www 现要修改为 d:/wamp/www 首先找到G:\wamp\bin\apache\apache2.4.9\conf\httpd.conf 大约在230行修改为 Doc

Ubuntu 修改tomcat端口

# vi /etc/default/tomcat6 按a进入编辑模式 AUTHBIND=yes  (默认为#AUTHBIND=no) 按Esc键退出编辑模式 :wq  (保存并退出) 然后再修改tomcat端口 # vi /etc/tomcat6/server.xml 按a进入编辑模式 <Connector port="80" protocol="HTTP/1.1"                connectionTimeout="20000&qu

linux中修改ssh端口和禁止root远程登陆设置

linux中修改ssh端口和禁止root远程登陆设置 查看下系统版本 [[email protected] ~]# cat /etc/redhat-release CentOS release 6.7 (Final) 修改配置文件 linux修改端口22vim /etc/ssh/sshd_config找到#port 22将前面的#去掉,然后修改端口 port 1234重启服务就OK了service sshd restart或/etc/init.d/ssh restart为增强安全先增加一个普通权

[转帖] 启动多个Tomcat 需要修改的端口

原址:http://blog.csdn.net/lnara/article/details/7687411 不知道朋友们 有没有遇到过 在一台机器 上启动多个Tomcat 的情况(别跟我说启动一个,里面多个项目就可以,这个我知道 ). 启动时会有商品冲突,需要修改Tomcat 的端口: 我用的是zip 版的 直接 解压 一共有3个: 修改 %TOMCAT_HOME%\conf 下的 server.xml 第一个: 修改http访问端口(默认为8080端口) <Connector port="