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

螢幕取詞技術原理:GDI Hook 截獲 TextOut/ExtTextOut 實現即時翻譯/字典

     編輯:VC 教學

核心原理

Windows 螢幕文字繪製最終均經由 GDI32.dll 核心函數:

  • TextOutA / TextOutW
  • ExtTextOutA / ExtTextOutW

取詞關鍵:**攔截這些函數調用,提取參數中的字串指標、座標、長度**。

三步驟實作架構

步驟 1:獲取滑鼠座標 → 目標視窗


// 全域鉤子 (WH_MOUSE) 記錄滑鼠位置
// 或定時器輪詢 GetCursorPos
POINT pt; GetCursorPos(&pt);
HWND hTarget = WindowFromPoint(pt);
if (!hTarget) return;
ScreenToClient(hTarget, &pt); // 轉客戶區座標

步驟 2:觸發目標視窗重繪


// 使目標區域失效,迫使 WM_PAINT → TextOut
InvalidateRect(hTarget, NULL, TRUE);
UpdateWindow(hTarget); // 同步發送 WM_PAINT

步驟 3:Hook GDI 函數截獲參數

3.1 定義 Hook 函數 (與原函數簽名完全一致)


// 原函數指標
typedef BOOL (WINAPI *PFN_TextOutA)(HDC, int, int, LPCSTR, int);
PFN_TextOutA g_RealTextOutA = NULL;

// Hook 函數
BOOL WINAPI MyTextOutA(HDC hdc, int x, int y, LPCSTR lpString, int c)
{
    // 1. 業務邏輯:記錄/翻譯/顯示提示
    if (lpString && c > 0) {
        String text(lpString, c); // 處理 ANSI 字串
        // 送往主程式顯示翻譯...
        PostMessage(g_hMainWnd, WM_USER_TEXTOUT, (WPARAM)hdc, (LPARAM)text.c_str());
    }
    // 2. 呼叫原函數保證正常繪製
    return g_RealTextOutA(hdc, x, y, lpString, c);
}

3.2 DLL 注入機制 (系統自動完成)

  • 鉤子 DLL 透過 SetWindowsHookEx 安裝時,系統將 DLL 映射到**所有受影響進程**的位址空間。
  • 進程載入 DLL 後,其導入表 (IAT) 中的 TextOutA 仍指向 GDI32,需進一步修改 IAT 或使用 Inline Hook。

3.3 IAT 修改實現 API 重導向


// 遍歷目標模組導入表,找到 gdi32.dll 的 TextOutA 項,修改函數指標
PIMAGE_IMPORT_DESCRIPTOR pImport = ...; // 定位 gdi32.dll 導入描述符
PIMAGE_THUNK_DATA pThunk = ...; // 遍歷 Thunk
while (pThunk->u1.Function) {
    if (IsTargetFunction(pThunk, "TextOutA")) {
        // 修改頁面保護
        MEMORY_BASIC_INFORMATION mbi;
        VirtualQuery(pThunk, &mbi, sizeof(mbi));
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect);
        // 保存原指標、寫入新指標
        g_RealTextOutA = (PFN_TextOutA)pThunk->u1.Function;
        pThunk->u1.Function = (DWORD)MyTextOutA;
        // 恢復保護
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &mbi.Protect);
        break;
    }
    pThunk++;
}

關鍵技術難點與對策

難點對策
Unicode/ANSI 混用同時 Hook TextOutW、ExtTextOutW,統一轉 UTF-16 處理
DirectWrite / GDI+ 繞過 GDI現代應用多用 DirectWrite,需額外 Hook IDWriteTextLayout::Draw 或使用 UI Automation
效能:頻繁調用導致卡頓快速判斷是否目標進程/視窗,非目標直接跳轉原函數;批次傳遞字串
64 位進程編譯 64 位 Hook DLL,或使用 Wow64 機制
安全軟體攔截簽名驗證、白名單、避免修改系統關鍵進程

現代替代方案:UI Automation


// 不需 Hook,直接查詢文字模式
IUIAutomation *pAuto; CoCreateInstance(CLSID_CUIAutomation, ..., &pAuto);
IUIAutomationElement *pElem; pAuto->ElementFromPoint(pt, &pElem);
IUIAutomationTextPattern *pTextPattern;
pElem->GetCurrentPattern(UIA_TextPatternId, (IUnknown**)&pTextPattern);
IUIAutomationTextRange *pRange; pTextPattern->DocumentRange(&pRange);
BSTR text; pRange->GetText(-1, &text); // 獲取完整文字
// 支援 Chrome, Edge, Office, WPF 等現代 UI

架構圖解


滑鼠移動 → Hook 記錄座標
      ↓
目標視窗 InvalidateRect → WM_PAINT
      ↓
目標進程呼叫 TextOutA (GDI32)
      ↓
Hook DLL (已注入) 截獲 MyTextOutA
      ↓
提取字串 → PostMessage 給主程式
      ↓
主程式顯示翻譯/字典視窗
      ↓
呼叫原 TextOutA 完成繪製

螢幕取詞 Hook 架構圖

GDI Hook 取詞是經典技術,但面對現代渲染引擎 (DirectWrite, GPU 加速) 效力遞減;新專案建議優先採用 UI Automation 或 OCR (Tesseract/Windows OCR API)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved