通过修改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 = ;
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的回调函数地址,达到过滤键盘操作的例子的更多相关文章
- Linux驱动 - SPI驱动 之三 SPI控制器驱动
通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...
- 利用模块加载回调函数修改PE导入表实现注入
最近整理PE文件相关代码的时候,想到如果能在PE刚刚读进内存的时候再去修改内存PE镜像,那不是比直接对PE文件进行操作隐秘多了么? PE文件在运行时会根据导入表来进行dll库的"动态链接&q ...
- 通过修改CR0寄存器绕过SSDT驱动保护
为了安全起见,Windows XP及其以后的系统将一些重要的内存页设置为只读属性,这样就算有权力访问该表也不能随意对其修改,例如SSDT.IDT等.但这种方法很容易被绕过,我们只要将这些部分修改为可写 ...
- 分享CCNTFS小工具,在 macOS 中完全读写、修改、访问Windows NTFS硬盘的文件,无须额外的驱动(原生驱动)更稳定,简单设置即可高速传输外接NTFS硬盘文件
CCNTFS [ 下载 ] 在 macOS 中完全读写.修改.访问Windows NTFS硬盘的文件,无须额外的驱动(原生驱动)更稳定,安装后进行简单设置即可高速传输外接NTFS硬盘文件,可全程离线使 ...
- liunx驱动----USB驱动
现象:把usb设备接入电脑 1.Windows发现设备 2.跳出一个对话框提示安装驱动程序 问1:既然没有驱动程序,为什么了够知道是什么驱动了?? 答1:Windows里面已经有了usb总线驱动程序, ...
- (笔记)linux设备驱动--LED驱动
linux设备驱动--LED驱动 最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友 ...
- 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl 0. 导语 在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后 ...
- Android驱动学习-app调用内核驱动过程(驱动框架回顾)
考研已经过去了,android驱动的学习也断了半年多了,现在重新捡起来学习,回顾一下Android驱动的大体框架. Android系统的核心是java,其有一个David虚拟机.Android-app ...
- Linux 驱动框架---驱动中的异步
异步IO是对阻塞和轮询IO的机制补充,所谓异步IO就是在设备数据就绪时主动通知所属进程进行处理的机制.之所以说是异步是相对与被通知进程的,因为进程不知道也无法知道什么时候会被通知:这一机制非常类似于硬 ...
随机推荐
- 【转】arm 开发工具比较(ADS vs RealviewMDK vs RVDS)
ADS REALVIEW MDK RVDS 公司 ARM Keil(后被ARM收购) ARM 版本 最新1.2 ,被RVDS取代 最新4.0 是否免费 破解情况 有 有 工程管理 CodeWarr ...
- 手把手教你玩转nginx负载均衡(四)--源码安装nginx
引言: 在上一篇,我们已经装好了虚拟机,并且已经配置好了网络,那么今天我们就要开始安装nginx服务器了. 安装工具以及过程 安装gcc编译套件以及nginx依赖模块 yum -y install g ...
- OC推箱子
#include<stdio.h> #include<stdlib.h> int main(void) { char sr;//存储用户输入的指令 //绘制地图 char a[ ...
- elasticsearch5.0.0 安装插件及配置过程
elasticsearch5.0.0 安装插件及配置过程 由于es5.0是里程碑式的更新,所以很多变化的地方,暂时我就插件安装遇到的问题记录一下. 插件安装命令 2.3版本的安装命令 安装Marvel ...
- ***PHP 数组排序 +php二维数组排序方法(PHP比较器)
PHP - 一维数组的排序函数 在本节中,我们将学习如下 PHP 数组排序函数: sort() - 以升序对数组排序 rsort() - 以降序对数组排序 asort() - 根据值,以升序对关联数组 ...
- SpringMVC(三) RequestMapping修饰类
SpringMVC使用@RequestMapping 注解为控制器指定可以处理哪些URL请求. 可以用于类定义以及方法定义: 类定义:提供初步的请求映射信息.相对于WEB应用的根目录. 方法处:提供进 ...
- 学习微信小程序之css3display
一display diaplay改变标签的模式,行内装块级(block),块级转行内(inline) 通过设置display为none,可以 让整个标签在页内移除掉 设置visibility为hidd ...
- Tomcat的粗略介绍
因为工作的缘故很多项目启动需要通过Tomcat修改配置文件进行启动项目,所以相应的就了解了下Tomcat便于在以后比我更新的新人面前装逼. 1.bin目录 我们能用到的无非一个启动跟一个关闭没什么好说 ...
- 转: Delphi的OverRide、OverLoad和Virtual方法
http://blog.csdn.net/ckli/article/details/2201418 override 重写 也叫覆盖 .方法的重写Overriding和重载Overloading是Ja ...
- RPC原理及RPC实例分析
在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 1 2 3 4 5 6 public class ...