我自己在看《寒江独钓》这本书的时候,书中除了给出了利用过滤的方式来拦截键盘数据之外,也提到了另外一种方法,就是hook键盘分发函数,将它替换成我们自己的,然后再自己的分发函数中获取这个数据的方式,但是书中并没有明确给出代码,我结合书中所说的一些知识加上网上找到的相关资料,自己编写了相关代码,并且试验成功了,现在给出详细的方法和代码。

用这种方式时首先根据ObReferenceObjectByName函数来根据对应的驱动名称获取驱动的驱动对象指针。该函数是一个未导出函数,在使用时只需要先声明即可,函数原型如下:

NTSTATUS ObReferenceObjectByName(
PUNICODE_STRING ObjectName, //对应对象的名称
ULONG Attributes, //相关属性,一般给OBJ_CASE_INSENSITIVE
PACCESS_STATE AccessState, //描述信息的一个结构体指针,一般给NULL
ACCESS_MASK DesiredAccess, //以何种权限打开,一般给0如果或者FILL_ALL_ACCESS给它所有权限
POBJECT_TYPE ObjectType, //该指针是什么类型的指针,如果是设备对象给IoDeviceObjectType如果是驱动对象则给IoDriverObjectType
KPROCESSOR_MODE AccessMode, //一般给NULL
PVOID ParseContext, //附加参数,一般给NULL
PVOID *pObject //用来接收相关指针的输出参数
);

IoDeviceObjectType或者IoDriverObjectType也是未导出的,在使用之前需要先申明他们,例如

extern POBJECT_TYPE IoDriverObjectType;
extern POBJECT_TYPE IoDeviceObjectType;

然后将该驱动对象中原始的分发函数保存起来,以便在hook之后调用或者在驱动卸载时恢复

接下来hook相关函数,要截取键盘的数据,一般采用的是hook read函数

在read函数中设置IRP的完成例程,然后调用原始的分发函数,一定要注意调用原始的分发函数,否则自己很难实现类似的功能,一旦实现不了,那么Windows上的键盘功能将瘫痪。

在完成例程中解析穿回来的IRP就可得到对应键盘的信息。

下面是具体的实现代码

#define  KDB_DRIVER_NAME L"\\Driver\\KbdClass" //键盘驱动的名称为KbdClass

NTSTATUS ObReferenceObjectByName(
PUNICODE_STRING ObjectName,
ULONG Attributes,
PACCESS_STATE AccessState,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID ParseContext,
PVOID *pObject);
extern POBJECT_TYPE IoDriverObjectType;
PDRIVER_OBJECT g_pKdbDriverObj; //键盘的驱动对象,保存这个是为了在卸载时还原它的分发函数
PDRIVER_DISPATCH g_oldDispatch[IRP_MJ_MAXIMUM_FUNCTION+1];
int g_KeyCount = 0; //记录键盘IRP的数量,当键盘的请求没有被处理完成时不能卸载这个驱动
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
LARGE_INTEGER WaitTime;
int i = 0;
DbgPrint("KBD HOOK: Entry DriverUnload\n"); //等待5s
WaitTime = RtlConvertLongToLargeInteger(-5 * 1000000000 / 100);
//如果IRP没有被处理完成,等待5s再检测是否处理完成
while(0 != g_KeyCount)
{
KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
} for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
{
//还原对应的分发函数
g_pKdbDriverObj->MajorFunction[i] = g_oldDispatch[i];
}
}
NTSTATUS
c2cReadComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PUCHAR pBuffer;
ULONG uLength;
int i = 0; if(NT_SUCCESS(Irp->IoStatus.Status))
{
pBuffer = (PUCHAR)(Irp->AssociatedIrp.SystemBuffer);
uLength = Irp->IoStatus.Information; for(i = 0; i < uLength; i++)
{
//在完成函数中只是简单的输出了对应的16进制数
DbgPrint("cap2ctrl: Key %02x\r\n", pBuffer[i]);
}
} //每当一个IRP完成时,未完成的IRP数量都需要减一
g_KeyCount--; if(Irp->PendingReturned)
{
IoMarkIrpPending( Irp );
} return Irp->IoStatus.Status;
} NTSTATUS
c2cReadDispathc(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION pIroStack;
DbgPrint("Hook By Me!\n");
//每当进入这个分发函数时都需要将这个未完成IRP数量加一
g_KeyCount++;
//设置完成函数
//在这只能用这种方式,我自己试过用IoSetCompletionRoutine ,它注册的完成函数没有被调用,我也不知道为什么
pIroStack = IoGetCurrentIrpStackLocation(Irp);
pIroStack->Control = SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR|SL_INVOKE_ON_CANCEL;
pIroStack->CompletionRoutine = (PIO_COMPLETION_ROUTINE)c2cReadComplete; //调用原始的分发函数
return (g_oldDispatch[IRP_MJ_READ])(DeviceObject, Irp);
} NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
int i = 0;
PDRIVER_OBJECT pKbdDriverObj;
UNICODE_STRING uKbdDriverName;
NTSTATUS status; UNREFERENCED_PARAMETER(pRegistryPath);
DbgPrint("cap2ctrl: Entry DriverEntry\n"); RtlInitUnicodeString(&uKbdDriverName, KDB_DRIVER_NAME);
status = ObReferenceObjectByName(&uKbdDriverName, OBJ_CASE_INSENSITIVE, NULL, 0, IoDriverObjectType, KernelMode, NULL, &g_pKdbDriverObj);
if(!NT_SUCCESS(status))
{
return status;
} //保存原始的派遣函数
for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION+1; i++)
{
g_oldDispatch[i] = g_pKdbDriverObj->MajorFunction[i];
} //HOOK读请求的派遣函数
g_pKdbDriverObj->MajorFunction[IRP_MJ_READ] = c2cReadDispathc; pDriverObject->DriverUnload = DriverUnload; //绑定设备
return STATUS_SUCCESS;
}

