import os import time import ctypes import psutil import win32gui import win32process from ctypes import wintypes kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) advapi32 = ctypes.WinDLL('advapi32', use_last_error=True) SECURITY_WORLD_SID_AUTHORITY = (0, 0, 0, 0, 0, 1) SECURITY_WORLD_RID = 0 ACL_REVISION = 2 SE_KERNEL_OBJECT = 6 DACL_SECURITY_INFORMATION = 0x00000004 MUTEX_ALL_ACCESS = 0x1F0001 kernel32.CreateMutexW.argtypes = [wintypes.LPVOID, wintypes.BOOL, wintypes.LPCWSTR] kernel32.CreateMutexW.restype = wintypes.HANDLE advapi32.AllocateAndInitializeSid.argtypes = [ ctypes.POINTER(ctypes.c_byte), ctypes.c_byte, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(ctypes.c_void_p) ] advapi32.AllocateAndInitializeSid.restype = wintypes.BOOL advapi32.InitializeAcl.argtypes = [wintypes.LPVOID, wintypes.DWORD, wintypes.DWORD] advapi32.InitializeAcl.restype = wintypes.BOOL advapi32.AddAccessDeniedAce.argtypes = [wintypes.LPVOID, wintypes.DWORD, wintypes.DWORD, wintypes.LPVOID] advapi32.AddAccessDeniedAce.restype = wintypes.BOOL advapi32.SetSecurityInfo.argtypes = [ wintypes.HANDLE, wintypes.DWORD, wintypes.DWORD, wintypes.LPVOID, wintypes.LPVOID, wintypes.LPVOID, wintypes.LPVOID ] advapi32.SetSecurityInfo.restype = wintypes.DWORD def Create_wechat_Mutex(): mutex_created = False try: h_mutex = kernel32.CreateMutexW(None, False, "_WeChat_App_Instance_Identity_Mutex_Name") if not h_mutex: raise ctypes.WinError(ctypes.get_last_error()) sid_auth_world = (ctypes.c_byte * 6)(*SECURITY_WORLD_SID_AUTHORITY) p_everyone_sid = ctypes.c_void_p() if not advapi32.AllocateAndInitializeSid( ctypes.cast(ctypes.byref(sid_auth_world), ctypes.POINTER(ctypes.c_byte)), 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, ctypes.byref(p_everyone_sid) ): raise ctypes.WinError(ctypes.get_last_error()) sz_buffer = (ctypes.c_byte * 4096)() p_acl = ctypes.cast(sz_buffer, ctypes.POINTER(ctypes.c_byte)) if not advapi32.InitializeAcl(p_acl, ctypes.sizeof(sz_buffer), ACL_REVISION): raise ctypes.WinError(ctypes.get_last_error()) if not advapi32.AddAccessDeniedAce(p_acl, ACL_REVISION, MUTEX_ALL_ACCESS, p_everyone_sid): raise ctypes.WinError(ctypes.get_last_error()) result = advapi32.SetSecurityInfo( h_mutex, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, None, None, p_acl, None ) if result != 0: raise ctypes.WinError(result) mutex_created = True print("提示:互斥体创建成功,将尝试通过互斥体绕过微信单分身限制") except Exception as e: print(f"警告:互斥体创建失败 ({e}),将尝试直接启动多个分身进行多开") return mutex_created def get_pid(process_name): pids = [] for proc in psutil.process_iter(['pid', 'name']): if proc.info['name'] == process_name: pids.append(proc.info['pid']) return pids def get_process_path(pid): try: process = psutil.Process(pid) return process.exe() except psutil.NoSuchProcess: return None def get_hwnd_from_pid(pids): hwnds = [] def callback(hwnd, extra): _, pid = win32process.GetWindowThreadProcessId(hwnd) window_title = win32gui.GetWindowText(hwnd) if pid in pids and win32gui.IsWindowVisible(hwnd) and window_title != "": hwnds.append(hwnd) return True win32gui.EnumWindows(callback, None) return hwnds def get_screen_size(): user32 = ctypes.windll.user32 screen_width = user32.GetSystemMetrics(0) screen_height = user32.GetSystemMetrics(1) return screen_width, screen_height def arrange_windows(windows): num_windows = len(windows) if num_windows == 0: print("警告:没有检测到新打开的微信窗口,可能启动失败") return screen_width, screen_height = get_screen_size() left, top, right, bottom = win32gui.GetWindowRect(windows[0]) window_width = right - left window_height = bottom - top spacing = 10 rows = 2 if num_windows <= 2: rows = 1 elif num_windows >= 3: rows = 2 windows_per_row = [] if rows == 1: windows_per_row = [num_windows] else: windows_per_row = [num_windows // 2 + num_windows % 2, num_windows // 2] start_y = (screen_height - rows * (window_height + spacing)) // 2 index = 0 for row in range(rows): current_cols = windows_per_row[row] total_width = current_cols * window_width + (current_cols - 1) * spacing start_x = (screen_width - total_width) // 2 for col in range(current_cols): if index >= num_windows: break x = start_x + col * (window_width + spacing) y = start_y + row * (window_height + spacing) win32gui.MoveWindow(windows[index], x, y, window_width, window_height, True) index += 1 print("微信公众号:蓝胖子之家") print("微信多开工具,正在初始化...") mutex_success = Create_wechat_Mutex() last_pids = get_pid("WeChat.exe") initial_count = len(last_pids) print(f"检测结果:当前运行的微信进程数为 {initial_count}") if len(last_pids) > 0: path = get_process_path(last_pids[0]) print(f"提示:检测到微信路径为 {path},将使用此路径启动新分身") else: default_path = r"C:\Program Files (x86)\Tencent\WeChat\WeChat.exe" if os.path.exists(default_path): path = default_path print(f"提示:未检测到运行中的微信,将使用默认路径 {path} 启动") else: print("错误:未检测到运行中的微信,且默认路径 {default_path} 无效") print("操作指引:请先手动打开一个微信(无需登录),然后重新运行此脚本") print("注意:如果微信安装路径不是默认值,请修改脚本中的 default_path 变量") exit(1) open_wx_num = 3 print(f"提示:即将启动 {open_wx_num} 个新的微信分身,请稍候...") for i in range(open_wx_num): try: os.startfile(path) print(f"状态:已启动第 {i+1}/{open_wx_num} 个微信分身") except Exception as e: print(f"错误:启动第 {i+1} 个分身失败 ({e}),请检查路径或微信版本") print("提示:等待新分身加载,可能需要几秒钟...") time.sleep(2) now_pids = get_pid("WeChat.exe") pids = list(set(now_pids) - set(last_pids)) new_count = len(now_pids) print(f"检测结果:启动后微信进程数为 {new_count}") print(f"检测结果:新增微信进程数为 {len(pids)}") if new_count > initial_count: if mutex_success: print(f"成功:通过互斥体操作实现多开,新增 {len(pids)} 个分身") else: print(f"成功:通过直接启动多个分身实现多开,新增 {len(pids)} 个分身") else: print("失败:无法启动新的微信分身") print("可能原因:1. 微信版本限制了多开;2. 路径错误;3. 系统权限不足") print("解决方法:1. 尝试以管理员权限运行脚本;2. 检查微信路径;3. 使用旧版微信") exit(1) wechat_windows = get_hwnd_from_pid(pids) print("提示:正在排列微信窗口,请稍候...") time.sleep(1) arrange_windows(wechat_windows) print(f"完成:窗口排列成功,共排列 {len(wechat_windows)} 个微信窗口") print("提示:多开完成,您可以开始登录不同的微信账号")
启动数量: 修改 open_wx_num 的值,例如改为 3
open_wx_num = 3
绕过微信单实例限制
微信默认通过一个名为_WeChat_App_Instance_Identity_Mutex_Name的互斥体(Mutex)限制多开。代码主要实现方法是创建并修改这个互斥体的权限,或者直接启动多个进程并规避限制。
1. 创建并修改互斥体权限
函数 Create_wechat_Mutex() 是实现多开的核心:
- 创建互斥体
:使用kernel32.CreateMutexW创建名为 _WeChat_App_Instance_Identity_Mutex_Name 的互斥体。这是微信用于检测是否已运行实例的关键。 - 修改访问权限
-
通过 advapi32.AllocateAndInitializeSid 创建一个“Everyone”安全标识符(SID),代表所有用户。 -
使用 advapi32.InitializeAcl 初始化一个访问控制列表(ACL),然后通过 advapi32.AddAccessDeniedAce 添加拒绝访问规则,禁止其他进程访问这个互斥体。 -
最后调用 advapi32.SetSecurityInfo 将修改后的ACL应用到互斥体上。
-
检测和启动微信进程
- 获取进程信息
:函数 get_pid("WeChat.exe") 使用 psutil 检测当前运行的微信进程数量,记录初始状态。 - 确定路径
- 启动新实例
:通过 os.startfile(path) 循环启动指定数量的微信进程(默认3个)。
原文始发于微信公众号(蓝胖子之家):Python实现微信互拆体多开代码
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论