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

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


res.png (229.32 KB, 下载次数: 0)
下载附件
效果图
2023-4-30 12:01 上传

#pragma once
#include
#include
#include
#include
#include
#include
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[1];
}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
#include
// 提升进程权限
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[0].Luid);
    tkp.Privileges[0].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 HandleCount; idx++)
    {
        currnetHnd = &(buff->Handles[idx]);
        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 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 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 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 pid;
    pid = findPidByName(L"WeChat.exe");
    if (pid.size()

句柄, 互斥

qq173339443   

名扫能实现不
apull   

这个厉害了。
宜城小站   

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

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

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

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

求用法与用量
advertising   

马上试试看
theshaonian   

哈哈哈,小白进来逛了一圈,硬是没看懂
您需要登录后才可以回帖 登录 | 立即注册