VS挤房间探索(含源码)

发布时间:2025-12-09 19:31:27 浏览次数:5

最近在网上看到一个VS挤房器,就想自己也实现一下玩玩。
这里主要是对远程进程空间中的控件发送消息的知识。
算法流程:
1. 先找到VS窗口
2. 找到VS窗口中显示房间列表的SysListView32控件
3. 读取房间列表, 这里是跨进程读取,方法是对SysListView32控件发送消息
4. 创建2个线程
5. 线程1任务:模拟不停的双击,由于VS中进入房间是通过双击进行的
6. 线程2任务:关闭房间人满窗口及重试窗口,由于VS中进入房间时如果房间人满,会弹出一个窗口,这个窗口我们需要关闭,另外,我们挤同一个窗口时会告诉你稍后重试,这个窗口也需要关闭
7. 同时,线程中判断我们是否已经成功进入房间,如果未成功则继续挤,成功则退出线程

下面说一下几个技术细节:
1. 为顾及版本兼容性,查找VS窗口我并没有直接FindWindow(NULL,"VS竞技游戏平台 -- 测试版-2.7.6"), 而是先找到VS进程ID,然后查找进程内窗口名前2个字节为'VS'的窗口,该窗口即为VS的主窗口

2. 查找SysListView32控件时可以直接EnumChildWindows, 从所有的子窗口中找到一个名为List1的控件,当然也可以由窗口类名为SysListView32作为判断条件

3. 对SysListView32控件发送消息的时候涉及到进程界限的问题,对远程控件发送消息时使用的数据结构必须在远程进程空间内,而不能在本进程空间内。所有先OpenProcess, 并用VirtualAllocEx申请远程进程空间内的内存,然后WriteProcessMemory把消息参数写入目标进程内,然后
SendMessage, 再ReadProcessMemory把返回值读出来,这个不懂可以看看Windows核心编程。

4. 如何模拟鼠标的双击呢?我一开始想的是发送WM_NOTIFY消息,没有成功,后来找资料,才找到直接发送WM_LBUTTONDBLCLK, 不过前提是选中房间。如何选中房间呢,如果当前已经选中某房间,必须把该房间的选择取消,然后再选中别的房间。选中房间的方法是发送LVM_SETITEMSTATE消息。另外,获取当前已选中房间的序号是发送LVM_GETNEXTITEM消息,关闭窗口是发送(WM_KEYDOWN, VK_ESCAPE)消息。

5. 线程通信问题,我这里主要是设置了2个EVENT, 分别代表双击事件和杀窗口事件(这里的杀窗口是指按ESC键), 这2个线程的逻辑是先双击需要进入的房间那一栏,然后等待房间人满窗口和重试窗口,如果发现这2个窗口,就关闭窗口双击下一个房间,如果没有发现这2个窗口而且SendMessage(WM_LBUTTONDBCLK)已经返回,则表示成功挤入房间。

附我的源码:

