JackLSQ 发表于 2023-4-30 12:02

微信之无限多开无需更改微信的任何文件无视版本限制

关于微信多开网上的大多资料都是跟踪CreateMutexW()找到调用的地方然后改内存中的字节码。这样的方式不太好,很容易被检测。 在微信更新版本之后有需要重新去修改,但是有没有一种无视版限制又不需要去修改其代码的方式呢?
答案是有的。
首先,对于CreateMutexW 函数要进一步的了解.
```
HANDLE CreateMutexW(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
         BOOL                  bInitialOwner,
LPCWSTR               lpName
);
```
**第一个参数**是安全属性结构体, lpMutexAttributes 为 NULL,则 mutex 获取默认的安全描述符。 为NULL即可。
**第二个参数**是否被继承,如果此值为 TRUE ,并且调用方创建了互斥体,则调用线程获取互斥体对象的初始所有权。 否则,调用线程不会获取互斥体的所有权。为FALSE即可。
**第三个参数**是互斥体名称,这个参数很关键。
**返回值** 如果函数成功,则返回值是新创建的互斥体对象的句柄。如果函数失败,则返回值为 NULL。

微信判断是否多开的互斥体名称是**_WeChat_App_Instance_Identity_Mutex_Name**
有了这个名称那就好办了

找到这个名称对应的互斥体,然后将句柄给它关闭,就能实现多开了。也无需去修改其源代码。

下面效果图和源码


