研究pc微信逆向的都知道要让pc微信支持多开的话,就要干掉它的互斥体_WeChat_App_Instance_Identity_Mutex_Name,但是市面上的代码都是c++的,c#微信多开的代码貌似是没找到,然后到Github上找了下,倒是找到了一个库类,代码如下:
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace RevokeMsgPatcher.MultiInstance { /// <summary> /// 微信多开原理: /// https://mp.weixin.qq.com/s/bb7XMxop7e8rd7YqQ88nyA /// 参考: /// https://stackoverflow.com/questions/54872228/c-sharp-how-to-find-all-handles-associated-with-current-process /// https://hintdesk.com/2010/05/22/c-get-all-handles-of-a-given-process-in-64-bits/ /// </summary> public class ProcessUtil { /// <summary> /// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/handle_table_entry.htm?ts=0,242 /// </summary> [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_HANDLE_INFORMATION { // Information Class 16 public ushort ProcessID; public ushort CreatorBackTrackIndex; public byte ObjectType; public byte HandleAttribute; public ushort Handle; public IntPtr Object_Pointer; public IntPtr AccessMask; } private enum OBJECT_INFORMATION_CLASS : int { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct OBJECT_NAME_INFORMATION { // Information Class 1 public UNICODE_STRING Name; } [StructLayout(LayoutKind.Sequential)] private struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [Flags] private enum PROCESS_ACCESS_FLAGS : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VMOperation = 0x00000008, VMRead = 0x00000010, VMWrite = 0x00000020, DupHandle = 0x00000040, SetInformation = 0x00000200, QueryInformation = 0x00000400, Synchronize = 0x00100000 } [DllImport("ntdll.dll")] private static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int returnLength); [DllImport("kernel32.dll")] private static extern IntPtr OpenProcess(PROCESS_ACCESS_FLAGS dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); [DllImport("kernel32.dll")] private static extern IntPtr GetCurrentProcess(); [DllImport("ntdll.dll")] private static extern int NtQueryObject(IntPtr ObjectHandle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, ref int returnLength); [DllImport("kernel32.dll")] private static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll")] private static extern bool GetHandleInformation(IntPtr hObject, out uint lpdwFlags); private const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; private const int DUPLICATE_CLOSE_SOURCE = 0x1; private const int DUPLICATE_SAME_ACCESS = 0x2; private const int CNST_SYSTEM_HANDLE_INFORMATION = 0x10; private const int OBJECT_TYPE_MUTANT = 17; public static List<SYSTEM_HANDLE_INFORMATION> GetHandles(Process process) { List<SYSTEM_HANDLE_INFORMATION> aHandles = new List<SYSTEM_HANDLE_INFORMATION>(); int handle_info_size = Marshal.SizeOf(new SYSTEM_HANDLE_INFORMATION()) * 20000; IntPtr ptrHandleData = IntPtr.Zero; try { ptrHandleData = Marshal.AllocHGlobal(handle_info_size); int nLength = 0; while (NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ptrHandleData, handle_info_size, ref nLength) == STATUS_INFO_LENGTH_MISMATCH) { handle_info_size = nLength; Marshal.FreeHGlobal(ptrHandleData); ptrHandleData = Marshal.AllocHGlobal(nLength); } long handle_count = Marshal.ReadIntPtr(ptrHandleData).ToInt64(); IntPtr ptrHandleItem = ptrHandleData + Marshal.SizeOf(ptrHandleData); for (long lIndex = 0; lIndex < handle_count; lIndex++) { SYSTEM_HANDLE_INFORMATION oSystemHandleInfo = new SYSTEM_HANDLE_INFORMATION(); oSystemHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ptrHandleItem, oSystemHandleInfo.GetType()); ptrHandleItem += Marshal.SizeOf(new SYSTEM_HANDLE_INFORMATION()); if (oSystemHandleInfo.ProcessID != process.Id) { continue; } aHandles.Add(oSystemHandleInfo); } } catch (Exception ex) { throw ex; } finally { Marshal.FreeHGlobal(ptrHandleData); } return aHandles; } public static bool FindAndCloseWeChatMutexHandle(SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process) { IntPtr ipHandle = IntPtr.Zero; IntPtr openProcessHandle = IntPtr.Zero; IntPtr hObjectName = IntPtr.Zero; try { PROCESS_ACCESS_FLAGS flags = PROCESS_ACCESS_FLAGS.DupHandle | PROCESS_ACCESS_FLAGS.VMRead; openProcessHandle = OpenProcess(flags, false, process.Id); // 通过 DuplicateHandle 访问句柄 if (!DuplicateHandle(openProcessHandle, new IntPtr(systemHandleInformation.Handle), GetCurrentProcess(), out ipHandle, 0, false, DUPLICATE_SAME_ACCESS)) { return false; } int nLength = 0; hObjectName = Marshal.AllocHGlobal(256 * 1024); // 查询句柄名称 while ((uint)(NtQueryObject(ipHandle, (int)OBJECT_INFORMATION_CLASS.ObjectNameInformation, hObjectName, nLength, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH) { Marshal.FreeHGlobal(hObjectName); if (nLength == 0) { Console.WriteLine("Length returned at zero!"); return false; } hObjectName = Marshal.AllocHGlobal(nLength); } OBJECT_NAME_INFORMATION objObjectName = new OBJECT_NAME_INFORMATION(); objObjectName = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(hObjectName, objObjectName.GetType()); if (objObjectName.Name.Buffer != IntPtr.Zero) { string strObjectName = Marshal.PtrToStringUni(objObjectName.Name.Buffer); Console.WriteLine(strObjectName); // \Sessions\1\BaseNamedObjects\_WeChat_App_Instance_Identity_Mutex_Name if (strObjectName.Contains("_Instance_Identity_Mutex_Name")) { // 通过 DuplicateHandle DUPLICATE_CLOSE_SOURCE 关闭句柄 IntPtr mHandle = IntPtr.Zero; if (DuplicateHandle(openProcessHandle, new IntPtr(systemHandleInformation.Handle), GetCurrentProcess(), out mHandle, 0, false, DUPLICATE_CLOSE_SOURCE)) { CloseHandle(mHandle); return true; } } } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Marshal.FreeHGlobal(hObjectName); CloseHandle(ipHandle); CloseHandle(openProcessHandle); } return false; } /// <summary> /// 关闭微信的互斥句柄 /// </summary> /// <param name="processes">微信的进程</param> /// <returns></returns> public static void CloseMutexHandle(Process[] processes) { foreach (Process process in processes) { CloseMutexHandle(process); } } public static bool CloseMutexHandle(Process process) { bool existMutexHandle = false; List<SYSTEM_HANDLE_INFORMATION> aHandles = GetHandles(process); foreach (SYSTEM_HANDLE_INFORMATION handle in aHandles) { // Mutant 类型的句柄 // if (handle.ObjectType == OBJECT_TYPE_MUTANT) // { if (FindAndCloseWeChatMutexHandle(handle, process)) { existMutexHandle = true; } // } } return existMutexHandle; } } }
但其实使用的话,发现并没有效果,那没折了,只能自己来了。先看下能正常干掉微信互斥体的c++代码:
HANDLE hMutex = CreateMutexW(NULL, FALSE, L"_WeChat_App_Instance_Identity_Mutex_Name"); if (!hMutex) { return false; } SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; PSID pEveryoneSID = NULL; // everyone群组SID char szBuffer[4096]; PACL pAcl = (PACL)szBuffer; AllocateAndInitializeSid( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID); InitializeAcl(pAcl, sizeof(szBuffer), ACL_REVISION); AddAccessDeniedAce(pAcl, ACL_REVISION, MUTEX_ALL_ACCESS, pEveryoneSID); SetSecurityInfo(hMutex, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pAcl, NULL); return true;
代码很简短,主要呢也都是调用的系统api。我们c#要调用win32的话,就需要使用DllImport声明对应的win32函数供c#调用,比较难的就是对应的win32函数里面的相关参数也要自己声明成对应的c++结构。过程不说了,直接给出可以正常使用的代码
下面是可以正常使用的微信多开c#代码
using System; using System.Runtime.InteropServices; namespace WxRobot.Core { public class MutexClose { [DllImport("kernel32.dll")] public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] internal static extern bool AddAccessDeniedAce(IntPtr pAcl, int dwAceRevision, int AccessMask, IntPtr pSid); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] internal static extern bool InitializeAcl(IntPtr pAcl, int nAclLength, int dwAclRevision); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] internal static extern bool AllocateAndInitializeSid(ref SID_IDENTIFIER_AUTHORITY pIdentifierAuthority, byte nSubAuthorityCount, int dwSubAuthority0, int dwSubAuthority1, int dwSubAuthority2, int dwSubAuthority3, int dwSubAuthority4, int dwSubAuthority5, int dwSubAuthority6, int dwSubAuthority7, ref IntPtr pSid); [DllImport("advapi32.dll")] private static extern uint SetSecurityInfo(IntPtr handle, SeObjectType ObjectType,SecurityInformation SecurityInfo, IntPtr psidOwner,IntPtr psidGroup, IntPtr pDacl, IntPtr pSacl); private enum SeObjectType { SE_UNKNOWN_OBJECT_TYPE = 0, SE_FILE_OBJECT, SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_LMSHARE, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT, SE_DS_OBJECT, SE_DS_OBJECT_ALL, SE_PROVIDER_DEFINED_OBJECT, SE_WMIGUID_OBJECT, SE_REGISTRY_WOW64_32KEY, SE_REGISTRY_WOW64_64KEY, } private enum SecurityInformation { DaclSecurityInformation = 0x4 } [StructLayout(LayoutKind.Sequential)] public struct SID_IDENTIFIER_AUTHORITY { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.I1)] public byte[] Value; } public static bool EnableMultiWeChat() { IntPtr hMutex = CreateMutex(IntPtr.Zero, false, "_WeChat_App_Instance_Identity_Mutex_Name"); if (hMutex == IntPtr.Zero) return false; SID_IDENTIFIER_AUTHORITY pIdentifierAuthority = new SID_IDENTIFIER_AUTHORITY { Value = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 } }; IntPtr pEveryoneSID = new IntPtr(); // everyone群组SID char[] szBuffer = new char[4096]; var pAcl = Marshal.AllocHGlobal(szBuffer.Length); AllocateAndInitializeSid(ref pIdentifierAuthority, 1, 0, 0, 0, 0, 0, 0, 0, 0, ref pEveryoneSID); int dwAclRevision = 2; InitializeAcl(pAcl, szBuffer.Length, dwAclRevision); int accessMask = 2031617; AddAccessDeniedAce(pAcl, dwAclRevision, accessMask, pEveryoneSID); SetSecurityInfo(hMutex, SeObjectType.SE_KERNEL_OBJECT, SecurityInformation.DaclSecurityInformation, IntPtr.Zero, IntPtr.Zero, pAcl, IntPtr.Zero); //SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; //PSID pEveryoneSID = NULL; // everyone群组SID //char szBuffer[4096]; //PACL pAcl = (PACL)szBuffer; //AllocateAndInitializeSid( // &SIDAuthWorld, // 1, // SECURITY_WORLD_RID, // 0, 0, 0, 0, 0, 0, 0, // &pEveryoneSID); //InitializeAcl(pAcl, sizeof(szBuffer), ACL_REVISION); //AddAccessDeniedAce(pAcl, ACL_REVISION, MUTEX_ALL_ACCESS, pEveryoneSID); //SetSecurityInfo(hMutex, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pAcl, NULL); return true; } } }
只要调用下EnableMultiWeChat()函数就Ok了。