#include <iostream>#include <windows.h>#include <commctrl.h>#include <TLHELP32.H>#include <vector>#include <iterator>using namespace std;//房间信息typedef struct tagROOMINFO {TCHAR roomname[100];TCHAR onlinenum[20];TCHAR level[20];TCHAR speed[20];} ROOMINFO;DWORDg_dwProcessID;HWNDg_hTargetWnd;HWNDg_hTargetList;HANDLE g_hProcess;LVITEM *g_rlvi;TCHAR *g_rstr;vector<HWND> g_vChildList;vector<ROOMINFO> g_vRoomInfo;volatile BOOL g_onScan;volatile BOOL g_onSending;volatile BOOL g_bFinish;volatile HWND g_hOtherWnd;//用于线程通信HANDLE hEventForKill; //杀掉HANDLE hEventForClick;DWORD GetNamedProcessID(TCHAR* strProcessName){HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);PROCESSENTRY32 pe;DWORD dwProcessID = 0;//找第一个进程BOOL flag = Process32First(hSnapshot, &pe);while(flag){if (lstrcmpi(pe.szExeFile, strProcessName) == 0){printf("ProcessID:%X EXE:%s/n", pe.th32ProcessID, pe.szExeFile);dwProcessID = pe.th32ProcessID;break;}flag = Process32Next(hSnapshot, &pe); //继续查找}CloseHandle(hSnapshot);return dwProcessID;}//查找窗口名前两个字节为'VS'的窗口,且该窗口所属进程为lParamBOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam){TCHAR str[101];DWORD pid;GetWindowText(hwnd, str, 100);if (str[0]=='V' && str[1]=='S'){GetWindowThreadProcessId(hwnd, &pid);if (pid == (DWORD)lParam){g_hTargetWnd = hwnd;return FALSE;}}return TRUE;}//查找目标窗口以外的窗口名为'VS**'的窗口BOOL CALLBACK EnumProcFindOther(HWND hwnd, LPARAM lParam){TCHAR str[101];DWORD pid;GetWindowText(hwnd, str, 100);if (str[0]=='V' && str[1]=='S'){GetWindowThreadProcessId(hwnd, &pid);if (pid==(DWORD)lParam && g_hTargetWnd!=hwnd){g_hOtherWnd = hwnd;return FALSE;}}return TRUE;}//列举所有的子窗口BOOL CALLBACK EnumProcList(HWND hwnd, LPARAM lParam){DWORD depth = (DWORD)lParam;g_vChildList.push_back(hwnd);//if (depth <= 3)//EnumChildWindows(hwnd, EnumProcList, (LPARAM)(depth+1));return TRUE;}BOOL InitRemote(){// 获取窗口PID、打开进程, 申请内存空间g_hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, g_dwProcessID);g_rlvi= (LVITEM*)VirtualAllocEx(g_hProcess, NULL, 512, MEM_COMMIT, PAGE_READWRITE);g_rstr= (TCHAR*)VirtualAllocEx(g_hProcess, NULL, 512, MEM_COMMIT, PAGE_READWRITE);return TRUE;}BOOL FreeRemote(){//释放远程内存VirtualFreeEx(g_hProcess, g_rlvi, 512, MEM_RELEASE);VirtualFreeEx(g_hProcess, g_rstr, 512, MEM_RELEASE);CloseHandle(g_hProcess);return TRUE;}//读取ListCtrlBOOL ReadTargetList(){g_vRoomInfo.clear();LVITEM lvi;TCHAR str[512];int count, i;ROOMINFO roominfo;lvi.cchTextMax=512;count = (int)::SendMessage(g_hTargetList, LVM_GETITEMCOUNT, 0, 0);printf("Records number: %d/n", count);for(i=0; i<count; i++){// 获取第一列记录lvi.iSubItem = 0;lvi.pszText = g_rstr;WriteProcessMemory(g_hProcess, g_rlvi, &lvi, sizeof(LVITEM), NULL);::SendMessage(g_hTargetList, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)g_rlvi);ReadProcessMemory(g_hProcess, g_rstr, str, 512, NULL);lstrcpy(roominfo.roomname, str);// 获取第二列记录lvi.iSubItem = 1;lvi.pszText = g_rstr;WriteProcessMemory(g_hProcess, g_rlvi, &lvi, sizeof(LVITEM), NULL);::SendMessage(g_hTargetList, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)g_rlvi);ReadProcessMemory(g_hProcess, g_rstr, str, 512, NULL);lstrcpy(roominfo.onlinenum, str);// 获取第三列记录lvi.iSubItem = 2;lvi.pszText = g_rstr;WriteProcessMemory(g_hProcess, g_rlvi, &lvi, sizeof(LVITEM), NULL);::SendMessage(g_hTargetList, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)g_rlvi);ReadProcessMemory(g_hProcess, g_rstr, str, 512, NULL);lstrcpy(roominfo.level, str);// 获取第四列记录lvi.iSubItem = 3;lvi.pszText = g_rstr;WriteProcessMemory(g_hProcess, g_rlvi, &lvi, sizeof(LVITEM), NULL);::SendMessage(g_hTargetList, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)g_rlvi);ReadProcessMemory(g_hProcess, g_rstr, str, 512, NULL);lstrcpy(roominfo.speed, str);g_vRoomInfo.push_back(roominfo);//printf(TEXT("%s/t%s/t%s/t%s/n"), roominfo.roomname, roominfo.onlinenum, roominfo.level, roominfo.speed);}return TRUE;}//选择某一项void SelItem(int nItem){//先取消当前选择项,然后选择项nItemLVITEM lvi;int nCurSel = ::SendMessage(g_hTargetList, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));memset(&lvi, 0, sizeof(&lvi));lvi.stateMask = LVIS_SELECTED;WriteProcessMemory(g_hProcess, g_rlvi, &lvi, sizeof(LVITEM), NULL);SendMessage(g_hTargetList, LVM_SETITEMSTATE, (WPARAM)nCurSel, (LPARAM)g_rlvi);memset(&lvi, 0, sizeof(&lvi));lvi.stateMask = LVIS_SELECTED;lvi.state = LVIS_SELECTED;WriteProcessMemory(g_hProcess, g_rlvi, &lvi, sizeof(LVITEM), NULL);::SendMessage(g_hTargetList, LVM_SETITEMSTATE, (WPARAM)nItem, (LPARAM)g_rlvi);}DWORD DoubleClkItem(int nItem){//选择该项,并发送左键双击消息SelItem(nItem);return SendMessage(g_hTargetList, WM_LBUTTONDBLCLK, MK_LBUTTON, 0);}DWORD SelNextItem(){//向下移动一项,方式是模拟按下键盘的VK_DOWNSendMessage(g_hTargetList, WM_KEYDOWN, VK_DOWN, 0);return SendMessage(g_hTargetList, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));}//线程函数1,不停的发送双击消息DWORD WINAPI ThreadProc1(LPVOID lpParam){printf("Now starting to get into the room.../n");int nCurSel = ::SendMessage(g_hTargetList, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));if (nCurSel == -1)nCurSel = 0;g_bFinish = FALSE;while (g_onScan){g_onSending = TRUE;SetEvent(hEventForClick);DoubleClkItem(nCurSel);g_onSending = FALSE;//等待ESC按键, 关掉重试窗口或房间满人窗口WaitForSingleObject(hEventForKill, INFINITE);ResetEvent(hEventForKill);if (g_bFinish){printf("We've got into the room!/n");}if (!g_onScan){break;}Sleep(800);nCurSel = SelNextItem();}return 0;}//线程函数2,关掉重试窗口或房间人满窗口DWORD WINAPI ThreadProc2(LPVOID lpParam){BOOL bFlag;while (g_onScan){WaitForSingleObject(hEventForClick, INFINITE);ResetEvent(hEventForClick);//在双击消息还没有返回之前,寻找需要关闭的窗口while (g_onSending){g_hOtherWnd = 0;bFlag = EnumWindows(EnumProcFindOther, (LPARAM)g_dwProcessID);if (!bFlag && g_hOtherWnd!=0){printf("Send Escape Message!/n");Sleep(800);PostMessage(g_hOtherWnd, WM_KEYDOWN, VK_ESCAPE, 0);break;}}//如果双击消息返回了,而且没有找到其他窗口,说明成功挤入房间if (!g_onSending && bFlag){g_onScan = FALSE;g_bFinish = TRUE;}SetEvent(hEventForKill);}return 0;}int main(){g_dwProcessID = GetNamedProcessID(TEXT("VSClient.exe"));BOOL bFlag = EnumWindows(EnumProc, (LPARAM)g_dwProcessID);TCHAR str[300];if (g_dwProcessID!=0 && !bFlag)printf("Target ProcessID: %X , Target Window: %X/n", g_dwProcessID, g_hTargetWnd);else{printf("We have not found the VSClient window!/n");return -1;}g_vChildList.clear();EnumChildWindows(g_hTargetWnd, EnumProcList, 0);vector<HWND>::iterator ii;for (ii=g_vChildList.begin(); ii!=g_vChildList.end(); ii++){GetWindowText(*ii, str, 300);if (lstrcmpi(str, TEXT("List1")) == 0){g_hTargetList = *ii;printf("We've find the list, list hwnd = 0x%x/n", g_hTargetList);break;}}getchar();InitRemote();ReadTargetList();g_onScan = TRUE;HANDLE hThread[2];hEventForKill = ::CreateEvent(NULL, TRUE, FALSE, "EventForKill");hEventForClick = ::CreateEvent(NULL, TRUE, FALSE, "EventForClick");hThread[0] = CreateThread(NULL, 0, ThreadProc1, 0, 0, NULL);hThread[1] = CreateThread(NULL, 0, ThreadProc2, 0, 0, NULL);WaitForMultipleObjects(2, hThread, TRUE, INFINITE);CloseHandle(hEventForKill);CloseHandle(hEventForClick);CloseHandle(hThread[0]);CloseHandle(hThread[1]);FreeRemote();return 0;}

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477