```
#pragma once
#include<iostream>
#include <windows.h>
#include <winternl.h>
#include <TlHelp32.h>
#include <string>
#include<vector>

using namespace std;
// 定义需要的宏
#define STATUS_SUCCESS 0x00UL
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

#define SystemHandleInformation 16
#define SE_DEBUG_PRIVILEGE 0x14

// 定义需要用到的结构体
typedef enum _OBJECT_INFORMATION_CLASSEX {
        ObjBasicInformation = 0,
        ObjNameInformation,
        ObjTypeInformation,
} OBJECT_INFORMATION_CLASSEX;

typedef enum _PROCESSINFOCLASSEX
{
        ProcessHandleInformation = 20,
}PROCESSINFOCLASSEX;

typedef struct _SYSTEM_HANDLE
{
        ULONG ProcessId;
        BYTE ObjectTypeNumber;
        BYTE Flags;
        USHORT Handle;
        PVOID Object;
        ACCESS_MASK GrantAccess;
}SYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
        DWORD HandleCount;
        SYSTEM_HANDLE Handles;
}SYSTEM_HANDLE_INFORMATION;

typedef struct _OBJECT_NAME_INFORMATION
{
        UNICODE_STRING ObjectName;
}OBJECT_NAME_INFORMATION;

// 声明未导出API
typedef NTSTATUS(WINAPI* ZwQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASSEX, LPVOID, DWORD, PDWORD);
ZwQueryInformationProcessProc ZwQueryInformationProcess;

typedef NTSTATUS(WINAPI* ZwQuerySystemInformationProc)(DWORD, PVOID, DWORD, DWORD*);
ZwQuerySystemInformationProc ZwQuerySystemInformation;

typedef NTSTATUS(WINAPI* ZwQueryObjectProc)(HANDLE, OBJECT_INFORMATION_CLASSEX, PVOID, ULONG, PULONG);
ZwQueryObjectProc ZwQueryObject;

typedef NTSTATUS(WINAPI* RtlAdjustPrivilegeProc)(DWORD, BOOL, BOOL, PDWORD);
RtlAdjustPrivilegeProc RtlAdjustPrivilege;

typedef DWORD(WINAPI* ZwSuspendProcessProc)(HANDLE);
ZwSuspendProcessProc ZwSuspendProcess;

typedef DWORD(WINAPI* ZwResumeProcessProc)(HANDLE);
ZwResumeProcessProc ZwResumeProcess;


#pragma warning (disable: 6011)
#pragma warning (disable: 6001)
#pragma warning (disable: 6387)
#include <stdio.h>
#include <Windows.h>

// 提升进程权限
BOOL ElevatePrivileges()
{
        HANDLE hToken;
        TOKEN_PRIVILEGES tkp;
        tkp.PrivilegeCount = 1;
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
                return FALSE;
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges.Luid);
        tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
        if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
        {
                return FALSE;
        }

        return TRUE;
}

// 初始化未导出API
BOOL GetUnDocumentAPI()
{
        ZwSuspendProcess = (ZwSuspendProcessProc)
                GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwSuspendProcess");

        ZwQuerySystemInformation = (ZwQuerySystemInformationProc)
                GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQuerySystemInformation");

        ZwQueryObject = (ZwQueryObjectProc)
                GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQueryObject");

        ZwResumeProcess = (ZwResumeProcessProc)
                GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwResumeProcess");

        ZwQueryInformationProcess = (ZwQueryInformationProcessProc)
                GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQueryInformationProcess");

        if ((ZwSuspendProcess == NULL) || \
                (ZwQuerySystemInformation == NULL) || \
                (ZwQueryObject == NULL) || \
                (ZwResumeProcess == NULL) || \
                (ZwQueryInformationProcess == NULL))
                return FALSE;

        return TRUE;
}

// 关闭指定Mutex s
BOOL closeMutexHandle(UINT Proc_id, const wchar_t* Mutex_name) {
        HANDLE duplicateHnd, sourceHnd = 0;
        DWORD procHndNum;
        SYSTEM_HANDLE* currnetHnd;
        DWORD buffLen = 0x1000;
        NTSTATUS status;
        SYSTEM_HANDLE_INFORMATION* buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
        UINT count = 0;
        if ((ElevatePrivileges() == FALSE) || (GetUnDocumentAPI() == FALSE))
                return FALSE;

        do
        {
                status = ZwQuerySystemInformation(SystemHandleInformation, buff, buffLen, &buffLen);
                if (status == STATUS_INFO_LENGTH_MISMATCH)
                {
                        free(buff);
                        buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
                }
                else
                        break;

        } while (1);

        OBJECT_NAME_INFORMATION* objNameInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);
        OBJECT_NAME_INFORMATION* objTypeInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);

        for (int idx = 0; idx < (int)buff->HandleCount; idx++)
        {
                currnetHnd = &(buff->Handles);

                if (currnetHnd->ProcessId == Proc_id)
                {
                        sourceHnd = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, Proc_id);
                        (ZwSuspendProcess)(sourceHnd);
                        (ZwQueryInformationProcess)(sourceHnd, ProcessHandleInformation, &procHndNum, sizeof(DWORD), NULL);
                        //进程有效句柄从4开始,每次以4递增
                        unsigned short hndNum = 4;
                        for (int idx = 0; idx < (int)procHndNum; hndNum += 4)
                        {
                                //判断是否为有效句柄,返回TRUE,就是有效句柄
                                if (!DuplicateHandle(sourceHnd,
                                        (HANDLE)hndNum,
                                        GetCurrentProcess(),
                                        &duplicateHnd, 0, FALSE, DUPLICATE_SAME_ACCESS))
                                {
                                        continue;
                                }
                                else
                                {
                                        memset(objNameInfo, 0, 0x1000);
                                        memset(objTypeInfo, 0, 0x1000);

                                        ZwQueryObject((HANDLE)duplicateHnd, ObjNameInformation, objNameInfo, 0x1000, NULL);
                                        ZwQueryObject((HANDLE)duplicateHnd, ObjTypeInformation, objTypeInfo, 0x1000, NULL);

                                        //找到互斥体 比较名字
                                        if (wcscmp(objTypeInfo->ObjectName.Buffer, L"Mutant") == 0)
                                        {
                                                //OutputDebugString();
                                                if (objNameInfo->ObjectName.Length != 0 && wcsstr(objNameInfo->ObjectName.Buffer, Mutex_name) != 0)
                                                {
                                                        printf("%ws\n", objNameInfo->ObjectName.Buffer);



                                                        wstring str(objNameInfo->ObjectName.Buffer);
                                                        int pos = str.rfind(L"\\");
                                                        wstring subStr = str.substr(pos + 1, 40);
                                                        if (subStr == L"_WeChat_App_Instance_Identity_Mutex_Name") {
                                                                CloseHandle(duplicateHnd);

                                                                if (DuplicateHandle(sourceHnd,
                                                                        (HANDLE)hndNum,
                                                                        GetCurrentProcess(),
                                                                        &duplicateHnd, 0, FALSE, DUPLICATE_CLOSE_SOURCE))
                                                                {
                                                                        CloseHandle(duplicateHnd);
                                                                        (ZwResumeProcess)(sourceHnd);
                                                                        return TRUE;
                                                                }
                                                        }

                                                }
                                                count++;
                                                if (count == 20) { return FALSE; }
                                        }

                                        CloseHandle(duplicateHnd);
                                        idx++;
                                }
                        }
                }
        }
        return FALSE;
}

vector<int > findPidByName(const wchar_t* name) {
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        PROCESSENTRY32 pe;
        pe.dwSize = sizeof(PROCESSENTRY32);
        bool b = Process32First(hSnap, &pe);
        string str;
        vector<int> pId;

        while (b) {
                //pe.szExeFile;
                if (wcscmp(pe.szExeFile, name) == 0)
                {
                        printf("应用名称%ws,进程id %d\n", pe.szExeFile, pe.th32ProcessID);
                        pId.push_back(pe.th32ProcessID);
                }

                b = Process32Next(hSnap, &pe);
        }
        return pId;
}





int main() {
        ElevatePrivileges();//提升当前进程权限
        GetUnDocumentAPI();    //初始化未导出API


        vector<int> pid;

        pid = findPidByName(L"WeChat.exe");
        if (pid.size() <= 0) {
                printf("微信未打开\n");
                return 0;//为空直接跳出
        }

        for (int i = 0; i < pid.size(); i++) {
                printf("%d\n", pid);//\Sessions\2\BaseNamedObjects\SM0:18508:168:WilStaging_02
                closeMutexHandle(pid, L"\\Sessions\\2\\BaseNamedObjects\\_WeChat_App_Instance_Identity_Mutex_Name");
        }



}

```

