微信PC端多开的秘密
微信电脑端也能多开
昨天,偶然从好朋友小林(微信公众号:小林Coding)处得知,他的电脑居然可以同时上两个微信号。
手机端多开微信我知道,像华为、小米等手机系统都对此做了支持,不过在运行Windows系统的电脑上怎么启动两个微信呢,这倒是一下引起了我的好奇。
小林告诉我他是这样做的,写了一个批处理:
start D:\WeChat\WeChat.exe
start D:\WeChat\WeChat.exe
然后直接双击批处理文件,就能启动两个微信进程。
我试了一下,果然如此!
随后我又加了一行,竟然还能启动3个:

接着我在网络上搜了一下,原来这一招早就被人用过了,看来是我火星了。不过到底为什么用这种方式就能多开,我倒是很想知道这个迷底。
TIPS:如果对技术分析部分不感兴趣,可以跳过直接来到后面的真相部分。
微信的单例模式
正常情况下,直接手动双击微信图标启动,后面启动的进程会进行全局单例模式检查,如果发现已经存在微信进程,就会直接把对应进程的微信窗口激活,定位到桌面最前面,随后自己退出。
但为什么用上面的方式就能启动俩呢?我们来一探究竟。
首先,分析一下上面描述的微信单个实例是如何实现的。
做过Windows平台应用程序开发的朋友可能对此比较熟悉,一般是进程启动后创建一个全局唯一名字的互斥体,创建成功则正常启动,创建失败则判断一下是否这个互斥体已经存在。如果已经存在则说明已经有对应程序之前启动。
带着这种猜想,用工具procexp查看一下微信进程打开的所有内核对象,并找到互斥体部分:

果然,这其中有一个名字叫 _WeChat_App_Instance_Identity_Mutex_Name 的互斥体,从这个名字可以猜出,这个跟微信的单例模式绝对有关系。
接着,启动神器APIMonitor,它可以帮你监控指定进程的API调用情况,勾选上CreateMutex和GetLastError这两个Windows API函数。在已经有微信在运行的情况下,用这个工具再启动一个微信进程,看一下函数调用情况:

可以看到,创建这个名字的互斥体后,随后又调用了GetLastError函数,并返回了0x000000b7,查看手册,其含义:

表示已经存在。
来看一下,这个CreateMutex调用的堆栈,看看是哪个地方的代码在创建这个全局互斥体:

从堆栈看出,调用来自于微信目录下的一个动态库WeChatWin.dll。具体位置在偏移0x8e271b处的前一条指令。
接下来就要祭出神器中的神器,大名鼎鼎的反汇编软件IDA,这家伙支持x86、x64、ARM、MIPS等多种处理器架构和Windows、Linux、Android、MacOS、JVM等多种系统平台的程序分析。
用IDA打开这个WeChatWin.dll文件,并定位到偏移0x8e271b处:

如上图所示,创建互斥体的动作,发生在函数sub_108e26d0。
上层是sub_108e2660函数在调用它:

上面这张图反映了创建互斥体后的判断逻辑:
- 如果sub_108e26d0的返回值为0,表示没有错误,当前函数也直接返回0。
- 如果sub_108e26d0的返回值不为0,表示出现了错误,则依次判断WeChatMainWndForPC和WeChatLoginWndForPC两个窗口是否存在,如果存在则使用BringWindowToTop函数将其置顶弹出。这两个窗口分别代表的是微信的主界面窗口和登陆界面窗口,如果一个微信实例已经存在,则势必处于这两种状态之一。
问题就出在上面这个判断中,汇编代码看起来有点辣眼睛,咱们F5来还原一下C代码(还原效果只能凑合看,能看清楚逻辑就行):

上面图片的注解已经说明了,函数sub_108e2660的返回值将决定是否启动微信实例进程,还是直接退出。
真相只有一个
事情到这里就真相大白了,来总结一下。
微信判断是否启动的2个条件:
- 如果能成功创建互斥体对象,则启动微信
- 如果不能创建互斥体:
- 如果找到对应窗口,则置顶之,自己退出
- 如果没有找到,则启动微信
用伪代码来表示一下:
if (CreateMutex() == SUCCESS) {
启动微信
} else {
if (FindWindow() == SUCCESS) {
将已有窗口置顶
} else {
启动微信
}
}
而直接使用脚本启动的多个进程,虽然操作系统内核层面保证了互斥体的唯一,但由于启动速度相差不大,相应的窗口还没有来得及创建出来,导致走入上面的第二个启动逻辑,从而可以启动多个实例。
小发现
在分析的过程中,发现了一个有趣的事情:
在WeChatWin.dll中,上面的创建互斥体再上一级函数名字叫StartWaChat,也是作为导出函数被该DLL导出:

这里不知道是故意还是不小心把微信的WeChat写成了WaChat,如果是笔误,这位程序员同学看到了赶紧偷偷去改一下吧。
往期TOP5文章


