BeneficialWeb 发表于 2020-3-22 23:34

微信双开代码实现

   互斥量是一个很好玩的东西,可以实现进程的单例。WeChat也是用的Mutant技术实现的防止多开。无事练习下Win32 API编程,于是便有了此贴。
   实现双开的原理就是跨进程关闭互斥量句柄。各位看官可以自行完善下面代码实现多开。
   #include<Windows.h>
#include<TlHelp32.h>
#include<stdio.h>
#include<memory>

#pragma comment(lib,"ntdll")

#define NT_SUCCESS(status) (status>=0)

#define STATUS_INFO_LENGTH_MISMATCH((NTSTATUS)0xC0000004L)

enum PROCESSINFOCLASS {
      ProcessHandleInformation = 51
};

typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO {
      HANDLE HandleValue;
      ULONG_PTR HandleCount;
      ULONG_PTR PointerCount;
      ULONG GrantedAccess;
      ULONG ObjectTypeIndex;
      ULONG HandleAttributes;
      ULONG Reserved;
}PROCESS_HANDLE_TABLE_ENTRY_INFO,*PROCESS_HANDLE_TABLE_ENTRY;


// private
typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION {
ULONG_PTR NumberOfHandles;
ULONG_PTR Reserved;
PROCESS_HANDLE_TABLE_ENTRY_INFO Handles;
}PROCESS_HANDLE_SNAPSHOT_INFORMATION, *PROCESS_HANDLE_SNAPSHOT;


extern "C" NTSTATUS NTAPI NtQueryInformationProcess(
      _In_ HANDLE ProcessHandle,
      _In_ PROCESSINFOCLASS ProcessInformationClass,
      _In_ _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
      _In_ ULONG ProcessInformationLength,
      _Out_opt_ PULONG ReturnLength);

typedef enum _OBJECT_INFORMATION_CLASS {
      ObjectNameInformation = 1
} OBJECT_INFORMATION_CLASS;

typedef struct _UNICODE_STRING {
      USHORT Length;
      USHORT MaximumLength;
      PWSTRBuffer;
} UNICODE_STRING;

