通过修改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就是在设备数据就绪时主动通知所属进程进行处理的机制.之所以说是异步是相对与被通知进程的,因为进程不知道也无法知道什么时候会被通知:这一机制非常类似于硬 ...
随机推荐
- 第一次使用UML的感觉
刚开始接触的时候,其实我内心是拒绝的,因为感觉这种软件之前接触过,觉得就是相当于思维导图那种的. 可当自己使用的时候,觉得大纲总体上是类似是规划方向的,可是细节却让人深思,用什么图标,特别是用什么线, ...
- 与你相遇好幸运,用sinopia搭建npm私服
需求: >在企业内部搭建私有npm服务器,企业开发人员上传下载自己开发的npm包 >私有npm服务器包不存在时,找npm或者taobao的镜像站点 >服务器硬盘有限,希望只缓存下载过 ...
- python map()
map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回. 举例说明,比如我们有一个函数f(x)=x%2,要把这个函数作用在一个li ...
- Java源码之 java.util.concurrent 学习笔记01
准备花点时间看看 java.util.concurrent这个包的源代码,来提高自己对Java的认识,努力~~~ 参阅了@梧留柒的博客!边看源码,边通过前辈的博客学习! 包下的代码结构分类: 1.ja ...
- Qt基本框架介绍
#include <QApplication>#include <QWidget> int main(int argc, char *argv[]){ QApplication ...
- 详解Eclipse断点
原文链接:http://www.blogjava.net/jiangshachina/archive/2011/11/20/364367.html 大家肯定都用过Eclipse的调试的功能,在调试的过 ...
- 《UML大战需求分析》阅读随笔(一)
UML:Unified Modeling Language(统一建模语言) 作为我专业学科里的一门语言,其目的就是交流,同客户交流,同自己交流. 用图像和文字,详细地讲解将要做的工程的 需求和功能细节 ...
- 高效快捷实用移动开单手持扫描打印一体智能 POS PDA
PDA数据采集器,是一款移动手持开单设备,它通过WIFI和GPRS连接并访问电脑,从进销存软件中读取数据,实现移动开单,打破电脑开单模式. 它自带扫描器,可直接扫描条码来查找产品,且功能强大.操作简单 ...
- 使用IntelliJ IDEA 配置Maven(入门)【转】
1.在IntelliJ IDEA中配置maven 打开-File-Settings 2.新建maven WEB项目 打开-File-New-Project 点击NEXT 点击NEXT 添加的配置 ...
- 关于null值的排序
关于空值null的排序问题 Oracle排序中NULL值处理的五种常用方法: 1.缺省Oracle在Order by 时缺省认为null是最大值,所以如果是ASC升序则排在最后,DESC降序则排在 ...