我知道手机上可以开设多个微信账号。 华为、小米等手机系统均支持此。 不过,如何在运行该系统的电脑上激活两个微信账号却引起了我的好奇。
小林告诉我,他是这样做的,写了一个批处理过程:
start D:\WeChat\WeChat.exe start D:\WeChat\WeChat.exe
然后直接双击批处理文件即可启动两个微信进程。
我尝试了一下,果然有效!
然后我又添加了一行,然后我又可以开始另外 3 行:
然后我在网上搜索了一下,发现这个技巧很早以前就被别人用过了。 看来我是在火星上。 但为什么我可以通过这种方式打开更多的门呢? 我真的很想知道其中的奥秘。
TIPS:如果你对技术分析部分不感兴趣,可以跳过,直接看最后的真相部分。
微信的单例模式
一般情况下,直接双击微信图标即可启动。 稍后启动的进程将检查全局单例模式。 如果发现微信进程已经存在,则直接激活对应进程的微信窗口,定位到桌面最前面,然后自行退出。 。
但是为什么我们可以用上面的方法来启动呢? 让我们来看看吧。
首先我们来分析一下上面介绍的微信单实例是如何实现的。
做过平台应用开发的朋友可能对此比较熟悉。 通常,进程启动后会创建一个具有全局唯一名称的互斥体。 如果创建成功,则可以正常启动。 如果创建失败,会判断互斥体是否已经存在。 如果已经存在,则说明之前已经启动过相应的程序。
有了这个猜想,使用工具查看微信进程打开的所有内核对象,找到互斥部分:
果然,其中有一个互斥体的名字。 从这个名字我们就可以猜测,这肯定和微信的单例模式有关。
接下来启动该,它可以帮助你监控指定进程的API调用,查看两个API函数。 当微信已经运行时,使用该工具启动另一个微信进程,看一下函数调用:
可以看出,创建该名称的互斥锁后,该函数随后被调用并返回。 检查手册了解其含义:
表明它已经存在。
让我们看一下调用堆栈,看看代码在哪里创建全局互斥体:
从堆栈中可以看出,调用来自微信目录下的一个动态库.dll。 具体位置就是偏移处的上一条指令。
接下来就是要拿出精华中的精华了,著名的反汇编软件IDA。 这个家伙支持多种处理器架构(例如 x86、x64、ARM、MIPS 和 JVM)上的程序分析。
使用 IDA 打开这个 .dll 文件并找到偏移量:
如上图所示,创建互斥体的动作发生在函数中。
上层是调用它的函数:
上图体现了创建互斥体后的判断逻辑:
问题就出在上面的判断上。 汇编代码看起来有点抢眼。 我们用F5来还原C代码(还原效果还算可以,只要能看清楚逻辑即可):
上图的注释已经说明了,函数的返回值会决定是启动微信实例进程还是直接退出。
只有一个真理
至此真相已经明朗了,我们来总结一下。
微信判断是否启动的两个条件:
让我们用伪代码来表达:
if (CreateMutex() == SUCCESS) { 启动微信 } else { if (FindWindow() == SUCCESS) { 将已有窗口置顶 } else { 启动微信 } }
对于直接使用脚本启动的多个进程,虽然操作系统内核层面保证了互斥量的唯一性,但由于启动速度差不多,相应的窗口还没有创建出来,导致出现上面的第二个启动逻辑。 ,允许启动多个实例。
小发现
在分析过程中,发现了一个有趣的事情:
在.dll中,上面创建互斥体的上层函数的名称也被DLL作为导出函数导出:
我不知道我把微信地址写在这里是有意还是无意。 如果是笔误的话,这位程序员同学看到后应该是偷偷改正的。