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.商户后台在提交订单信息到银联后台 ...
随机推荐
- 【LeetCode】17. Letter Combinations of a Phone Number 电话号码的字母组合
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:电话号码, 字母组合,回溯法,题解,leetcode, ...
- 【LeetCode】166. Fraction to Recurring Decimal 解题报告(Python)
[LeetCode]166. Fraction to Recurring Decimal 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingz ...
- 「实用」打造自我感觉非常漂亮的Mac终端
背景 (今天我是一个美妆博主) 突然发现自己使用的iterm2终端样式有些朴素,为了让她看起来花枝招展的,我决定给她打扮打扮.毕竟每天面对她的时间比对象还多-- 效果对比 因为每个人的喜好都不一样,所 ...
- [炼丹术]UNet图像分割模型相关总结
UNet图像分割模型相关总结 1.制作图像分割数据集 1.1使用labelme进行标注 (注:labelme与labelImg类似,都属于对图像数据集进行标注的软件.但不同的是,labelme更关心对 ...
- Java初学者作业——编写 Java 程序,定义 Java 类 (Point) 用来表示坐标,坐标范围在(0,0)到(100,100)以内,并显示合法的坐标在控制台。
返回本章节 返回作业目录 需求说明: 编写 Java 程序,定义 Java 类 Point 用来表示坐标,坐标范围在(0,0)到(100,100)以内,并显示合法的坐标在控制台. 实现思路: 定义 P ...
- ECMA-262规范定义的七种错误类型
第一种:Error 所有错误的基本类型,实际上不会被抛出. 第二种:EvalError 执行eval错误时抛出. 第三种:ReferenceError 对象不存在是抛出. 第四种: ...
- django中写入数据时给密码加密
方法一.在自定义的form表单中重写save方法: 方法二.使用信号量来实现 1. 在应用的模块下新建signal.py文件 2.编写回调函数,内容如下: 3. 在应用的app.py文件中的ready ...
- 痞子衡嵌入式:我入选了2021年度与非网(eefocus)星选创作者Top10
本周二「与非网」一个美女运营小姐姐加痞子衡微信,告知痞子衡评上了一个奖,让痞子衡把收件地址告诉她,她把证书寄过来. 昨天痞子衡收到了快递,拆开一看,原来是被评上了 与非网 2021 年度创作者,这个证 ...
- ElasticSearch的应用
一.介绍 全文检索技术: 分布式: Restful风格: 近实时搜索 二.部署 下载:https://thans.cn/mirror/elasticsearch.html 新建用户,并登录: 解压: ...
- Java 内幕新闻第二期深度解读
这是由 Java 官方发布,Oracle JDK 研发 Nipafx 制作的节目,包含 JDK 近期的研发进展和新特性展望和使用,这里加上个人译制的字幕搬运而来.我把 Nipafx 的扩展资料详细研读 ...