搜一搜网上的文章,很多以前的大佬都是通过hook掉 updateWithOnConflict函数,当type=1000时,判断出撤回信息的id,然后重新插入数据库,并修改“xx撤回一条信息”为“xx撤回信息失败”。
猜想这个过程可能分为三步
1.接收到某某发出的一条信息
2.接收到某某撤回了一条信息,删除或者替换这条信息
3.插入文字“某某撤回了一条信息文字”
通过monitor方法回溯或者直接hook函数 updateWithOnConflict作为突破口,因为发送消息肯定要与数据库交互,而处理数据库信息很有可能用到这个函数,手动狗头
我们先正常发一条消息,查看hook结果
函数原型updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm)
向测试手机发送haha,拼接数据库语句为
update rconversation set msgType=1 flag=1579779746000 content=haha
digestUser= digest=haha lastSeq=707367243 msgCount=33 isSend=0
hasTrunc=1 unReadCount=1 conversationTime=1579779746000
username=wxid_dajiadebaba status=3 where username=wxid_dajiadebaba
hook update start
a1:rconversation
a2:msgType=1 flag=1579779746000 content=haha digestUser= digest=haha
lastSeq=707367243 msgCount=33 isSend=0 hasTrunc=1 unReadCount=1
conversationTime=1579779746000 username=wxid_dajiadebaba status=3
a3:username=?
a4:wxid_dajiadebaba
a5:0
堆栈信息如下,这个下面分析撤回的堆栈信息时要用
下面我们撤回这条信息,发现updateWithOnConflict这个函数被调用了3次,也就是说一次撤回包含着3次数据库更新
hook update start
a1:message
a2:msgId=38 type=10000 content="baba" 撤回了一条消息
a3:msgId=?
a4:38
a5:0
hook update start
a1:rconversation
a2:msgType=10000 flag=1579779746000 digestUser= digest="baba" 撤回了一条消息
isSend=0 hasTrunc=1 unReadCount=0 conversationTime=1579779746000
content="baba" 撤回了一条消息 username=wxid_dajiadebaba status=3
对比a2:msgType=1 flag=1579779746000 content=haha digestUser= digest=haha
lastSeq=707367243 msgCount=33 isSend=0 hasTrunc=1 unReadCount=1
conversationTime=1579779746000 username=wxid_dajiadebaba status=3
a3:username=?
a4:wxid_dajiadebaba
a5:0
hook update start
a1:rconversation
a2:UnReadInvite=0 atCount=0
a3:username= ?
a4:wxid_dajiadebaba
a5:0
拼接数据库语句为
update message set :msgId=38 type=10000 content="baba" 撤回了一条消息 where msgId=38
update rconversation set msgType=10000 flag=1579779746000 digestUser=
digest="baba" 撤回了一条消息 isSend=0 hasTrunc=1 unReadCount=0
conversationTime=1579779746000 content="baba" 撤回了一条消息
username=wxid_dajiadebaba status=3 where msgId=38 where
username=wxid_dajiadebaba
update rconversation set UnReadInvite=0 atCount=0 where username=wxid_dajiadebaba
这里msgType=10000 很重要,我们刚才成功发送的msgType=1,放过来对比一下,content从haha变成"baba" 撤回了一条消息
a2:msgType=10000 flag=1579779746000 digestUser= digest="baba" 撤回了一条消息
isSend=0 hasTrunc=1 unReadCount=0 conversationTime=1579779746000 content="baba" 撤回了一条消息 username=wxid_dajiadebaba status=3
a22:msgType=1 flag=1579779746000 content=haha digestUser= digest=haha lastSeq=707367243 msgCount=33
isSend=0 hasTrunc=1 unReadCount=1 conversationTime=1579779746000 username=wxid_dajiadebaba status=3
第一句update message这个表,还附带 msgId,这个 msgId应该就是待撤回的msg的id,猜测这一句的功能就是通过 msgId删除msg,替换为"baba" 撤回了一条消息。
第二句就是更新界面了。
第三句,字面意思就是更新 rconversation未读信息的计数,跟防撤回关系不大。
其实到了这里,我们已经可以通过判断 msgType是否=1000判断是否需要撤回信息,
如果要撤回,先得到要撤回的msgId,调用相关函数重新插入数据库就能实现防撤回了,
类似的文章如下:
简书大佬的防撤回https://www.jianshu.com/p/fb16ea7b28bf
很明显,updateWithOnConflict必定有上层函数直接判断是否撤回,如果判断撤回,调用更下面的逻辑才会到updateWithOnConflict和delete类似函数完成撤回功能的删除和更新。如果我们hook上层函数,可以直接屏蔽掉撤回功能,而不需要先通过判断
msgType是否=1000判断是否需要撤回信息,如果要撤回,得到要撤回的msgId,再调用相关函数重新插入数据库
于是,我们再一次分析函数流程,撤回haha这句消息,打印updateWithOnConflict堆栈如下
这里先点出重点函数吧,后面再具体分析流程,懒得看同学的就看到这里结束吧,
关键函数在com.tencent.mm.model.f类里面,为什么关注这个model呢,因为正常接受信息没有走这个类,还有com.tencent.mm.plugin.messenger.foundation类,应该在更上层,
类比django的mvc框架,猜想model也是封装了和数据库交互的上层,
1.com.tencent.mm.model.f.a(SourceFile:145) m34535a;
2.com.tencent.mm.model.f.a(SourceFile:352) mo7343a;
函数mo7343a调用了m34535a,这里我们直接看mo7343a,南极公司对jadx做了小动作,导致反编译失败,具体原因估计还是变量太多,但我们还有gjden
大佬的神器gda,这是真正的大佬,给大佬打个广告http://www.gda.wiki:9090/blog_list0.php,虽然也不算完美,一大堆的寄存器变量,但是肯定比看smali好多了,我们把gda反编译的代码粘过来看
我们一眼就看到了这一句p0.equals("revokemsg"),revokemsg不就是撤回消息吗,很明显,p0=revokemsg时,跳转进入撤回的逻辑,
p1是一个Map,v5 = p1.get(".sysmsg.revokemsg.newmsgid"); v6 = p1.get(".sysmsg.revokemsg.replacemsg");存储着msgid和replacemsg,
而这句话实现了具体功能 f.a(c.ajB().ak(p1.get(".sysmsg.revokemsg.session"),
bo.getLong(v5, 0)), p2, v6, "MicroMsg.BigBallSysCmdMsgConsumer");
我们直接hook这个函数,当p0=revokemsg时直接返回就可以屏蔽掉撤回了;粗略一看,这个函数还控制着添加联系人,更新包等功能,大家有兴趣可以具体跟一下。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-3-7 12:35
被挤蹭菌衣编辑
,原因: