C++ 微信多开的实现

 更新时间:2022年02月16日 09:25:52   作者:乔安生  
本文主要介绍了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++ 微信多开的实现的文章就介绍到这了,更多相关C++ 微信多开内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用C++实现迷宫游戏

    使用C++实现迷宫游戏

    这篇文章主要为大家详细介绍了C++实现迷宫游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • 在C语言中输入中文字符串讲解

    在C语言中输入中文字符串讲解

    这篇文章主要介绍了在C语言中输入中文字符串讲解,本文通过概念和案例相结合讲述了如何在C语言中使用中文,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 深入解读C语言中的符号常量EOF

    深入解读C语言中的符号常量EOF

    这篇文章主要介绍了C语言中的符号常量EOF,文中还介绍了EOF的验证和打印方法,需要的朋友可以参考下
    2015-11-11
  • C++实现班级成绩管理系统

    C++实现班级成绩管理系统

    这篇文章主要为大家详细介绍了C++实现班级成绩管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C++ 重载运算符在HotSpot VM中的应用小结

    C++ 重载运算符在HotSpot VM中的应用小结

    C++支持运算符重载,对于Java开发者来说,这个可能比较陌生一些,因为Java不支持运算符重载,下面介绍一下HotSpot VM中的运算符重载,感兴趣的朋友跟随小编一起看看吧
    2023-09-09
  • 深入讲解Socket原理

    深入讲解Socket原理

    这篇文章深入的讲解Socket原理,并附带实例代码。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-12-12
  • 对for循环中表达式和循环体的执行顺序详解

    对for循环中表达式和循环体的执行顺序详解

    今天小编就为大家分享一篇对for循环中表达式和循环体的执行顺序详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06
  • C++ 实现带监视哨的顺序查找算法

    C++ 实现带监视哨的顺序查找算法

    这篇文章主要介绍了C++ 实现带监视哨的顺序查找算法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • C语言寻找无向图两点间的最短路径

    C语言寻找无向图两点间的最短路径

    这篇文章主要为大家详细介绍了C语言寻找无向图两点间的最短路径,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • C语言接口与实现方法实例详解

    C语言接口与实现方法实例详解

    这篇文章主要介绍了C语言接口与实现方法,包括接口的概念、实现方法及抽象数据类型等,并配合实例予以说明,需要的朋友可以参考下
    2014-09-09

最新评论