微信 macOS 客户端拦截撤回功能实践
微信的小贱人特多,尤其是群里的,老喜欢撤回,还有一大堆的跟风党起哄党…当然少不了一些手抖发错的,嘿嘿嘿。好奇心如此强的我怎能错过这些消息!
一、原理
要拦截撤回的消息,首先就要知道当客户端接收到撤回消息的通知时候,执行一个方法来撤回消息:
服务端 ---发送撤回通知---> 客户端接收 ---> 执行撤回消息的方法(删除本地消息,刷新UI,提示消息被撤回)
所以我们需要做修改的这个入口就是执行撤回消息的这个方法,让其不删除本地的消息就可以了。
二、准备
在OS X环境下逆向工具有以下几个大杀器:
- Hopper Disassembler - 反编译工具,能够将二进制执行文件反编译出伪代码
- class-dump - 导出可执行文件的Class Header
- Hexfiend - 二进制文件编辑器
- gdb - 调试神器,不用多介绍啦,通过
brew install gdb
安装 - otx - 同上,貌似比较小众,通过
brew install --HEAD homebrew/head-only/otx
安装
当然还有App Store下载最新版的微信OS X客户端一份。
三、Dump出头文件
首先肯定要先知道WeChat这个App有哪些方法,并猜测出撤回消息的这个方法在那个Class中,因此利用Class-Dump
是最好不过的了,先把/Applications/WeChat.app/Contents/MacOS/WeChat
复制一份到Class-Dump
的相同目录下,然后直接执行:class-dump -H WeChat
,目录下就会dump出了大量的.h文件。
不难想到撤回这个英文应该是Recall
,用英文版的微信就知道啦,可以直接通过Finder的搜索条搜索Recall
,找出包含Recall
的头文件:
有趣的是,包含Recall
的方法比较少,而且按照方法名好像也不太相关,但其中一个方法成功吸引了我的注意:- (void)onRevokeMsg:(id)arg1
,这是在MessageService.h
里面的一个方法,值得一试!
四、反编译
打开Hopper Disassembler
,并在菜单栏中选择File
->Read Executable to Disassemble
,接下来就得等一段时间了,毕竟WeChat的这个二进制可执行文件有30多M。
等待Hopper Disassembler Load完之后,大概是这样的:
是不是觉得很可怕
但是,我们应该要特么地冷静下来,因为我们已经掌握了疑似撤回消息的方法名,在右侧上方的搜索栏中搜索onRevokeMsg
,就能快速定位到方法的位置了,想要看懂这对奇怪的东西,就要生成伪代码,通过伪代码来看逻辑,点击右上角的这个按钮:
这就是传说中的伪代码,通过观察,找到了以下的这段代码:
结果非常明显了,标注的两个方法分别是删除被撤回的消息和添加一条撤回成功的消息,所以证明了以上定位的方法onRevokeMsg
正是撤回消息的方法,我们只要从这里入手就可以实现拦截撤回的功能了。
五、修改onRevokeMsg方法
这一步我就直接采用简单暴力有效的方法了,直接干掉onRevokeMsg
方法,不执行内部逻辑操作,选中-[MessageService onRevokeMsg:]:
下方的一行:
快捷键:Alt + A
并输入ret
,点击Assemble and Go Next
其中
ret
的意思就是Return
,当执行到这个方法的时候直接就Return了,屏蔽了下面的所有操作。
六、重新生成可执行文件
在菜单栏中选择File
->Produce New Executable
,提示是否清除签名信息选择Yes
就可以了,然后保存到任意位置,然后覆盖/Applications/WeChat.app/Contents/MacOS/
下的WeChat
,至此所有的操作都已经完成了。
打开OS X微信客户端登陆,并在手机随便找个基友给他发条消息然后撤回,在OS X微信客户端可以发现毫无动静,消息没有撤回,可见这次实践非常成功(=゚ω゚)ノ
最后
当然除了修改二进制文件能够暴力实现拦截撤回的功能,也可以通过dylib对微信客户端进行hook,替换乘自己的方法,这样能够更加灵活并可以有更多的玩法,例如实现撤回消息发出通知等效果。再研究研究吧~
已经以更优雅的动态库注入方式实现拦截撤回功能,具体实现参考:https://github.com/Sunnyyoung/WeChatHook-macOS