C++ 微信多开
应用是如何判断多开
一、通过查找窗口标题或者类名来判断程序是否正在运行。
二、通过互斥对象确定程序是否运行,大多数软件都是使用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();
// 找到所有的指定的进程 (多开的情况下会有多个)
vector<DWORD> pidList;
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;
}
根据进程名字,获取到系统中全部的进程信息
vector<DWORD> GetProcessIdsByName(WCHAR* processName) {
vector<DWORD> 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++ 微信多开的更多相关文章
- macOS 版微信小助手,支持微信多开、防撤回、远程控制mac、自动回复等等
微信小助手 GitHub大牛提供的微信小助手是一款插件,该插件具备多开.防撤回.免手机认证登录.自动回复.远程控制自己的 macOS.群发等众多功能 GitHub网址:https://github.c ...
- 微信多开脚本(Windows,Mac)
微信多开 以下内容仅用于学习使用.严禁用于非法用途,违者自负. Windows 多开 Windows 版本的微信在一些比较新的版本好像限制了多开,我们这里提供一个版本(也是官方的).https://p ...
- 目前用下来最溜的MacOS微信多开工具!
一个生活微信,一个工作微信是很多上班族的基本配置. 但由于微信客户端在PC端上只能打开一个,这使得在上班时候就非常不便,一个号在PC端上登录,一个在手机上使用,但是上班时候又不能一直看手机,不然老板还 ...
- .Net微信网页开发之JSSDK使用步骤和配置信息timestamp(时间戳),nonceStr(随机串),signature(签名),access_token(接口调用凭据)的生成获取讲解
前言: 因为接下来会有几篇关于微信JS-SDK功能使用的文章,主要会对微信分享,获取设备信息,获取地理位置,微信扫一扫这几个功能进行讲解.而这几个功能都是围绕着微信JS-SDK实现的,首先使用微信JS ...
- 微信多开简单实现 WeXinMoreOpen.bat
新建一个 WeXinMoreOpen.bat 文件,内容如下 @echo off D: cd "D:\Program Files (x86)\Tencent\WeChat" sta ...
- macOS 微信多开插件
macOS版本微信默认只能开一个,安装 WeChatTweak-macOS 插件即可实现多开. 效果图 安装步骤打开终端输入一下命令: git clone https://github.com/Sun ...
- PC微信多开
1.桌面上面新建一个 多开.txt . 2.将下面的内容拷贝进去 TASKKILL /F /IM wechat.exestart "" "E:\wechat\WeCha ...
- 微信企业号开发之weixin://preInjectJSBridge/fail
最近几天遇到个奇怪的问题,目前只有在Andriod平台上出现:weixin://preInjectJSBridge/fail 不止我一个人遇到这个问题,群里也有好几个问了这个问题.这个问题直接导致我们 ...
- iOS银联,支付宝,微信,ping++开发文档
银联支付 银联支付目测只需两个参数 1.tn 其实就是订单号 2.mode 是测试环境还是线上环境 开发步骤 1.首先客户端浏览商品,点击下单,请求到达商户后台 2.商户后台在提交订单信息到银联后台 ...
随机推荐
- 【九度OJ】题目1109:连通图 解题报告
[九度OJ]题目1109:连通图 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1109 题目描述: 给定一个无向图和其中的 ...
- Docker 与 K8S学习笔记(八)—— 自定义容器网络
我们在上一篇中介绍了Docker中三种网络,none.host和bridge,除了这三种网络,Docker还允许我们创建自定义网络,当我们要创建自定义网络时,Docker提供了三种网络驱动供我们选择: ...
- Java 将Excel转为OFD
OFD是一种开放版式文档(Open Fixed-layout Document )的英文缩写,是我国国家版式文档格式标准.本文,通过Java后端程序代码展示如何将Excel转为OFD格式.方法步骤如下 ...
- Java编程基础
JDK与JRE有什么区别 JDK:Java开发工具包(Java Development Kit),提供了Java的开发环境和运行环境. JRE:Java运行环境(Java Runtime Enviro ...
- Redis -使用 Bitmap
redis数据类型 String.Set.Zset.List.hash Bitmap . 四种统计类型: 二值状态统计: 聚合统计: 排序统计: 基数统计 二值状态统计: 就是集合中的元素 ...
- Oracle 11g安装和PL/SQL连接完全解读(连接本地数据库)
Oracle安装是很多新手都烦恼的事情,各种奇怪的错误,并且还无从下手解决.我也隔了两年没有用Oracle了,昨天安装了一下,出现很多问题,也很苦恼.现在将安装过程详细记录下来,一来方便自己下次安装, ...
- Gumbel distribution
目录 概 主要内容 定义 Gumbel-Max trick Gumbel trick 用于归一化 代码 概 感觉这个分布的含义很有用啊, 能预测'最大', 也就是自然灾害, 太牛了. 主要内容 定义 ...
- 一个老菜鸟的年度回忆 & 智能工厂奋斗的第三年,可能有你值得借鉴的
岁月蹉跎,寒冬的夜晚仍伏案疾书,见论坛中有诸多大神已经开始了一年的总结,突然安奈不住心中的躁动,也想为这今年的奋斗留下只言片语,没有年初的目标总结,没有未来的展望,就想作为一篇日记记录今年项目精力,为 ...
- element ui el-tree回显问题及提交问题(当后台返回的el-tree相关数组的时候,子菜单未全部选中,但是只要父级菜单的id在数组中,那么他的子菜单为全部选中状态)
1:问题原因:我们可能使用 this.$refs.tree.setCheckedKeys(this.defalutArr);或者使用:default-expanded-keys="treeD ...
- Android studio 报错 Unable to resolve dependency for ‘:app@releaseUnitTest/compileClasspath‘:
出现报错: Unable to resolve dependency for ':app@debugAndroidTest/compileClasspath': Could not find any ...