本文記錄一個實際需求:透過 MFC 程式尋找 QQ 聊天視窗(「發送訊息」、「查看訊息」),修改其按鈕、靜態文字、編輯框等控件屬性(如禁用發送按鈕、修改標題文字),並寫入登錄實現開機自啟,以達到「強制戒除 QQ 聊天」的效果。技術涉及視窗枚舉、控件子類化、跨進程視窗操作與登錄操作。
HWND WndHandle = ::FindWindow(NULL, "查看訊息");
::SetWindowText(WndHandle, "聊天真的很痛苦的呀"); // 修改視窗標題
// 禁用編輯框
HWND WndEdit = ::FindWindowEx(WndHandle, NULL, "Edit", "");
::EnableWindow(WndEdit, FALSE);
char buttoncaption[4][20] = {
"聊天記錄(&H)", "對話模式(&T)", "取消發送(&C)", "送訊息(&S)"
};
HWND button_c[6];
for (int i = 0; i < 4; i++) {
button_c[i] = FindWindowEx(WndHandle, NULL, "Button", buttoncaption[i]);
}
for (int i = 0; i < 4; i++) {
::EnableWindow(button_c[i], FALSE);
}
HWND static_c[11];
static_c[0] = NULL;
for (int i = 1; i < 11; i++) {
// 關鍵:第二參數傳入上一個找到的 HWND,避免重複返回同一控件
static_c[i] = FindWindowEx(WndHandle, static_c[i-1], "Static", NULL);
}
int static_index[4], n = 0;
for (int i = 1; i < 11; i++) {
char caption[100];
::GetWindowText(static_c[i], caption, 100);
// 保留不需修改的標籤:QQ#:、暱稱:、Email:、按ctrl+回車鍵發送訊息
if (strcmp(caption, "QQ#:") != 0 &&
strcmp(caption, "暱稱:") != 0 &&
strcmp(caption, "Email:") != 0 &&
strcmp(caption, "按ctrl + 回車鍵發送訊息") != 0) {
static_index[n++] = i;
}
}
char *s[4] = {"自定義文字1", "自定義文字2", "自定義文字3", "自定義文字4"};
for (int i = 1; i <= 4; i++) {
int index = static_index[i-1];
if (index >= 0 && index <= 10) {
int dlgindex = ::GetDlgCtrlID(static_c[index]);
::SetDlgItemText(WndHandle, dlgindex, s[i-1]);
}
}
::InvalidateRect(WndHandle, NULL, FALSE);
for (int i = 1; i <= 4; i++) {
::UpdateWindow(static_c[static_index[i-1]]);
}
char path[MAX_PATH];
::GetCurrentDirectory(MAX_PATH, path);
strcat(path, "\\戒掉qq聊天的壞習慣.exe");
LPBYTE path_set = pchar_To_LPBYTE(path);
DWORD type = REG_SZ;
DWORD cbdata = strlen(path) + 1;
HKEY hkey;
LPCTSTR data_set = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\";
long ret_0 = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_set, 0, KEY_ALL_ACCESS, &hkey);
long ret_1 = ::RegSetValueEx(hkey, "BadQQ", 0, type, path_set, cbdata);
::RegCloseKey(hkey);
LPBYTE CShitDlg::pchar_To_LPBYTE(char* str) {
LPBYTE lpb = new BYTE[strlen(str) + 1];
for (int i = 0; i < strlen(str); i++) lpb[i] = str[i];
lpb[strlen(str)] = 0;
return lpb;
}
| 難點 | 解決方案 |
|---|---|
| 跨進程操作 QQ 控件 | 使用 FindWindow/FindWindowEx 取得 HWND,直接呼叫 EnableWindow/SetWindowText 等 Win32 API,Windows 允許跨進程視窗操作(受 UIPI 限制,需相同或更高完整性等級) |
| 枚舉同類別名控件避免重複 | FindWindowEx(hParent, hChildAfter, ...) 第二參數傳入上一次找到的 HWND,實現迭代枚舉 |
| 修改對話框模板文字需重繪 | 修改後呼叫 InvalidateRect + UpdateWindow 強制重繪 |
| 登錄寫入需管理員權限 | HKLM 需管理員權限;若無權限可改寫 HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
此技術屬於「軟體行為修改/攔截」範疇,實際部署時必須:
- 取得使用者明確知情同意
- 提供完整的卸載/恢復機制
- 不得繞過系統安全機制(如 UAC、UIPI)
- 企業環境應透過群組原則、EDR 等正規管道管理軟體使用行為
本文僅供技術原理解析,請勿用於未經授權的軟體行為控制。