├── README.md └── main.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Wechat-Open-More 2 | Wechat PC Open More 3 | # PC 微信多开 Demo 4 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #pragma comment(lib,"Shlwapi.lib") 6 | 7 | /* 8 | 原理:通过 DuplicateHandle 关闭 wechat.exe 里的互斥对象 9 | */ 10 | 11 | /* 12 | BOOL DuplicateHandle( 13 | HANDLE hSourceProcessHandle, // 来源进程(从XX复制 ) 也就是 OpenProcess 的返回值 14 | HANDLE hSourceHandle, // 来源进程内的 X句柄 15 | HANDLE hTargetProcessHandle, // 目标进程(复制到 ) 16 | LPHANDLE lpTargetHandle, // 接收X句柄的地址指针 17 | DWORD dwDesiredAccess, // 设置复制来的句柄的 访问权限 18 | BOOL bInheritHandle, // 设置复制来的句柄 继承属性 19 | DWORD dwOptions // 其他选项(0x1 DUPLICATE_CLOSE_SOURCE 0x2 DUPLICATE_SAME_ACCESS) 20 | // 写 DUPLICATE_SAME_ACCESS 的话,dwDesiredAccess 就忽略了 21 | ); 22 | */ 23 | 24 | #define NT_SUCCESS(Status)((NTSTATUS)(Status)>=0) 25 | #define STATUS_SUCCESS 0x00000000 26 | #define STATUS_UNSUCCESSFUL 0xC0000001 27 | #define STATUS_NOT_IMPLEMENTED 0xC0000002 28 | #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 29 | #define STATUS_INVALID_PARAMETER 0xC000000D 30 | #define STATUS_ACCESS_DENIED 0xC0000022 31 | #define STATUS_BUFFER_TOO_SMALL 0xC0000023 32 | #define OBJ_KERNEL_HANDLE 0x00000200 33 | 34 | typedef enum _SYSTEM_INFORMATION_CLASS { 35 | SystemBasicInformation, // 0 Y N 36 | SystemProcessorInformation, // 1 Y N 37 | SystemPerformanceInformation, // 2 Y N 38 | SystemTimeOfDayInformation, // 3 Y N 39 | SystemNotImplemented1, // 4 Y N 40 | SystemProcessesAndThreadsInformation, // 5 Y N 41 | SystemCallCounts, // 6 Y N 42 | SystemConfigurationInformation, // 7 Y N 43 | SystemProcessorTimes, // 8 Y N 44 | SystemGlobalFlag, // 9 Y Y 45 | SystemNotImplemented2, // 10 Y N 46 | SystemModuleInformation, // 11 Y N 47 | SystemLockInformation, // 12 Y N 48 | SystemNotImplemented3, // 13 Y N 49 | SystemNotImplemented4, // 14 Y N 50 | SystemNotImplemented5, // 15 Y N 51 | SystemHandleInformation, // 16 Y N 52 | SystemObjectInformation, // 17 Y N 53 | SystemPagefileInformation, // 18 Y N 54 | SystemInstructionEmulationCounts, // 19 Y N 55 | SystemInvalidInfoClass1, // 20 56 | SystemCacheInformation, // 21 Y Y 57 | SystemPoolTagInformation, // 22 Y N 58 | SystemProcessorStatistics, // 23 Y N 59 | SystemDpcInformation, // 24 Y Y 60 | SystemNotImplemented6, // 25 Y N 61 | SystemLoadImage, // 26 N Y 62 | SystemUnloadImage, // 27 N Y 63 | SystemTimeAdjustment, // 28 Y Y 64 | SystemNotImplemented7, // 29 Y N 65 | SystemNotImplemented8, // 30 Y N 66 | SystemNotImplemented9, // 31 Y N 67 | SystemCrashDumpInformation, // 32 Y N 68 | SystemExceptionInformation, // 33 Y N 69 | SystemCrashDumpStateInformation, // 34 Y Y/N 70 | SystemKernelDebuggerInformation, // 35 Y N 71 | SystemContextSwitchInformation, // 36 Y N 72 | SystemRegistryQuotaInformation, // 37 Y Y 73 | SystemLoadAndCallImage, // 38 N Y 74 | SystemPrioritySeparation, // 39 N Y 75 | SystemNotImplemented10, // 40 Y N 76 | SystemNotImplemented11, // 41 Y N 77 | SystemInvalidInfoClass2, // 42 78 | SystemInvalidInfoClass3, // 43 79 | SystemTimeZoneInformation, // 44 Y N 80 | SystemLookasideInformation, // 45 Y N 81 | SystemSetTimeSlipEvent, // 46 N Y 82 | SystemCreateSession, // 47 N Y 83 | SystemDeleteSession, // 48 N Y 84 | SystemInvalidInfoClass4, // 49 85 | SystemRangeStartInformation, // 50 Y N 86 | SystemVerifierInformation, // 51 Y Y 87 | SystemAddVerifier, // 52 N Y 88 | SystemSessionProcessesInformation // 53 Y N 89 | } SYSTEM_INFORMATION_CLASS; 90 | 91 | typedef NTSTATUS ( WINAPI *_ZwQuerySystemInformation) ( 92 | SYSTEM_INFORMATION_CLASS SystemInformationClass, 93 | PVOID SystemInformation, 94 | ULONG SystemInformationLength, 95 | PULONG ReturnLength); 96 | 97 | typedef enum _OBJECT_INFORMATION_CLASS { 98 | ObjectBasicInformation, 99 | ObjectNameInformation, 100 | ObjectTypeInformation, 101 | ObjectAllInformation, 102 | ObjectDataInformation, 103 | } OBJECT_INFORMATION_CLASS; 104 | typedef NTSTATUS(NTAPI *NTQUERYOBJECT)( 105 | HANDLE Handle, 106 | OBJECT_INFORMATION_CLASS ObjectInformationClass, 107 | PVOID ObjectInformation, 108 | ULONG ObjectInformationLength, 109 | PULONG ReturnLength 110 | ); 111 | typedef struct _UNICODE_STRING { 112 | USHORT Length; //UNICODE占用的内存字节数,个数*2; 113 | USHORT MaximumLength; 114 | PWSTR Buffer; 115 | } UNICODE_STRING, *PUNICODE_STRING; 116 | typedef struct _OBJECT_NAME_INFORMATION { 117 | UNICODE_STRING Name; 118 | } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; 119 | typedef struct _SYSTEM_HANDLE_INFORMATION 120 | { 121 | ULONG ProcessId; 122 | UCHAR ObjectTypeNumber; 123 | UCHAR Flags; 124 | USHORT Handle; 125 | PVOID Object; 126 | ACCESS_MASK GrantedAccess; 127 | }SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; 128 | 129 | typedef struct _SYSTEM_HANDLE_INFORMATION_EX 130 | { 131 | ULONG NumberOfHandles; 132 | SYSTEM_HANDLE_INFORMATION Information[1]; 133 | }SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; 134 | 135 | void EnumObjInfo(LPVOID pBuffer, DWORD pid); 136 | NTQUERYOBJECT NtQueryObject; 137 | _ZwQuerySystemInformation ZwQuerySystemInformation; 138 | bool EnableDebugPrivilege(); 139 | 140 | 141 | PVOID GetObjBuffer() 142 | { 143 | ULONG dwNeedSize = 0; 144 | PVOID pBuff = NULL; 145 | ULONG dwSize = 4096; 146 | 147 | ZwQuerySystemInformation = (_ZwQuerySystemInformation)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "ZwQuerySystemInformation"); 148 | NtQueryObject = (NTQUERYOBJECT)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryObject"); 149 | 150 | printf("%d\n",EnableDebugPrivilege()); 151 | 152 | pBuff = malloc(dwSize); 153 | do { 154 | NTSTATUS status = ZwQuerySystemInformation(SystemHandleInformation, pBuff, dwSize, &dwNeedSize); 155 | if (status == STATUS_INFO_LENGTH_MISMATCH ) 156 | { 157 | free (pBuff); 158 | dwSize <<= 1; 159 | 160 | } 161 | else if (status == STATUS_SUCCESS) 162 | { 163 | break; 164 | } 165 | pBuff = malloc(dwSize); 166 | 167 | }while(1); 168 | 169 | return pBuff; 170 | } 171 | 172 | int main(int argc, char* argv[]) 173 | { 174 | if (argc == 2) 175 | { 176 | PVOID pObjInfo = GetObjBuffer(); 177 | if (pObjInfo) 178 | { 179 | EnumObjInfo(pObjInfo,atoi((char*)argv[1])); 180 | free(pObjInfo); 181 | } 182 | 183 | } 184 | else 185 | { 186 | printf("\nusage %s wechat.exe PID\n",argv[0]); 187 | } 188 | 189 | return 0; 190 | } 191 | 192 | void EnumObjInfo(LPVOID pBuffer, DWORD pid) 193 | { 194 | char szType[128] = { 0 }; 195 | char szName[512] = { 0 }; 196 | DWORD dwFlags = 0; 197 | 198 | POBJECT_NAME_INFORMATION pNameInfo; 199 | POBJECT_NAME_INFORMATION pNameType; 200 | 201 | PSYSTEM_HANDLE_INFORMATION_EX pInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer; 202 | ULONG OldPID = 0; 203 | for (DWORD i = 0; i < pInfo->NumberOfHandles; i++) 204 | { 205 | if (OldPID != pInfo->Information[i].ProcessId) 206 | { 207 | if (pInfo->Information[i].ProcessId == pid) 208 | { 209 | HANDLE newHandle; 210 | DuplicateHandle(OpenProcess(PROCESS_ALL_ACCESS, FALSE, pInfo->Information[i].ProcessId), (HANDLE)pInfo->Information[i].Handle, GetCurrentProcess(), &newHandle, DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_SAME_ACCESS); 211 | NTSTATUS status1 = NtQueryObject(newHandle, ObjectNameInformation, szName, 512, &dwFlags); 212 | NTSTATUS status2 = NtQueryObject(newHandle, ObjectTypeInformation, szType, 128, &dwFlags); 213 | if (strcmp(szName, "") && strcmp(szType, "") && status1 != 0xc0000008 && status2 != 0xc0000008) 214 | { 215 | pNameInfo = (POBJECT_NAME_INFORMATION)szName; 216 | pNameType = (POBJECT_NAME_INFORMATION)szType; 217 | 218 | // printf("%wZ ", pNameType); 219 | // printf("%wZ \n", pNameInfo); 220 | 221 | // WeChat_App_Instance_Identity_Mutex_Name 222 | if (StrStrW(pNameInfo->Name.Buffer,L"WeChat_App_Instance_Identity_Mutex_Name")) 223 | { 224 | // 复制后关闭源句柄 225 | BOOL dupOK = DuplicateHandle(OpenProcess(PROCESS_ALL_ACCESS, FALSE, pInfo->Information[i].ProcessId),(HANDLE)pInfo->Information[i].Handle,GetCurrentProcess(), &newHandle, DUPLICATE_SAME_ACCESS,FALSE,DUPLICATE_CLOSE_SOURCE); 226 | 227 | printf("多开成功!\n"); 228 | 229 | // printf("多开 %d %wZ \n", dupOK, pNameInfo); 230 | CloseHandle(newHandle); 231 | } 232 | } 233 | } 234 | } 235 | } 236 | } 237 | bool EnableDebugPrivilege() 238 | { 239 | HANDLE hToken; 240 | LUID sedebugnameValue; 241 | TOKEN_PRIVILEGES tkp; 242 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 243 | { 244 | return false; 245 | } 246 | if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) 247 | { 248 | CloseHandle(hToken); 249 | return false; 250 | } 251 | tkp.PrivilegeCount = 1; 252 | tkp.Privileges[0].Luid = sedebugnameValue; 253 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 254 | if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) 255 | { 256 | CloseHandle(hToken); 257 | return false; 258 | } 259 | return true; 260 | } 261 | --------------------------------------------------------------------------------