typedef struct _OBJECT_NAME_INFORMATION {
      UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;

extern "C" NTSTATUS NTAPI NtQueryObject(
      _In_opt_ HANDLE Handle,
      _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,
      _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,
      _In_ ULONG ObjectInformationLength,
      _Out_opt_ PULONG ReturnLength);

DWORD FindWeChat() {
      HANDLE hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
      if (hSnapshot == INVALID_HANDLE_VALUE)
                return 0;

      PROCESSENTRY32 pe;
      pe.dwSize = sizeof(pe);

      // skip the idle process
      ::Process32First(hSnapshot, &pe);

      DWORD pid = 0;
      while (::Process32Next(hSnapshot, &pe)) {
                if (::_wcsicmp(pe.szExeFile, L"WeChat.exe") == 0) {
                        // found it
                        pid = pe.th32ProcessID;
                        break;
                }
      }
      ::CloseHandle(hSnapshot);
      return pid;
}

int main() {
      DWORD pid = FindWeChat();
      if (pid == 0) {
                printf("Failed to locate WeChat\n");
                return 1;
      }
      printf("Located WeChat : PID=%u\n", pid);

      HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,
                FALSE, pid);
      if (!hProcess) {
                printf("Failed to open WeChat process handle (error=%u)\n",
                        GetLastError());
                return 1;
      }

      ULONG size = 1 << 10;
      std::unique_ptr<BYTE[]> buffer;
      for (;;) {
                buffer = std::make_unique<BYTE[]>(size);
                auto status = ::NtQueryInformationProcess(hProcess, ProcessHandleInformation,
                        buffer.get(), size, &size);
                if (NT_SUCCESS(status))
                        break;
                if (status == STATUS_INFO_LENGTH_MISMATCH) {
                        size += 1 << 10;
                        continue;
                }
                printf("Error enumerating handles\n");
                return 1;
      }

      WCHAR targetName;
      DWORD sessionId;
      ::ProcessIdToSessionId(pid, &sessionId);
      ::swprintf_s(targetName,
                L"\\Sessions\\%u\\BaseNamedObjects\\_WeChat_App_Instance_Identity_Mutex_Name",
                sessionId);
      auto len = ::wcslen(targetName);

      WCHAR targetName2;
      ::swprintf_s(targetName2,
                L"\\Sessions\\%u\\BaseNamedObjects\\WeChat_GlobalConfig_Multi_Process_Mutex",
                sessionId);
      auto len2 = ::wcslen(targetName2);

      auto info = reinterpret_cast<PROCESS_HANDLE_SNAPSHOT_INFORMATION*>(buffer.get());
      for (ULONG i = 0; i < info->NumberOfHandles; i++) {
                HANDLE h = info->Handles.HandleValue;
                HANDLE hTarget;
                if (!::DuplicateHandle(hProcess, h, ::GetCurrentProcess(), &hTarget,
                        0, FALSE, DUPLICATE_SAME_ACCESS)) {
                        continue;      // move to next handle
                }
                BYTE nameBuffer;
                auto status = ::NtQueryObject(hTarget, ObjectNameInformation,
                        nameBuffer, sizeof(nameBuffer), nullptr);
                auto name = reinterpret_cast<UNICODE_STRING*>(nameBuffer);
                if (name->Buffer&&::wcsnicmp(name->Buffer, targetName, len) == 0) {
                        // found it!
                        ::DuplicateHandle(hProcess, h, ::GetCurrentProcess(), &h,
                              0, false, DUPLICATE_CLOSE_SOURCE);
                        printf("Found it! and closed it!\n");
                }
                if (name->Buffer&&::wcsnicmp(name->Buffer, targetName2, len2) == 0) {
                        // found it!
                        ::DuplicateHandle(hProcess, h, ::GetCurrentProcess(), &h,
                              0, false, DUPLICATE_CLOSE_SOURCE);
                        printf("Found it! and closed it!\n");
                }
      }
      
      return 0;
}


最终效果:

   

涛之雨 发表于 2020-3-23 00:49

VIPAccount 发表于 2020-3-23 00:04
楼主牛逼!从代码角度解析了如何双卡,牛!
这里插个楼,也可以用bat实现双开,下面代码保存成.bat文件, ...

还可以在weichat文件夹里放一个bat
start WeChat.exe ""
%0

能开几个就看电脑性能了

VIPAccount 发表于 2020-3-23 00:04

楼主牛逼!从代码角度解析了如何双卡,牛!
这里插个楼,也可以用bat实现双开,下面代码保存成.bat文件,双击也可以打开两个微信:
PATH E:\Program Files (x86)\Tencent\WeChat
start WeChat.exe&WeChat.exe

第一行路径为微信安装的跟路径,第二行不变。

尔等幼稚 发表于 2020-3-23 11:52

虽然看不懂,但是我电脑微信双开的时候,就是用鼠标快速点击微信图标,能点几次就点几次,最后至少会出现3个登陆界面,我电脑是win7系统,微信是最新版本,多开屡试不爽,大家可以试试

萌新想学习 发表于 2021-7-16 15:12

虽然看不懂,但是我喜欢用下面的代码start D:\微信\WeChat\WeChat.exe
start D:\微信\WeChat\WeChat.exe

伤心的笔 发表于 2020-3-22 23:49

666 原来是文件锁
希望这个锁只有这一个用途

suixuersheng 发表于 2020-3-22 23:51

希望只有这一个用途

Parkourr 发表于 2020-3-23 00:05

感谢大佬分享感谢

Crazy开发仔 发表于 2020-3-23 00:08

使用沙箱貌似也可以吧?

sd4060483 发表于 2020-3-23 00:48

跟着大神又学习了

昔日天才 发表于 2020-3-23 02:01

感谢分享{:1_927:}

q10123 发表于 2020-3-23 04:38

厉害了。
页: [1] 2 3 4
查看完整版本: 微信双开代码实现