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

使用 WH_CALLWNDPROC Hook 自動關閉 IE 彈出式廣告視窗

     編輯:關於C++

需求分析

IE 瀏覽特定網站時會彈出廣告視窗,通常特徵為:

  • 視窗類別名為 IEFrame
  • 無選單列、工具列
  • 子視窗 WorkerW 設為不可見 (WS_VISIBLE 未設定)

利用 WH_CALLWNDPROC Hook 攔截 WM_SHOWWINDOW 訊息,檢測符合特徵的視窗並發送 WM_CLOSE 關閉。

DLL 端 Hook 回呼函數


LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode < 0) return CallNextHookEx(g_hHook, nCode, wParam, lParam);

    CWPSTRUCT* pCwp = (CWPSTRUCT*)lParam;
    if (!pCwp) return CallNextHookEx(g_hHook, nCode, wParam, lParam);

    // 僅處理視窗顯示訊息
    if (pCwp->message != WM_SHOWWINDOW) {
        return CallNextHookEx(g_hHook, nCode, wParam, lParam);
    }

    TCHAR szClass[128];
    GetClassName(pCwp->hwnd, szClass, 128);

    // 檢查是否為 IEFrame
    if (lstrcmpi(szClass, _T("IEFrame")) != 0) {
        return CallNextHookEx(g_hHook, nCode, wParam, lParam);
    }

    // 遍歷子視窗尋找 WorkerW
    HWND hChild = GetWindow(pCwp->hwnd, GW_CHILD);
    BOOL bClose = FALSE;

    while (hChild) {
        GetClassName(hChild, szClass, 128);
        if (lstrcmpi(szClass, _T("WorkerW")) == 0) {
            // 檢查可見性
            LONG style = GetWindowLong(hChild, GWL_STYLE);
            if (!(style & WS_VISIBLE)) {
                bClose = TRUE;  // 不可見的 WorkerW = 廣告視窗特徵
            }
            break;
        }
        hChild = GetWindow(hChild, GW_HWNDNEXT);
    }

    if (bClose) {
        PostMessage(pCwp->hwnd, WM_CLOSE, 0, 0);  // 非同步關閉,避免死結
    }

    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

EXE 端安裝/移除 Hook


// 全域變數
HHOOK g_hHook = NULL;

void InstallAdBlockHook() {
    HINSTANCE hDll = GetModuleHandle(_T("AdBlockHook.dll"));
    if (!hDll) return;

    HOOKPROC proc = (HOOKPROC)GetProcAddress(hDll, "CallWndProc");
    if (!proc) return;

    g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, proc, hDll, 0);  // 0 = 所有執行緒
}

void UninstallAdBlockHook() {
    if (g_hHook) {
        UnhookWindowsHookEx(g_hHook);
        g_hHook = NULL;
    }
}

// 程式啟動時呼叫 InstallAdBlockHook()
// 程式結束時呼叫 UninstallAdBlockHook()

關鍵 API 與常數

API/常數用途
WH_CALLWNDPROC攔截 SendMessage 發送的訊息 (同步,訊息進入目標視窗程序前)
CWPSTRUCTHook 回呼參數結構,含 hwnd, message, wParam, lParam
WM_SHOWWINDOW視窗顯示/隱藏時發送,wParam=TRUE 表示顯示
GetClassName取得視窗類別名稱
GetWindow / GW_CHILD / GW_HWNDNEXT遍歷子視窗
GetWindowLong / GWL_STYLE取得視窗樣式位元組
WS_VISIBLE視窗可見旗標 (0x10000000)
PostMessage / WM_CLOSE張貼關閉訊息,非同步避免阻塞 Hook 鏈

注意事項與限制

  • 僅針對 IE 經典模式:現代 Edge/Chrome 使用不同架構,此法不適用
  • 誤判風險:某些合法 IE 子視窗也可能符合特徵,建議加強檢查 (如視窗標題、URL)
  • 效能影響:全域 Hook 會增加所有 GUI 進程的訊息處理開銷
  • 64 位元 IE需編譯 64 位元 DLL,否則無法注入 64 位元進程
  • 更穩健方案:使用 IWebBrowser2 介面事件 (NewWindow2/3) 攔截導航,屬應用層解決方案

延伸應用

同樣架構可用於:

  • 自動填寫登入對話框
  • 攔截特定網站的彈出視窗
  • 記錄應用程式視窗建立/銷毀生命週期
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved