我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++微信多开的实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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
已在三台电脑上测试(物理机)
理论上应该是所有版本的微信都能用 (只要这个互斥体的字符串不变)

缺点:直接修改了微信进程中的资源


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++ 微信多开的实现的文章就介绍到这了,更多相关C++ 微信多开内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++微信多开的实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

WeChaTextension如何实现微信消息防撤回及微信多开

这篇文章将为大家详细讲解有关WeChaTextension如何实现微信消息防撤回及微信多开,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。为您推荐WeChatExtension mac版。We
2023-06-03

在电脑上如何实现微信多开

本篇内容介绍了“在电脑上如何实现微信多开”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!实现思路需要打开输入框并获取到输入的数量,这里使用in
2023-07-05

在电脑上实现微信多开的技巧教程

这篇文章主要为大家介绍了在电脑上实现微信多开的技巧教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-06

Mac系统微信如何双开(多开)?Mac多开微信方法是什么?

有些朋友因工作关系,需要打开多个Mac版的微信,一个个人一个公司的,有些人会用第三方的微信(weweChat)来代替,或是安装其它的三方插件;其实不用第三方微信也可以实现mac微信双开,今天教程就告诉各位Mac多开微信方法,具体请参阅下面的
2023-06-04

python怎么实现微信钉钉等软件多开分身

今天小编给大家分享一下python怎么实现微信钉钉等软件多开分身的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。目前很多软件都
2023-06-29

电脑怎么开启多个微信

这篇文章主要介绍“电脑怎么开启多个微信”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“电脑怎么开启多个微信”文章能帮助大家解决问题。电脑开启多个微信的具体操作如下:1、桌面空白处,点击右键,在打开的菜
2023-06-27

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录