微信PC端多开的秘密的更多相关文章
- 企业微信 PC端多开
企业微信,正常情况下一个PC端只能登一个账号.现在多个人共用一个外网机,需要在一个电脑上登录多个账号.解决办法如下: 下载process explorer.exe,使用管理员权限运行,找到WXWork ...
- 【实战问题】【4】Vue写的页面在微信手机端和微信web开发者工具中都能正常显示,但是在微信pc端上显示空白
原因:pc端微信浏览器不支持es6,而代码中使用了 let . 解决:将 let 改为 var(若使用 es6 语法比较多,可以进行转换,将 es6 语法转为 es5) 参考博客: 1,h5微信页面在 ...
- mint-ui 企业微信PC端内置浏览器 Picker 无法滚动
处理 在主JS代码之上附加以下代码 : <script> if (~navigator.userAgent.toLowerCase().indexOf('windowswechat')) ...
- 微信PC端授权页面提示授权入口所在域名为空
做第三方微信平台的时候做授权页面,用window.open方法从第三方平台页面打开新的授权标签页. 在IE浏览器上出问题,提示如下: 在chrome和firefox浏览器上正常. 搜了一下,发现微信是 ...
- 微信pc端和手机上传处理
一.原因 在微信通过电脑版和浏览器登录时,调用了微信上传的接口,wx.getLocalImgData或返回失败. 没办法,只有处理当电脑上传时,使用ajaxuploadfile上传. 二.方法 fun ...
- 我要多开梦幻手游PC端(梦幻手游PC端多开的简单分析及实现办法)(二)
上一篇,多开方法,适用于一年前的版本 http://www.cnblogs.com/suanguade/p/5646776.html 前言: 一转眼一年过去了,日子越来越无聊了,于是,准备再玩一玩梦幻 ...
- Java SpringMVC实现PC端网页微信扫码支付完整版
一:前期微信支付扫盲知识 前提条件是已经有申请了微信支付功能的公众号,然后我们需要得到公众号APPID和微信商户号,这个分别在微信公众号和微信支付商家平台上面可以发现.其实在你申请成功支付功能之后,微 ...
- 使用java做一个能赚钱的微信群聊机器人(2020年基于PC端协议最新可用版)
前言 微信群机器人,主要用来管理群聊,提供类似天气查询.点歌.机器人聊天等用途. 由于微信将web端的协议封杀后,很多基于http协议的群聊机器人都失效了,所以这里使用基于PC端协议的插件来实现. 声 ...
- 管理批量邮箱 FOXMAIL 和网易闪电邮(PC端)有什么区别? 对比
喜欢用FOXMAIL有订阅功能<img src="https://pic1.zhimg.com/fa72df2440f84043a5275b90df30b2f4_b.jpg&q ...
随机推荐
- Programming Model
上级:https://www.cnblogs.com/hackerxiaoyon/p/12747387.html Dataflow Programming Model 数据流的开发模型 Levels ...
- 基于MarkDown和Github图床以及SourceTree的一站式文章编辑和发布
标题: 基于MarkDown和Github图床以及SourceTree的一站式文章编辑和发布 作者: 梦幻之心星 sky-seeker@qq.com 标签: [MarkDown,Github,图床,S ...
- springBoot--集成RocketMQ
1.导入依赖 <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>sprin ...
- 七.数据分页原理,paginator与page对象
1.分页: Paginator对象 Page对象 2.Paginator: class Paginator(object_list, per_page, orphans=0, allow_empty_ ...
- CSS选择器整理以及优先级介绍
一.基础选择器 选择器 名称 描述 兼容性 * 通配选择器 选择所有的元素 ie6+ E 元素选择器 选择指定的元素 ie6+ #idName id选择器 选择id属性等于idName的元素 ie6+ ...
- 如何实现html页面自动刷新
使用场景: 1. 页面需要定时刷新,实时加载数据,需要实时查看监控数据(H5中的WebSocket和SSE可以实现局部刷新) 2. 一定时间之后跳转到指定页面(登录注册之类) 3. 前端开发使用伪数据 ...
- 单调栈之WYT的刷子
好久没更题解了(改题困难的我) 题目描述 WYT有一把巨大的刷子,刷子的宽度为M米,现在WYT要使用这把大刷子去粉刷有N列的栅栏(每列宽度都为1米:每列的高度单位也为米,由输入数据给出). 使用刷子的 ...
- mac篇---使用iTerm2快捷连接SSH
大家都知道使用iTerm2连接shh 使用命令 ssh -p22 root@129.10.10.1,然后输入密码即可. 但是每次都输入还是比较麻烦的.iTerm2为我们提供了快捷的方式.三步即可完成此 ...
- cmake的下载和安装
背景: 最近迷上了 vscode 编辑器, 快速便捷,而且插件丰富,使用起来很爽.既然这样,本身游戏也是用 mingw 加 cygwin 开发的, 可以配置一下,开搞. 实操: 1.登陆cmake官网 ...
- 简单的SQL语句学习
CREATE DATABASE db_test; USE db_test; CREATE TABLE USER( uid INT PRIMARY KEY AUTO_INCREMENT, usernam ...