Bootstrap

微信服务器会留撤回的消息吗,让你的微信不再被人撤回消息

处女座强迫症最讨厌别人发消息后撤回了,尤其是发的图片还没看清就被撤了,或者还没来得及看的消息就已经被撤回了。最近逆向工程很火,所以我也简单的逆向了一把微信 for Mac。

为什么不对 iOS 动刀

iOS 上的微信 APP 不一定始终在前台运行着,如果别人在撤回消息时微信在后台甚至手机锁屏、断网,这时很可能没有调用撤回消息的方法,甚至当微信重新返回到前台时,从服务器根本不会接到原来消息的数据,而是只收到了一条『撤回』指令。基于以上猜测,我决定对微信 for Mac 下手,毕竟电脑上的微信只要开着就一直接收消息,Mac 版微信不会跑到后台。

脑洞和胆子都要大

之前看的一些逆向的教程里,感觉前期工作都是装软件配环境,噼里啪啦命令一顿敲,整的挺玄乎,其实都是用人家现成儿的工具做些事情,美其名曰『站在巨人的肩膀上』,这里不再赘述。在我看来第一个真正意义上有难度的事情就是一个字儿:『猜』!

想要凭 dump 出的头文件里面的一堆函数名类名来猜出想要动手脚的地方,的确是个技术活儿。不仅考验脑洞,有时候还得运气好。把应用程序中的微信拖到 Hopper 中,搜下 “revoke”。这不,我一下子就猜出在哪个方法里面处理撤回消息逻辑的了:

5cc95f215ad45a22739fe3782dcd57b7.png

我凭借直觉,认为 -[MessageService onRevokeMsg:] 就是我们要找的方法。事实也证明我是对的,一次成功!先看看这个方法的伪代码:

c496b054adc1732bd2b60981742a3777.png

伪代码里面包含着好多层复杂的 if 判断逻辑,想必是这里复杂的业务逻辑让微信的同事无比抓狂,不要怕,我们不想让后面的事情发生,直接来个return 就万事大吉!按快捷键 『option+A』 或者选择 Hopper 菜单栏的 『Modify -> Assemble Instruction…』来修改第一行汇编语句:

c30459676f9f1b253fcf6de4c83b54eb.png

可能觉得这里直接 return 掉是不是胆子也太大了,其实我还是看了函数里这坨代码的。那么多的 if 判断伴随着的是各种出错场景下的数据上报,真正核心业务逻辑也就是下面这坨:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

r12 = [[MessageData alloc] initWithMsgType:0x2710];

rax = [r12 isSendFromSelf];

rsi = @selector(toUsrName);

if (LOBYTE(rax) != 0x0) {

rbx = [[r13 toUsrName] retain];

[r12 setFromUsrName:rbx];

[rbx release];

rbx = [[r13 fromUsrName] retain];

[r12 setToUsrName:rbx];

}

else {

rbx = [[r13 toUsrName] retain];

[r12 setFromUsrName:rbx];

[rbx release];

rbx = [[r13 fromUsrName] retain];

[r12 setToUsrName:rbx];

}

[rbx release];

[r12 setMsgStatus:0x4];

[r12 setMsgContent:var_58];

[r12 setMsgCreateTime:LODWORD([r13 msgCreateTime])];

[r15 AddLocalMsg:var_50 msgData:r12];

rbx = [[NSArray arrayWithObject:r13] retain];

[r15 DelMsg:var_50 msgList:rbx isDelAll:0x0];

r15 = *objc_release;

[rbx release];

[r12 release];

这段代码先是判断下撤回消息的人是不是自己,然后分情况更新 UI,最后生成并更新数据。既然没有啥重要操作,那就放心地忽略吧哈哈。

现在需要将修改后的汇编重新生成新的可执行文件。选择 Hopper 菜单里的 『File -> Produce New Executable…』 后点 Yes:

1b037ced8873ad6aa871a188fe0eef5b.png

最后将生成的可执行文件替换到 /Applications/WeChat.app/Contents/MacOS/WeChat

唯一让我不解的是无需对新的 WeChat 可执行文件进行代码签名微信依然可以正常运行。我是第一次玩逆向,还请前辈大神们指教。做了一系列撤回消息的尝试后,手机上面显示撤回,但 Mac 版微信的消息依然还在。一次猜中,成功!

后记

其实逆向工程是门很有趣的学问,而任何学问都是入门简单深入难。本例看似容易,其实如果面对更加复杂的环境下,光靠我那点儿可怜的汇编知识肯定是不够的。如果是对 iOS 上的 APP 进行逆向,实则准备工作要麻烦得多。真正掌握了底层的原理和基础知识才是硬道理!

老子终于也当了回标题党!啊哈!

;