看流星社区

 找回密码
 注册账号
查看: 1827|回复: 0

驱动笔记15 - 键盘过滤驱动学习笔记

[复制链接]

该用户从未签到

发表于 2017-6-1 17:25:42 | 显示全部楼层 |阅读模式
键盘过滤驱动对于分层驱动的学习是一个很好的例子,它相对文件过滤驱动来说较为简单,也更容易理解。
并不是所有的驱动都需要直接访问硬件的,事实上几乎所有的硬件设备都存在着驱动程序链,最底层的驱动程序可以直接访问硬件,并对上层提供透明服务,最上层的驱动程序只要对接收到的数据进行过滤、格式化等处理即可,这样大大减少了开发的难度。
我这次学习的对象是KLOG,但我将它的代码进行了精简,这样使得它的工作流程更容易被看清楚。
首先看DriverEntry例程:


NTSTATUS
DriverEntry(
INPDRIVER_OBJECTpDriverObject,
INPUNICODE_STRINGRegistryPath
)
{
inti
=
0;
PDEVICE_EXTENSIONpKeyboardDeviceExtension;

for (i
= 0; i
< IRP_MJ_MAXIMUM_FUNCTION;i++)
{
pDriverObject->MajorFunction[i]= DispatchPassDown;
}

pDriverObject->MajorFunction[IRP_MJ_READ]= DispatchRead;
pDriverObject->DriverUnload= Unload;

// 开启记录
HookKeyboard(pDriverObject);

// 设置DEVICE_EXTERSION
pKeyboardDeviceExtension =(PDEVICE_EXTENSION)pDriverObject->DeviceObject->DeviceExtension;

returnSTATUS_SUCCESS;
}


很容易看懂,我就不多说了,其中DispatchPassDown仅仅将接收到的IRP转发给下一层设备,代码就不贴了。下面我们先来看其中的重头戏之一:HookKeyboard。


NTSTATUS
HookKeyboard(
INPDRIVER_OBJECTpDriverObject
)
{
NTSTATUSstatus;
PDEVICE_OBJECTpKeyboardDeviceObject;
PDEVICE_EXTENSIONpKeyboardDeviceExtension;
STRINGntNameString;
UNICODE_STRINGuKeyboardDeviceName;
CCHARntNameBuffer[64]
= "\\Device\\KeyboardClass0";

// 创建设备
status=IoCreateDevice(pDriverObject,
sizeof(DEVICE_EXTENSION),
NULL,
FILE_DEVICE_KEYBOARD,
0,
TRUE,
&amp;pKeyboardDeviceObject);
if (!NT_SUCCESS(status))
{
returnstatus;
}

pKeyboardDeviceObject->Flags
|= (DO_BUFFERED_IO |DO_POWER_PAGABLE);
pKeyboardDeviceObject->Flags
&amp;= ~DO_DEVICE_INITIALIZING;

// 设置DEVICE_EXTENSION
RtlZeroMemory(pKeyboardDeviceObject->DeviceExtension,sizeof(DEVICE_EXTENSION));
pKeyboardDeviceExtension =(PDEVICE_EXTENSION)pKeyboardDeviceObject->DeviceExtension;

// 绑定到设备
RtlInitAnsiString(&amp;ntNameString,ntNameBuffer);
RtlAnsiStringToUnicodeString(&amp;uKeyboardDeviceName,&amp;ntNameString,TRUE);
IoAttachDevice(pKeyboardDeviceObject,
&amp;uKeyboardDeviceName,&amp;pKeyboardDeviceExtension->pKeyboardDevice);
RtlFreeUnicodeString(&amp;uKeyboardDeviceName);

returnSTATUS_SUCCESS;
}


首先IoCreateDevice不用多说了,在任何一个驱动程序中都会见到,关键是下面的Flags设置和IoAttachDevice。我们创建了设备之后,需要将其加入到键盘的驱动程序链中,这个具体转化为代码就是将我们的设备Attatch到"\\Device\\KeyboardClass0"中(当然不一定非得是这个设备,挂这个设备的主要目的是为了能够动态卸载我们的驱动,因此不能挂接更上层的设备)。
为了得到按键操作的信息,我们发送一个IRP_MJ_READ到驱动的设备栈,由于此时还不一定有按键产生,于是驱动程序把这个IRP标记为pending状态,一旦有按键产生,则马上把这个IRP完成,所以我们需要在IRP_MJ_READ的处理例程中设置一个完成例程。(因为我们工作的异步模式下)




NTSTATUS
DispatchRead(
INPDEVICE_OBJECTpDeviceObject,
INPIRPpIrp
)
{
PIO_STACK_LOCATIONcurrentIrpStack;
PIO_STACK_LOCATIONnextIrpStack;


currentIrpStack =IoGetCurrentIrpStackLocation(pIrp);
nextIrpStack=IoGetNextIrpStackLocation(pIrp);
*nextIrpStack
= *currentIrpStack;
// 设置完成例程
IoSetCompletionRoutine(pIrp, OnReadCompletion, pDeviceObject, TRUE,TRUE, TRUE);

returnIoCallDriver(((PDEVICE_EXTENSION)pDeviceObject->DeviceExtension)->pKeyboardDevice,pIrp);
}



在这个完成例程OnReadCompletion中,我们就可以获取按键的信息了,代码如下所示:



NTSTATUS
OnReadCompletion(
INPDEVICE_OBJECTpDeviceObject,
INPIRPpIrp,
INPVOIDContext
)
{
PDEVICE_EXTENSIONpKeyboardDeviceExtension;
PKEYBOARD_INPUT_DATAkeys;
intnumKeys;
inti
=
0;

pKeyboardDeviceExtension =(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;

if (pIrp->IoStatus.Status== STATUS_SUCCESS)
{
keys =(PKEYBOARD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;
numKeys = pIrp->IoStatus.Information/
sizeof(KEYBOARD_INPUT_DATA);

for(i=
0; i
< numKeys; i++)
{
DbgPrint("ScanCode:%x\n",keys[i].MakeCode);

//if(keys[i].Flags == KEY_BREAK)
//DbgPrint("%s\n", "KeyUp");
//if(keys[i].Flags == KEY_MAKE)
//DbgPrint("%s\n", "Key Down");
}
}

if(pIrp->PendingReturned)
{
IoMarkIrpPending(pIrp);
}

return pIrp->IoStatus.Status;
}


不过这里我们获取到是只是按键的扫描码,如果想知道直观的按键信息,还需要写个函数进行处理,这里我就给省略了。虽然这个程序比起rootkit.com上面那个KLOG简单的多,使得它的流程更加清楚,也更容易理解,但它不实用。
为什么呢?因为实用的键盘记录器应该能够将按键信息保存起来,这里我们只能通过DbgView来看到按键信息。但由于这个完成例程的IRQL为DISPATCH,不能进行文件操作,因此在KLOG的代码中是首先创建一个线程,然后在线程中进行保存操作,因为线程函数工作在PASSIVE,允许处理文件。
一旦涉及到线程和文件操作就变得麻烦多了,关于这点可以通过KLOG的代码看出来,其实也不难,就是需要考虑的东西较多而已。
最后说一下,这个程序还有一个BUG,就是在卸载的时候再有按键就会BSOD,因为在我们卸载驱动的时候,还有很多IRP处于pending状态,当我们被卸载后,再有按键操作,IRP返回后却找不到对应的驱动,就会造成蓝屏的后果。
关于这个问题,网上有很多文章都介绍了介绍的办法,我也没有实验过,就不废话了。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 10:21

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表