Ring3层键盘记录的实现
    本文主要论述、对比了用户层主要的三种实现键盘记录的方法:利用钩子函数、轮询键盘消息和直接从输入设备获取数据。
在木马程序中,键盘记录是不可缺少的一部分,因为它是窃取别人电脑上数据的关键部分,记录这些程序的账号、密码主要就是靠键盘记录实现的。然后再将获得的账号、密码发到某个指定的邮箱里或某个FTP或网站服务器上。 在用户层实现键盘记录远比在系统层实现简单,是比较常用的方法。
1、利用钩子函数
最简单的方法是使用SetWindowsHook函数。钩子(Hook),是Windows消息处理机制中的监视点,应用程序可以在这里安装一个监视函数以监视指定进程(本进程或其它进程都可以)发生的事件。当监视的事件消息到达后,钩子函数可以在目标窗口处理函数之前处理它。

1.1 Hook的分类
总的来说, Hook可以分为Local Hook (本地钩子) ,和Remote Hook (远程钩子) 。Local Hook对本进程中发生的事件进行监视,对系统的影响比较小;而Remote Hook则可以对其他进程中发生的事件进行监视,针对整个系统的事件进行拦截。RemoteHook又可以分为Thread Hook (线程钩子)和GlobalHook (全局钩子) 。线程钩子能够监视系统内其他进程中指定线程的事件(此时该Hook函数可以放置在DLL中,也可以放置在应用程序的模块段) ;而全局钩子能够监视系统内所有进程空间地址中所有线程的事件(此时该Hook 函数必须放置在DLL中) 。

1.2 Hook的实现方法
1.2.1安装和卸载Hook的方法
利用Ap i函数HHOOK SetWindowsHookEx ( int idHook, HOOKPROC lpfn, H INSTANCE hMod,DWORD dwThread Id) ,进行钩子的安装。
其中:第一个参数为指定钩子的类型(共15种);第二个参数为标识Hook函数的入口地址;第三个参数为钩子函数所在模块的句柄,如果是Local Hook,此值为0;第四个参数为希望挂钩线程的线程ID,为0时则拦截整个系统的消息。
SetWindowsHookEx总是将我们的Hook函数放置在挂接函数链的顶端,使得应用程序接收到相应消息时,我们的Hook函数能第一个被调用。Hook函数必须按照回调函数的格式声明:LRESULT W INAP I HookProc ( int nCode,WPARAM wParam,LPARAM lParam)。其中nCode指定Hook类型, wParam, iParam的取值随nCode 不同而不同,它代表了某种类型的Hook的某个特定动作。如果Hook函数需要将消息传递给下一个过滤函数, 则在该Hook 函数返回前还需要调用一次CallNextHookEx( )函数。
利用Ap i 函数BOOL UnHookWindowsHookEx(HHOOK hHook)卸载钩子。

1.2.2 利用键盘钩子监控系统键盘输入实现过程
1)使用MFC AppW izard (DLL)建立扩展动态链接库KeyboardHook. dll
2)在KeyboardHook. h中添加导出函数InstallHook。
原型为__declspec ( dllexport) void W INAP I  InstallHook ( ) ,以后在应用程序中调用此函数就能安装一个全局键盘钩子。
3)在Keyboard. cpp中添加全局变量Hook和全局函数HookProc ( ) 、SaveKeyboardLog ( ) 分别实现处理与保存。
4)最后调用UninstallHook ( )卸载钩子
5)编写应用程序调用KeyboardHook.dll。先调用动态链接库的InstallHook函数安装好钩子,此时即可对系统下的键盘消息实施拦截处理。使用完毕后,通过动态链接库中的UninstallHook函数卸载键盘钩子。
这种键盘记录十分简单。隐蔽性较差。功能也不强,不能记录虚拟键盘的输入。

