我自己在看《寒江独钓》这本书的时候,书中除了给出了利用过滤的方式来拦截键盘数据之外,也提到了另外一种方法,就是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. Comparable和Comparator的差别

    原文地址:http://leihuang.org/2014/11/16/Comparable-Vs-Comparator/ Comparable和Comparator都是用来实现集合中元素的比較.排序 ...

  2. Office 365 机器人(Bot)开发入门

    作者:陈希章 发表于 2017年7月29日 前言 作为人工智能技术的一个主要的表现形式,这些年机器人(bot)的应用越来越广泛.不管是有实物的,还是纯软件的,现在的机器人技术应该说已经走入寻常百姓家了 ...

  3. ASP.NET Core 使用 Hangfire 定时任务

    定时任务组件,除了 Hangfire 外,还有一个 Quarz.NET,不过 Hangfire .NET Core 支持的会更好些. ASP.NET Core 使用 Hangfire 很简单,首先,N ...

  4. windows 下使用VMware Workstation Pro 工具,ubuntu创建虚拟机

    本文记录windows 下使用VMware Workstation Pro 工具,ubuntu创建虚拟机 的步骤 第一步 [文件] --- [新建虚拟机]   第二步 弹出的新建虚拟机向导对话框 标准 ...

  5. Tomcat配置(二):tomcat配置文件server.xml详解和部署简介

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  6. 《Java NIO (中文版)》【PDF】下载

    <Java NIO (中文版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062530 NIO (中文版)>[PDF]& ...

  7. plugins/python/uwsgi_python.h:2:20: fatal error: Python.h: No such file or directory

    装一台新服务器环境的时候,装uwsgi报错: plugins/python/uwsgi_python.h:2:20: fatal error: Python.h: No such file or di ...

  8. sql经典试题

    1.一道SQL语句面试题,关于group by表内容:2005-05-09 胜2005-05-09 胜2005-05-09 负2005-05-09 负2005-05-10 胜2005-05-10 负2 ...

  9. MyBatis小抄

    持续更新中. Every MyBatis application centers around an instance of SqlSessionFactory A cleaner approch t ...

  10. 由于DG Broker的配置导致RAC某实例无法mount

    今天碰到一个我自己实验室发生的故障,起初看起来很简单,但实际上还很有趣,而且不细心的话还容易被忽视掉.相信在生产环境也会有客户会实际遇到. 环境:Oracle 11.2.0.4 RAC (2 node ...