应用是如何判断多开
一、通过查找窗口标题或者类名来判断程序是否正在运行。
二、通过互斥对象确定程序是否运行,大多数软件都是使用CreateMutexW 判断多开的。
三、内存映射物理文件,控制多开。
微信是使用 CreateMutexW 函数判断多开的。
CreateMutexW 是如何判断多开的。
微软 MSDN 文档
CreateMutexW 这个函数就是根据变量创建一个锁,下回再用相同的变量调用CreateMutexW 的时候就可以控制是否允许多开。
如何找到微信中的 CreateMutexW 方法和互斥体
使用 procexp.exe 寻找互斥体,这个软件是微软官方出的 微软官网下载地址
登陆微信后
打开 Process Explorer
找到微信的进程 WeChat.exe
CTRL + L 查看微信这个进程占用的各种资源
根据这个字符串的名字判断出来的_WeChat_App_Instance_Identity_Mutex_Name 这个字符串就是微信的互斥体
找到 CreateMutexW 这个函数
使用 OD 直接在内存中找 CreateMutexW 方法,并调试 CreateMutexW 方法,手动修改互斥体,启动多个微信实例。
使用 OD 打开微信
CTRL + G 搜索 CreateMutexW 方法
跳转到 CreateMutexW 方法后,在这个位置打一个断点 F2
打完断点之后继续运行
在堆栈窗口可以看到 CreateMutexW 方法传递的三个参数
第一个参数:NULL
第二个参数:FALSE
第三个参数:_WeChat_App_Instance_Identity_Mutex_Name
获取到 _WeChat_App_Instance_Identity_Mutex_Name 这个互斥体在内存中的地址 02BBB198
使用 CE 修改 _WeChat_App_Instance_Identity_Mutex_Name 这个字符串
打开CE后选择进程
选择当前进程
选择微信进程
打开
点击 手动添加地址
输入互斥体的内存地址
选择字符串
字符串长度设置成110
勾选 Unicode
选择数值这列,双击 _WeChat_App_Instance_Identity_Mutex_Name
在弹框中修改一下这个字符串
内存修改完成,回到 OD
F2 取消断点
继续运行,直到打开一个微信
这个微信他身上的互斥体就是手动修改的那个字符串
通过正常途径在启动一个微信
正常启动
正常登陆
代码思路
思路
PC:启动微信到登陆页面(那个页面都行,只要微信进程起来就可以了)
代码:
一、提升当前进程权限,提升到最大
二、获取当前操作系统中指定的所有进程(多开的时候会有多个微信进程,进程名字是一模一样的)
三、获取到系统中所有资源(内存中的资源,包含 文件,路径,锁,事件,线程等等)
四、通过指定的进程和已找到的资源,匹配到防多开的那个互斥体
4.1 干掉这个互斥体
PC:可以正常启动下一个微信使用
启动微信后,如果想在启动一个微信,执行一遍代码就可以正常启动了
微信版本:3.4.5.27
已在三台电脑上测试(物理机)
理论上应该是所有版本的微信都能用 (只要这个互斥体的字符串不变)缺点:直接修改了微信进程中的资源
/* processName 微信进程名称 nutexName 微信互斥体字符串 */ void CloseMutex(const WCHAR* processName, const WCHAR* nutexName) { // 提升当前进程的访问权限 ElevatePrivileges(); // 找到所有的指定的进程 (多开的情况下会有多个) vectorpidList; pidList = GetProcessIdsByName((WCHAR*)processName); if (pidList.size() == 0) { // 没有开启或者没有找到指定的进程 return; } // 获取到操作系统所有进程的资源 LPVOID lp = GetSystemProcessHandleInfo(); // 遍历所有的指定进程 for (int i = 0; i < pidList.size(); i++) { // 遍历从系统中获取到的所有进程 与 指定进程进行匹配 // 遍历指定进程中的资源 // 找到互斥体 // 直接干掉这个互斥体 // 完成,后面就可以继续打开PC端微信了 EnumObjInfo(lp, pidList[i], processName); } }
提升权限
bool ElevatePrivileges() { HANDLE hToken = NULL; //打开当前进程的访问令牌 int hRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken); if (hRet) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; //取得描述权限的LUID LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //调整访问令牌的权限 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); CloseHandle(hToken); } return TRUE; }
根据进程名字,获取到系统中全部的进程信息
vectorGetProcessIdsByName(WCHAR* processName) { vector pidList; //HANDLE HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == FALSE) { return pidList; } PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); BOOL bRet = Process32First(hProcessSnap, &pe32); while (bRet) { if (wcscmp(pe32.szExeFile, processName) == 0) { pidList.push_back(pe32.th32ProcessID); } bRet = Process32Next(hProcessSnap, &pe32); } CloseHandle(hProcessSnap); return pidList; }
获取系统中的所有资源
LPVOID GetSystemProcessHandleInfo() { ULONG cbBuffer = 0x4000; LPVOID pBuffer = NULL; NTSTATUS sts; do { pBuffer = malloc(cbBuffer); if (pBuffer == NULL) { return NULL; } memset(pBuffer, 0, cbBuffer); hNtDLL = GetModuleHandle(TEXT("ntdll.dll")); if (!hNtDLL) return 0; ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION) GetProcAddress(hNtDLL, "ZwQuerySystemInformation"); sts = ZwQuerySystemInformation(SystemHandleInformation, pBuffer, cbBuffer, NULL); if (sts == STATUS_INFO_LENGTH_MISMATCH) { free(pBuffer); pBuffer = NULL; cbBuffer = cbBuffer + 0x4000; // 初始分配的空间不足+4000h } } while (sts == STATUS_INFO_LENGTH_MISMATCH); return pBuffer; }
匹配到互斥体,并干掉他
void EnumObjInfo(LPVOID pBuffer, DWORD pid, const WCHAR* processName) { char szType[128] = { 0 }; char szName[512] = { 0 }; DWORD dwFlags = 0; POBJECT_NAME_INFORMATION pNameInfo; POBJECT_NAME_INFORMATION pNameType; PSYSTEM_HANDLE_INFORMATION_EX pInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer; ULONG OldPID = 0; for (DWORD i = 0; i < pInfo->NumberOfHandles; i++) { if (OldPID != pInfo->Information[i].ProcessId) { if (pInfo->Information[i].ProcessId == pid) { HANDLE newHandle; NtQueryObject p_NtQueryObject = (NtQueryObject)GetProcAddress(hNtDLL, "NtQueryObject"); if (p_NtQueryObject == NULL) { return; } DuplicateHandle(OpenProcess(PROCESS_ALL_ACCESS, FALSE, pInfo->Information[i].ProcessId), (HANDLE)pInfo->Information[i].Handle, GetCurrentProcess(), &newHandle, DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_SAME_ACCESS); NTSTATUS status1 = p_NtQueryObject(newHandle, ObjectNameInformation, szName, 512, &dwFlags); NTSTATUS status2 = p_NtQueryObject(newHandle, ObjectTypeInformation, szType, 128, &dwFlags); pNameInfo = (POBJECT_NAME_INFORMATION)szName; pNameType = (POBJECT_NAME_INFORMATION)szType; if (strcmp(szName, "") && strcmp(szType, "") && status1 != 0xc0000008 && status2 != 0xc0000008) { if (wcsstr(pNameType->Name.Buffer, L"Mutant")) { pNameInfo = (POBJECT_NAME_INFORMATION)szName; pNameType = (POBJECT_NAME_INFORMATION)szType; if (wcsstr(pNameInfo->Name.Buffer, L"_WeChat_App_Instance_Identity_Mutex_Name")) { if (DuplicateHandle(OpenProcess(PROCESS_ALL_ACCESS, FALSE, pInfo->Information[i].ProcessId), (HANDLE)pInfo->Information[i].Handle, GetCurrentProcess(), &newHandle, 0, FALSE, DUPLICATE_CLOSE_SOURCE)) { CloseHandle(newHandle); }; } } } } } } }
到此这篇关于C++ 微信多开的实现的文章就介绍到这了,更多相关C++ 微信多开内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!