chishingchan 发表于 2023-4-30 12:45

带源码,看来像高大上。可惜不是每人都懂编程的!
有点人喜欢渔,也有点人喜欢鱼,要看那人的水平。
例如:这源码我懂的,我就喜欢渔;这源码我不懂的,就喜欢鱼了。

ggogg928 发表于 2023-4-30 14:46

微信多开还要用软件吗?按住回车不松手,鼠标点击微信图标就OK了啊,就能实现多开啊

BiteTheDust 发表于 2023-4-30 15:28

有时会需要多开,但是小白看不懂,哈哈,不知道怎么弄

theshaonian 发表于 2023-4-30 12:48

哈哈哈,小白进来逛了一圈,硬是没看懂

qq173339443 发表于 2023-4-30 13:34

名扫能实现不

apull 发表于 2023-4-30 13:25

这个厉害了。

宜城小站 发表于 2023-4-30 13:25

谢谢分享
期待拿到能用的成品发布

wasm2023 发表于 2023-4-30 12:58

楼主,啥时候来篇code提取的文章呗

hjc2023 发表于 2023-4-30 12:55

没成品,能记住之前登陆过的,不有手机扫码才方便

pwp 发表于 2023-4-30 12:11

求用法与用量

advertising 发表于 2023-4-30 12:17

马上试试看
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 微信之无限多开无需更改微信的任何文件无视版本限制