首頁 > 軟體

C++ 微信多開的實現

2022-02-16 10:00:48

應用是如何判斷多開

一、通過查詢視窗標題或者類名來判斷程式是否正在執行。

二、通過互斥物件確定程式是否執行,大多數軟體都是使用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++ 微信多開內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com