2.GetAsyncKeyState
利用GetAsyncKeyState实现键盘记录也十分简单,这个函数根据虚拟键表判断按键类型。返回值为一个16位的二进制数,如果被按下则最高位为1,即返回-32767,但是如果需要对键盘进行全局性的记录,则需要与另 一个API函数GetKeyState配合使用才能实现。原因在于GetAsyncKeyState函数只在按键的瞬间执行一次,如果按下的键是开关键 (如:caps lock),那么过了那一瞬间GetAsyncKeyState函数则不起任何作用。而这个时候就需要用GetKeyState来判断该开关键是否按下。因为每个键的虚拟码是唯一,在这样一种情况下,不管在大写情况还是小写情况下,按下的键记录下来的信息都是一样的。这个时候就需要一次判断,需要判断有两个键是否按下,一个是caps lock是否按下,一个是shift是否按下,因为shift不属于开关键,那它自然就不需要GetKeyState函数,但是caps lock是一个开关键它在这种情况下就需要用GetKeyState函数。所以在这种特例下我们就需要用GetKeyState函数了。另外insert 这个键也是一种特例它也需要用GetKeyState函数来判断。
GetKeyState(int nKey)用法
经过验证,检查非锁定键(除去num lock,caps lock,scroll lock外)按下状态返回-127或-128,而且键值一定是键盘上刻的值(大写字母或数字,%¥#之类的和小写字母则不能识别),非按下状态则为0或 1。检查num lock,caps lock,scroll lock三个锁定键,锁定状态(键盘指示灯亮)返回1,否则返回0。
例如,不考虑其他因素,仅判断“A”键是否按下,大写键是否锁定可以这样实现:
if (GetAsyncKeyState('A') == -32767)
{
   if (GetKeyState(VK_CAPITAL)==1)  {log << "A";}
   else   {log << "a";}
 }
在轮询过程中,往往需要使用死循环while(1),此时为防止CPU利用过高,可以加入windows.h下的sleep函数来使程序暂停若干毫秒。
与HOOK函数相比使用这两个函数进行键盘记录虽然在程序上显的比较冗长,但是它却更加的简单,而且也不容易出现错误。而HOOK函数虽然使用起来,在代码上看起来可能比较简单,但是它却很容易暴露在杀毒软件的查杀之下。

3. GetRawInput
微软原来的鼠标键盘输入模型:
鼠标和键盘产生输入数据,系统中断去处理这些与设备信息相关的数据,让这些数据变得与设备无关。一个应用程序通过发送到他窗口的消息获取与设备无关的消息,例如WM_CHAR,WM_MOUSEMOVE
原始输入模型:
直接从设备获取数据并且可以根据他们的需要来获取。前提是一个应用程序想获取原始数据就必须注册他想要获取原始输入的那些设备,然后应用程序会收到WM_INPUT消息。
主要流程: 
1)向系统注册一个或者多个原始输入设备 
为了注册这个设备,一个应用程序首先必须创建一个指明他所希望接受设备类别的(top level collection—TLC)RAWINPUTDEVICE结构。TLC被定义成为UsagePage(设备类)和Usage(设备类内的具体设备)。例如为了从键盘获取原始输入,设置UsagePage = 1 and Usage = 6,应用程序调用RegisterRawInputDevice去注册这个设备。
  BOOL RegisitKeyBord(HWND hwnd)
{
   if(NULL == hwnd)
      return false;
   PRegisterRawInputDevices RegisterRawInputDevices = (PRegisterRawInputDevices)GetApiAdd("User32.dll", "RegisterRawInputDevices");
   if(NULL == RegisterRawInputDevices)
      return false;
   RAWINPUTDEVICE rid;
   rid.usUsagePage = 0x01;
   rid.usUsage = 0x06;
   rid.dwFlags = RIDEV_INPUTSINK;
   rid.hwndTarget = hwnd;
   return RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE));
}
应用程序可以注册系统当前没有的设备。当设备可用之后,Windows管理器会自动将原始输入数据发送到应用程序。应用程序可以调用GetRawInputDeviceList来获取系统中原始输入设备的列表。用GetRawInputDeviceList获取的hDevice,应用程序调用GetRawInputDeviceInfo获取设备信息。
2)在你注册的原始输入设备数据发生变化时,系统发送一个消息及新数据到你的进程 
3)调用GetRawInputData来获取这些数据 
部分代码:
case WM_INPUT:
     if(NULL == GetRawInputData)
     {
        DefWindowProc(hWnd, message, wParam, lParam);
        return 0;
     }      
     GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
     lpb = new BYTE[dwSize];
     if(lpb == NULL) 
     {
        DefWindowProc(hWnd, message, wParam, lParam);
        return 0;
     } 
     
     if(GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
        MessageBox(NULL, "GetRawInputData doesn't return correct size !", "Raw Input Test", 0);
     raw = (RAWINPUT*)lpb;
     if (raw->header.dwType == RIM_TYPEKEYBOARD) 
     {
      wsprintf(vk,"[%s]\r\n%s",&ti,GetKeyName(raw->data.keyboard.VKey))
     }
     delete[] lpb;

这类键盘监控程序比前面两种获取信息的能力要强,可以获取软键盘的输入。

4.汉字输入记录
1).先获取当前正在输入的窗口的输入法句柄
                    hIMC = ImmGetContext(hWnd);
2).将ImmGetCompositionString的获取长度设为0来获取字符串
       dwSize=ImmGetCompositionString(hIMC,GCS_RESULTSTR, NULL, 0);
 dwSize += sizeof(WCHAR); // 缓冲区大小要加上字符串的NULL结束符大小,
memset(lpstr, 0, 20);
3). 再调用一次.ImmGetCompositionString获取字符串
       ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);
现在lpstr里面即是输入的汉字了。
5.记录当前窗口
可以通过GetForegroundWindow函数来记录当前窗口。
  if ( prev == NULL)   
             {   
                 prev = GetForegroundWindow();   
                 GetWindowText(prev,ti,256);   
                 Writetitle();//写窗口名
                 Writefile();//写按键
             }   
     else if ( prev == GetForegroundWindow() )   
             { writefile(); }   
     else   {   
                prev = GetForegroundWindow();   
                GetWindowText(prev,ti,256);  
                 Writetitle();
                 Writefile();
             }

