文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++微信多开的实现

2024-04-02 19:55

关注

应用是如何判断多开

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

二、通过互斥对象确定程序是否运行,大多数软件都是使用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

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