Windows 版微信防撤回

公司相关的微信群太多了,导致经常会有人错发消息,出于对撤回内容的好奇下,最近研究了下如何防撤回,微信撤回消息相关函数实现在 WeChatWin.dll 中,我的想法是要么 hook 相关函数,或者直接改 WeChatWin.dll 的指令逻辑,后者实现起来简单点,就先尝试下。

首先电脑端先登录微信,然后打开 x32dbg,在菜单里找到「文件」 > 「附加」,附加窗口中找到「wechat」,然后附加上去。

接着在菜单「视图」 > 「模块」,找到加载的 WeChatWin.dll,并双击。

在 WeChatWin.dll 的反汇编窗口中点右键,选择「搜索」 > 「当前模块」 > 「字符串」,搜索“revokemsg”,此时会列出一堆搜索结果,需要去逐个甄别哪个才是真正的函数调用,最后我发现字符串是「"revokemsg"」(注意有双引号)的才是函数调用,其它什么“L”开头的、“<revokemsg>”均不是。双击它,看到的关键汇编代码如下:

69F8B0F2 | 32DB                     | xor bl,bl                               | 循环开始
69F8B0F4 | 8B45 94                  | mov eax,dword ptr ss:[ebp-6C]           |
69F8B0F7 | C785 60FFFFFF 30E31F6B   | mov dword ptr ss:[ebp-A0],wechatwin.6B1 |
69F8B101 | 3D C07C526B              | cmp eax,wechatwin.6B527CC0              |
69F8B106 | 74 09                    | je wechatwin.69F8B111                   |
69F8B108 | 50                       | push eax                                |
69F8B109 | E8 64E8BB00              | call wechatwin.6AB49972                 |
69F8B10E | 83C4 04                  | add esp,4                               |
69F8B111 | 8D8D 60FFFFFF            | lea ecx,dword ptr ss:[ebp-A0]           |
69F8B117 | E8 44496F00              | call wechatwin.6A67FA60                 |
69F8B11C | 8D4D C0                  | lea ecx,dword ptr ss:[ebp-40]           |
69F8B11F | E8 0C932800              | call wechatwin.6A214430                 |
69F8B124 | 8D4D 08                  | lea ecx,dword ptr ss:[ebp+8]            |
69F8B127 | E8 04932800              | call wechatwin.6A214430                 |
69F8B12C | 8AC3                     | mov al,bl                               |
69F8B12E | 8B4D F4                  | mov ecx,dword ptr ss:[ebp-C]            |
69F8B131 | 64:890D 00000000         | mov dword ptr fs:[0],ecx                |
69F8B138 | 59                       | pop ecx                                 |
69F8B139 | 5F                       | pop edi                                 |
69F8B13A | 5E                       | pop esi                                 |
69F8B13B | 5B                       | pop ebx                                 |
69F8B13C | 8B4D F0                  | mov ecx,dword ptr ss:[ebp-10]           |
69F8B13F | 33CD                     | xor ecx,ebp                             |
69F8B141 | E8 7EE4BB00              | call wechatwin.6AB495C4                 |
69F8B146 | 8BE5                     | mov esp,ebp                             |
69F8B148 | 5D                       | pop ebp                                 |
69F8B149 | C3                       | ret                                     |
69F8B14A | 8B06                     | mov eax,dword ptr ds:[esi]              |
69F8B14C | 8BCE                     | mov ecx,esi                             |
69F8B14E | FF50 18                  | call dword ptr ds:[eax+18]              |
69F8B151 | 85C0                     | test eax,eax                            | 判断是否有撤回
69F8B153 | 74 9D                    | je wechatwin.69F8B0F2                   | 这里是个循环,如果没有撤回消息,控制流就跳到循环开始处,否则就继续向下执行
69F8B155 | 68 DCBF266B              | push wechatwin.6B26BFDC                 | 6B26BFDC:"revokemsg"
69F8B15A | 8BC8                     | mov ecx,eax                             |
69F8B15C | E8 DF4B6F00              | call wechatwin.6A67FD40                 | 调用消息撤回函数

把这段理解成一个循环判断是否有撤回消息,着手点在这一段代码上:

call dword ptr ds:[eax+18]
test eax,eax
je wechatwin.69F8B0F2
push wechatwin.6B26BFDC
mov ecx,eax
call wechatwin.6A67FD40

为了不让调用到最后句撤回消息函数,有两个选择:

1、把 je 指令改成 jmp,让指令永远跳不到最后一句 call 指令;

2、把最后句 call 指令用 nop 替换掉。

相比之下我觉得修改 je 指令稳妥点,选中 je 指令那行,点右键,选择「汇编」,把 je 改为 jmp,然后勾选「保持大小」和「剩余字节以 NOP 填充」。

最后点右键,选中「补丁」,补丁窗口中会列出修改的内容,确认无误后点「修补文件」,把导出补丁后的 WeChatWin.dll 放到微信目录下覆盖原本的即可。