6.防范
由上面的介绍可以看出,除了对记录程序进行检测处理之外,软键盘可以在一定程度上提高安全性,但十分有限,比如对GetRawInput 类型的键盘记录就无能为力。

实际上,更为简单有效的方法是人为打乱输入顺序,例如,输入密码1234567,可以先输入12567,再用鼠标切换焦点位置输入34。此时键盘监控程序只会记录错误的结果1256734

http://www.pediy.com/kssd/pediy11/123117.html

3种简单的键盘记录简单介绍相关推荐

  1. 简单的键盘按键记录(无码)/虚拟地址转物理地址/生成随机字符串/计算字符串哈希

    最近看到 一个 样本 ,里面有键盘 按键记录的功能 ,而且 实现也比较 简单,运行 记录 的效果还 不错 .主要思路如下 : //假代码 int i=0;for(i=0;i<0x100;i++) ...

  2. 如何用FFmpeg编写一个简单播放器详细步骤介绍

    如何用FFmpeg编写一个简单播放器详细步骤介绍(转载) FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码.复用和解复用. ...

  3. Android自定义键盘的简单实现

    概述 突然发现好多软件都使用了自己定义的软键盘.自己就想着先把这块坑先踩踩把,以后掉坑的时候不至于帅的太惨.言归正传,对于自定义软键盘.需要用到系统提供的两个类:Keyboard和KeyboardVi ...

  4. 一个简单的键盘钩子程序(ZZZ)

    一个简单的键盘钩子程序 从哪儿抄来的忘了,不过写的很简单明了 实现适时监视键盘,并将按键信息保存在TXT文件中的程序         Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都 ...

  5. 一个简单的键盘钩子程序

    Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的.而钩子是Windows系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序 ...

  6. 使用NLog实现一个简单的日志记录(包含源代码)

    目前比较流行.net的Log框架是log4net,不过个人觉得log4net配置比较繁琐,这里我向大家推荐一个比较简单实用的log框架:NLog. 有兴趣的朋友可以到http://www.nlog-p ...

  7. Net Core平台灵活简单的日志记录框架NLog+Mysql组合初体验

    Net Core平台灵活简单的日志记录框架NLog初体验 前几天分享的"[Net Core集成Exceptionless分布式日志功能以及全局异常过滤][https://www.cnblog ...

  8. lfu算法实现java_LFU五种实现方式,从简单到复杂

    前言 最近刷力扣题,对于我这种 0 基础来说,真的是脑壳疼啊.这个月我估计都是中等和困难题,没有简单题了. 幸好,力扣上有各种大牛给写题解.看着他们行云流水的代码,真的是羡慕不已.让我印象最深刻的就是 ...

  9. hook:实现简单的键盘记录器

    说到hook技术,开始我真是一头雾水! 不久前看到一篇博客,实现 了一个简单的键盘记录器.我从中颇为受益!今天就来和大家分享一下我的一个小例子,并说说我的感悟! 首先就从main()函数开始吧,不过这 ...

最新文章

  1. python工作技巧_Python常用小技巧汇总
  2. pycharm专业版(window)安装
  3. 冲击波病毒攻击-《截获网站服务器数据》
  4. 【渝粤教育】国家开放大学2018年春季 0004-22T有机合成单元反应 参考试题
  5. SVN在vs2013中使用
  6. 动态PHP查看新闻,PHP_用文本文件实现的动态实时发布新闻的程序,动态实时发布新闻的程序,可 - phpStudy...
  7. MediaCoder压缩参数设置
  8. 用于微信小程序的图文编辑器
  9. Java工具类,随机生成(姓名,年龄,性别,密码,邮箱,地址,)
  10. 标题 青蛙跳杯子java_蓝桥杯 青蛙跳杯子
  11. tf.app.flags
  12. 深入探究802.11ac技术
  13. Nova8pro自动调节亮度忽亮忽暗问题
  14. 什么是nmap以及如何使用它
  15. sinon.js的spy、stub和mock
  16. Attention机制介绍(原理+代码)
  17. Missing Marketing Icon. iOS Apps must include a 1024x1024px Marketing Icon in PNG format. Apps that
  18. AdSense 介绍
  19. 时间都去哪了。。。。
  20. 自选股同步:文华财经、同花顺、大智慧、通达信

热门文章

  1. python爬虫实例网易云-爬虫实战(二) 用Python爬取网易云歌单
  2. 忘记了Windows系统的账号对应的密码的解决方案
  3. 强大的代码编档工具—Doxygen
  4. 《左耳听风》-ARTS-打卡记录-第十四周
  5. [量子计算]一种金融衍生品的蒙特卡洛定价量子算法。(Quantum algorithm for the Monte Carlo pricing of financial derivatives.)
  6. O(n)的时间复杂度求中位数
  7. Linux下终端输出重定向至剪贴板的方法
  8. Java求1000以内的水仙花数
  9. 热动力数据MATLAB代码分享
  10. altera fpga 型号说明_ALTERA的FPGA命名规则