hook键盘驱动中的分发函数实现键盘输入数据的拦截的更多相关文章

  1. 为什么linux驱动中变量或者函数都用static修饰?(知乎问题)

    static定义的全局变量 或函数也只能作用于当前的文件. 世界硬件厂商太多,定义static为了防止变量或 函数 重名,定义成static, 就算不同硬件驱动中的 变更 或函数重名了也没关系 .

  2. 《寒江独钓_Windows内核安全编程》中修改类驱动分发函数

    最近在阅读<寒江独钓_Windows内核安全编程>一书的过程中,发现修改类驱动分发函数这一技术点,书中只给出了具体思路和部分代码,没有完整的例子. 按照作者的思路和代码,将例子补充完整,发 ...

  3. 4.5 HOOK分发函数

    4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...

  4. [内核编程] 4.5 HOOK分发函数

    4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...

  5. 【驱动】USB驱动实例·串口驱动·键盘驱动

    Preface   USB体系支持多种类型的设备. 在 Linux内核,所有的USB设备都使用 usb_driver结构描述.    对于不同类型的 USB设备,内核使用传统的设备驱动模型建立设备驱动 ...

  6. 【驱动】USB驱动实例·串口驱动·键盘驱动【转】

    转自:http://www.cnblogs.com/lcw/p/3159370.html Preface USB体系支持多种类型的设备. 在 Linux内核,所有的USB设备都使用 usb_drive ...

  7. Linux设备驱动中的阻塞和非阻塞I/O

    [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到 ...

  8. 蜕变成蝶~Linux设备驱动中的阻塞和非阻塞I/O

    今天意外收到一个消息,真是惊呆我了,博客轩给我发了信息,说是俺的博客文章有特色可以出本书,,这简直让我受宠若惊,俺只是个大三的技术宅,写的博客也是自己所学的一些见解和在网上看到我一些博文以及帖子里综合 ...

  9. linux内核驱动中对字符串的操作【转】

    转自:http://www.360doc.com/content/12/1224/10/3478092_255969530.shtml Linux内核中关于字符串的相关操作,首先包含头文件: #inc ...

随机推荐

  1. zookeeper web ui--&gt;node-zk-browser安装

    眼下公司正在使用zookeeper做配置管理和其它工作,在网上找几个zookeeper管理工具,都不尽人意,要么功能不够强大,要么不能友好的浏览zk树形结构.我的想法是zk管理工具,应该有一个树形结构 ...

  2. Spring Boot-------热部署

    热部署 热部署重要的是:添加一个jar包 第一步:在我们项目中的pom.xml文件中添加spring-boot-devtools这个jar包,Maven会帮我们自动下载的 <dependency ...

  3. 第五章 使用 SqlSession

    第五章 使用 SqlSession 原文链接; http://www.mybatis.org/spring/zh/sqlsession.html 在 MyBatis 中,你可以使用 SqlSessio ...

  4. JavaScript--AJAX页面传值

    1.首先 闲话不说 直接代码走起,都是我工作闲事的积累干货 //重要 js 运行 $(function (){ 代码 }); 2.ajax 传值 //第一种 输入框 <input type=&q ...

  5. 深入理解java虚拟机_前言

    2.JVM虚拟机 2.1  概述 java获得广泛认可主要是因为: (1)  java是一门结构严谨.面向对象的编程语言; (2)  java摆脱了硬件平台的束缚,实现了“一次编写,到处运行”的理想; ...

  6. 同时只允许Count个线程访问同一块区域的实现方式

    转载请注明出处. 好吧,后来才发现有Semaphore和SemaphoreSlim这两个类. 以前的答案: 最近.Net项目中用到了网页截图功能,这个截图功能是类似后台开了一个IE浏览器默默加载某个网 ...

  7. magento获取商品的图片

    获取商品的图片主要从catalog_product_entity_media_gallery 表中 该表中各列的属性代表 value_id:记录 ID,可以留空让数据库自动生成. attribute_ ...

  8. 基于 HTML5 WebGL 的 3D 场景中的灯光效果

    构建 3D 的场景除了创建模型,对模型设置颜色和贴图外,还需要有灯光的效果才能更逼真的反映真实世界的场景.这个例子我觉得既美观又代表性很强,所以拿出来给大家分享一下. 本例地址:http://www. ...

  9. bzoj 3551: [ONTAK2010]Peaks加强版

    Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来 ...

  10. KVM(一):KVM安装

    KVM通俗的说就是一台服务器当多台用,详细介绍去百度和谷歌. 首先查看服务器是否支持虚拟化 [root@KVM ~]# grep -E '(vmx|svm)' /proc/cpuinfo --colo ...