首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC++

免 DLL 全域鉤子實戰:WH_KEYBOARD_LL 低層鍵盤鉤子範例

     編輯:VC++

打破迷思:全域鉤子不一定需要 DLL

《Windows 核心程式設計》介紹三種代碼注入法,全域訊息鉤子是其中之一,普遍認為必須依賴 DLL。實則四種特殊鉤子可在安裝執行緒內文脈執行,無需 DLL:

  • WH_JOURNALPLAYBACK
  • WH_JOURNALRECORD
  • WH_KEYBOARD_LL (低層鍵盤)
  • WH_MOUSE_LL (低層滑鼠)

MSDN 說明:「This hook is called in the context of the thread that installed it.」 即鉤子程序在安裝執行緒上下文執行,無法達到代碼注入效果,故不需 DLL。

低層鍵盤鉤子完整範例 (主控台程式)

#define _WIN32_WINNT 0x0400
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

DWORD g_main_tid = 0;
HHOOK g_kb_hook = 0;

BOOL CALLBACK ConsoleHandler(DWORD) {
    PostThreadMessage(g_main_tid, WM_QUIT, 0, 0);
    return TRUE;
}

LRESULT CALLBACK KeyboardProc(int code, WPARAM w, LPARAM l) {
    PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)l;
    const char *info = NULL;
    if (w == WM_KEYDOWN) info = "key dn";
    else if (w == WM_KEYUP) info = "key up";
    else if (w == WM_SYSKEYDOWN) info = "sys key dn";
    else if (w == WM_SYSKEYUP) info = "sys key up";
    printf("%s - vkCode [%04x], scanCode [%04x]\n", info, p->vkCode, p->scanCode);
    return CallNextHookEx(g_kb_hook, code, w, l);
}

int main() {
    g_main_tid = GetCurrentThreadId();
    SetConsoleCtrlHandler(ConsoleHandler, TRUE);

    g_kb_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);
    if (!g_kb_hook) {
        fprintf(stderr, "SetWindowsHookEx failed: %d\n", GetLastError());
        return 0;
    }

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) { // 訊息迴圈必要 (MSDN)
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    UnhookWindowsHookEx(g_kb_hook);
    return 0;
}

關鍵點總結

  1. SetWindowsHookEx 第 3 參數 不可為 NULL (需 GetModuleHandle(NULL)),否則失敗
  2. 主控台程式必須有訊息迴圈 (GetMessage 迴圈),否則鉤子不會被呼叫
  3. WH_KEYBOARD_LL 可攔截系統層級鍵盤事件,適用於熱鍵、鍵盤記錄器等場景
  4. 同理 WH_MOUSE_LL 可實現免 DLL 全域滑鼠鉤子
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved