C++ 微信多开

应用是如何判断多开

一、通过查找窗口标题或者类名来判断程序是否正在运行。

二、通过互斥对象确定程序是否运行,大多数软件都是使用CreateMutexW 判断多开的。

三、内存映射物理文件,控制多开。

微信是使用 CreateMutexW 函数判断多开的。

CreateMutexW 是如何判断多开的。

微软 MSDN 文档

CreateMutexW 这个函数就是根据变量创建一个锁,下回再用相同的变量调用 CreateMutexW 的时候就可以控制是否允许多开。

如何找到微信中的 CreateMutexW 方法和互斥体

使用 procexp.exe 寻找互斥体,这个软件是微软官方出的 微软官网下载地址

C++ 微信多开

登陆微信后

打开 Process Explorer

找到微信的进程 WeChat.exe

CTRL + L 查看微信这个进程占用的各种资源

根据这个字符串的名字判断出来的 _WeChat_App_Instance_Identity_Mutex_Name 这个字符串就是微信的互斥体

找到 CreateMutexW 这个函数

使用 OD 直接在内存中找 CreateMutexW 方法,并调试 CreateMutexW 方法,手动修改互斥体,启动多个微信实例。

C++ 微信多开

使用 OD 打开微信

C++ 微信多开

CTRL + G 搜索 CreateMutexW 方法

C++ 微信多开

跳转到 CreateMutexW 方法后,在这个位置打一个断点 F2

C++ 微信多开

打完断点之后继续运行

在堆栈窗口可以看到 CreateMutexW 方法传递的三个参数

第一个参数:NULL

第二个参数:FALSE

第三个参数:_WeChat_App_Instance_Identity_Mutex_Name

C++ 微信多开

获取到 _WeChat_App_Instance_Identity_Mutex_Name 这个互斥体在内存中的地址 02BBB198

使用 CE 修改 _WeChat_App_Instance_Identity_Mutex_Name 这个字符串

C++ 微信多开

打开CE后选择进程

选择当前进程

选择微信进程

打开

C++ 微信多开

点击 手动添加地址

输入互斥体的内存地址

选择字符串

字符串长度设置成110

勾选 Unicode

C++ 微信多开

选择数值这列,双击 _WeChat_App_Instance_Identity_Mutex_Name

在弹框中修改一下这个字符串

内存修改完成,回到 OD

C++ 微信多开

F2 取消断点

继续运行,直到打开一个微信

这个微信他身上的互斥体就是手动修改的那个字符串

C++ 微信多开

通过正常途径在启动一个微信

正常启动

正常登陆

代码思路

思路
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++ 微信多开

原文链接: https://www.cnblogs.com/ansheng/p/15821465.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/186648

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 上午11:09
下一篇 2023年2月12日 上午11:09

相关推荐