最小密钥记录器使用 RAWINPUT






4.71/5 (7投票s)
这是“使用RAWINPUT的最小键盘记录器”的VB.NET和C#版本。
引言
如果您正在寻找阅读材料,您应该访问主要文章。这是一篇简短的替代文章,其中包含仅在此处提供的下载。提供了完整的C#和完整的VB.Net软件版本。
据我所知,这是地球上唯一一款托管的极简Raw Input键盘记录器。如果还有其他,请评论在哪里可以下载。另外,据我所知,这是唯一一款可以正确编译64位平台的Raw Input库;如果您知道其他,请再次评论。
我知道这篇文章很短,但主要文章中已经说过一切。我写这篇文章是为了发布您在这里找不到的源代码。
我知道许多VB.Net和C#编码员可能曾尝试从原始文章中的非托管版本中重建此项目,但都未成功。大多数C#的Raw Input库都包含多个缺陷,并且关于在C#或VB.NET中创建极简消息窗口的信息并不直观。
背景
我还没有遇到过可以正确编译64位版本的C# Raw Input库。我还没有遇到过任何VB.Net库;如果您知道任何,请评论并留下下载链接。这些Raw Input类同时存在于这两种语言中,并且可以正确编译64位平台和32位平台。如果您阅读了原始文章,您就能从中推断出托管代码的许多相似之处。
键盘记录是指监视和记录键盘上按键和释放的动作。具有键盘焦点的应用程序在每次按下键时都会收到一条消息。在释放键时(按键抬起)会收到一条单独的消息。当您按住一个键时,应用程序可能会收到多个按键消息。应用程序通过一个名为“WndProc
”的特定方法接收按键和按键抬起消息(以及其他输入消息,如鼠标输入)。每个能够接收这些消息的窗口都有一个“WndProc
”方法。
传统的键盘记录器(不使用Raw Input的)会安装一个全局钩子。如果您不熟悉全局钩子,可以进行研究。但让我们承认,这可能会影响您机器的性能,特别是如果操作不当。Raw Input是一种完全不同的技术。当您可能拥有多个键盘或输入设备,并且试图保持日志的可读性时,Raw Input尤其有用。知道输入来自哪个设备非常方便。
Raw Input技术不是安装全局钩子,而是只需要创建一个极简窗口。它要求您这样做,因为您需要有一个具有“WndProc
”的窗口的窗口句柄。然后,您可以“注册”该句柄与RegisterRawInputDevices
,一旦您这样做了;该窗口将接收您注册接收的所有输入消息(传递给它的参数决定了您将接收哪些输入消息)。在本例中,键盘记录器注册以接收所有键盘输入。用多个键盘尝试会很有趣。与传统的键盘记录场景相比,这种Raw Input技术非常优雅。
要做到这一切,最困难的部分是拥有正确的结构和参数,以进行各种Raw Input原生调用。保持事情的极简和正确至关重要;大多数托管Raw Input库无法正确编译64位版本的原因是,不正确的结构由于额外的四个字节而变得臃肿(偏移量发生变化),或者比存储指针少四个字节。64位指针是8个字节;32位指针是4个字节。这就是为什么在参数和结构中使用指针(System.IntPtr
)并在正确的位置使用整数,而不是混淆两者的重要性。通常,在32位版本上,您可能会混淆两者,因为它们都是四个字节。但当您编译64位版本时,调用将变得不可预测。
事实上,我可以在这里写上亿个段落;但您通过使用代码并自己理解源代码会学到更多。设置断点,亲自看看发生了什么。甚至更好;改变它,修改它,改进它,添加它,评论它,并享受它。
使用代码
下面的代码演示了初学者在尝试自己移植代码时可能面临的最困难的挑战之一。那就是我们如何为WNDCLASS
所需的hInstance
进行封送,还要注意New IntPtr(-3)
是HWND_MESSAGE
(它告诉CreateWindowEx
创建一个仅消息窗口)。
Dim msg As New MSG
Dim wc As New WNDCLASS
Dim hInstance As System.IntPtr = New System.IntPtr(System.Runtime.InteropServices.Marshal.GetHINSTANCE(_
System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32())
wc.lpfnWndProc = AddressOf WndProcCallback
wc.hInstance = hInstance
wc.lpszClassName = "SimpleMessageWindow"
RegisterClass(wc)
m_handle = CreateWindowEx(0, wc.lpszClassName, Nothing, 0, 0, 0, 0, 0, New IntPtr(-3), IntPtr.Zero, hInstance, 0)
MSG msg = new MSG();
WNDCLASS wc = new WNDCLASS();
System.IntPtr hInstance = new System.IntPtr(System.Runtime.InteropServices.Marshal.GetHINSTANCE(
System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32());
wc.lpfnWndProc = WndProcCallback;
wc.hInstance = hInstance;
wc.lpszClassName = "SimpleMessageWindow";
RegisterClass(wc);
m_handle = CreateWindowEx(0, wc.lpszClassName, null, 0, 0, 0, 0, 0,
new System.IntPtr(-3), System.IntPtr.Zero, hInstance, 0);
可下载的演示应用程序是整个项目的完整示例。
关注点
使用Raw Input很有趣,但它不提供检测焦点在哪个应用程序或控件上的方法。换句话说,我们知道一个键被按下或释放了,但原始消息发送到了哪个窗口(应用程序)?为了确定这一点,有几种技术可用。我自己使用的技术是使用SetWinEventHook
,但不要将其与SetWinEventHookEx
混淆。如果我能完成这篇文章,我将发布一篇关于如何使用SetWinEventHook
来收听系统事件(直接在您的托管应用程序中;这本应是“不可能”的)的技巧。不过,有一个系统事件(EVENT_OBJECT_FOCUS = 32773
)可以挂钩并获得键盘焦点更改的通知。这将消除每次想要知道哪个应用程序是键盘输入消息的原始目标时,都需要不断轮询GetForegroundWindow
的需要。希望我能尽快发布这个技巧并在此处链接。
历史
我希望这能激励更多的VB.Net和C#编码员利用Raw Input。我期待收到VB.Net和C#编码员的评论;其他所有人都可以评论原始文章;这只针对VB.Net和C#编码员。