Windows 下的窗口是靠消息(Message)来驱动的。用户的操作由系统向程序发送消息,告诉程序用户做了什么操作。
情景
笔者使用 EasyConnect 连接自己学校内网。跑了服务需要一直保持与校园网的连接。EasyConnect 在检测到一段时间无流量/网络切换后会自动强制断开连接。
尝试
看到 EasyConnect 产品目录下有 LogoutTimeOut.exe,运行后发现就是断开提示信息。
立即联想到可以写一个程序替换,当 EasyConnect 客户端超时拉起此提示时,调用自己的程序然后重启 EasyConnect。在尝试后,发现会造成系统直接死机?(未深入研究)联想到深信服家产品普遍有“那种”背景,推测可能被检测了。
检测
接下来笔者立即想到可以循环遍历窗口句柄,然后模拟按钮点击事件解决。经过测试,此办法有效。以下附上代码:(编译环境:VS2015 64Bit, 运行环境:Windows Server 2003 R2 X64 SP2)
#include "stdafx.h" #include <iostream> #include "tchar.h" #include "Windows.h" int main() { ::SetConsoleTitle(_T("iEdon Sangfor EasyConnect Auto Reconnect Utility")); ::system("color 2b"); while (true) { ::system("cls"); std::cout << "[*] Finding EasyConnect Timeout window..." << std::endl; HWND hWnd = ::FindWindowEx(NULL, NULL, nullptr, nullptr); while (hWnd != NULL) { TCHAR *lptcWndName = new TCHAR[MAXBYTE]; ::GetWindowText(hWnd, lptcWndName, MAXBYTE); if (::_tcscmp(lptcWndName, _T("EasyConnect")) == 0) { std::cout << "[*] Found parent window, matching child window... "; HWND hWndChild = ::GetWindow(hWnd, GW_CHILD); if (hWndChild) { TCHAR *lptcBtnName = new TCHAR[MAXBYTE]; ::GetWindowText(hWndChild, lptcBtnName, MAXBYTE); if (::_tcscmp(lptcBtnName, _T("重新登录")) == 0) { std::cout << "Found" << std::endl; std::cout << "[*] Simulating button click..." << std::endl; ::SendMessage(hWndChild, WM_SETFOCUS, NULL, NULL); ::Sleep(100); ::SendMessage(hWndChild, WM_KEYDOWN, VK_SPACE, NULL); ::Sleep(100); ::SendMessage(hWndChild, WM_KEYUP, VK_SPACE, NULL); ::SendMessage(hWndChild, BM_CLICK, NULL, NULL); } else { std::cout << "Not Found" << std::endl; } delete[] lptcBtnName; } else { std::cout << "Not Found" << std::endl; } } delete[] lptcWndName; hWnd = ::FindWindowEx(NULL, hWnd, nullptr, nullptr); } ::Sleep(5000); } return 0; }
经测试,可以自动重新连接。
Leave a Reply