首页
社区
课程
招聘
[原创]hook 微信信息撤回功能
发表于: 2024-6-3 02:26 33322

[原创]hook 微信信息撤回功能

2024-6-3 02:26
33322

b站刷到一位老师分享了hook pc端微信信息撤回功能的视频,跟着动手操作了一遍之后,尝试了一下hook Android端的微信,下面分享一下学习过程。

视频链接:广东财经大学-信息安全-基于IDA Pro和Frida的微信消息撤回无效实验_哔哩哔哩_bilibili

PC端那位老师已经演示的很清楚了,我就简单的复述一遍,感兴趣的可以看一下视频。

微信的核心功能都是在WeChatwin.dll(windows下)里实现的,信息撤回也不例外。

我们使用ida分析,通过字符串进行定位,试试相关的字符,如:撤回、revoke、withdrawn等关键字

我们逐一hook使用到这些字符串的函数,然后点击微信的撤回,如果有log输出,就代表是关键函数。

测试脚本如下,首先我们获取了dll的加载地址,然后通过ida查看到函数的偏移地址,将dll地址加上该偏移地址,即可得到内存中该函数的地址,那么如何确定哪一个才是撤回相关函数? 就是靠试,使用到msg相关字符串的函数我们都hook一遍,然后触发撤回功能,如果打印出来revokeMsg就说明hook成功。

运行测设脚本

当我们测试到字符串SyncMgr::ProcessRevokeMsg所在的函数时,有了revokeMsg的回显

函数逻辑比较复杂,hook点也是比较难找

但是我们知道每次撤回信息,这个函数都要被调用,我们直接查看他的交叉引用,发现这个函数在一个switch语句里被调用

我们只需要让这个不为4,这里就不会被执行

edi为4的时候就会执行撤回相关的函数,修改思路就是当程序运行到这里时修改edi寄存器的值

最终实现的效果:

PC端显示

移动端 消息1 已经被撤回

大致思路也是向PC端演示的那样,但是因为没有参考的教程,所以走了不少弯路

还是直接搜索字符串进行定位,考虑到PC端那里时revoke关键字,所以也是直接搜索revoke

其实也不用逐个尝试,因为有几个特别明显的,hook这几个特别明显的方法测试就行

直接右键方法名选择复制为frida片段即可,最终是定位到了这个RevokeMsgEvent方法,每当我们撤回信息,都会打印 RevokeMsgEvent.$init is called

这个方法其实没啥有价值的东西,尝试了直接置空这个方法,也就是将上面的 this["$init"](); 直接删除,并没有起到什么效果

然后就是查看了这个方法的交叉引用

整个程序只有这一出引用,微信应该做了一些混淆,名字都奇奇怪怪的,可读性很差,一时见不知从何下手。首先尝试了修改RevokeMsgEvent的赋值,它将 变量赋值为falsethis.f153351e = false;,我尝试了一下将该变量赋值为true,注意没有f153351e,这是jadx帮它命名的,实际的变量名是e

修改成功,但是信息还是被撤回。

这条路行不通就考虑另外的方案,hook掉调用这个方法的方法,和pc端相同的操作

该方法是被s类下的h方法所调用的,复制h方法的frida片段进行hook

报错,提示没有找到tj0.s这个类,于是我想这个类可能不是被默认的类加载器所加载的,遍历一下所有的类加载器然后再hook

结果遍历了所有的类加载器也没有这个类

而且我使用objection打印加载的类也没有这个tj0.s

最后想到了打印方法的调用堆栈

通过函数的调用堆栈,发现RevokeMsgEvent是被ij0.s.i方法调用的,我们直接将这个方法置空

最终实现的效果,左边是pc显示的,右边是手机显示的

使用xposed将上面的代码重写一下即可,frida逻辑如下

xposed代码

这个xposed等价的应该是没什么问题的,但是就是hook不上这个i方法,也尝试了使用算法助手,都是以失败告终

后续如果找到解决方案我会进行更新。。。。。。。
大哥们如果知道什么问题的话麻烦在评论区指点指点 >_<

小结:

写hook代码很简单,难的是分析的过程,如果定位到了关键代码,只需要短短几行代码就能成功hook。

import frida,sys
 
# 创建脚本
jsCode="""
 
//写入js脚本 就和之前一样
//下面的代码获取dll的加载地址
const baseAddr=Module.findBaseAddress('WeChatWin.dll');
console.log("baseAddr:"+baseAddr);
 
//每次需要修改的只有这里
const revokeMsgFunAddr=getRealAddr('0x1823CD710');
console.log("function addr:",revokeMsgFunAddr);
 
//根据地址进行frida注入
Interceptor.attach(revokeMsgFunAddr,{\
//一旦进入hook的函数,该回调函数就会被调用
     onEnter(args){
      console.log("-----revokeMsg------")
     }
});
 
//dll地址加上偏移地址,定位到这个函数
function getRealAddr(addr){
  //基地址
  const idaBase=ptr('0x180000000');
  const offset=ptr(addr).sub(idaBase);
  const result=ptr(baseAddr).add(offset);
  return result;
}
 
"""
 
#使用任务管理器查看微信的PID然后填入
session = frida.attach(7876)
 
# 运行脚本
script = session.create_script(jsCode)
 
script.load()
print("Successfully attached!!!!")
 
 
# 防止运行完进程直接退出
sys.stdin.read()
import frida,sys
 
# 创建脚本
jsCode="""
 
//写入js脚本 就和之前一样
//下面的代码获取dll的加载地址
const baseAddr=Module.findBaseAddress('WeChatWin.dll');
console.log("baseAddr:"+baseAddr);
 
//每次需要修改的只有这里
const revokeMsgFunAddr=getRealAddr('0x1823CD710');
console.log("function addr:",revokeMsgFunAddr);
 
//根据地址进行frida注入
Interceptor.attach(revokeMsgFunAddr,{\
//一旦进入hook的函数,该回调函数就会被调用
     onEnter(args){
      console.log("-----revokeMsg------")
     }
});
 
//dll地址加上偏移地址,定位到这个函数
function getRealAddr(addr){
  //基地址
  const idaBase=ptr('0x180000000');
  const offset=ptr(addr).sub(idaBase);
  const result=ptr(baseAddr).add(offset);
  return result;
}
 
"""
 
#使用任务管理器查看微信的PID然后填入
session = frida.attach(7876)
 
# 运行脚本
script = session.create_script(jsCode)
 
script.load()
print("Successfully attached!!!!")
 
 
# 防止运行完进程直接退出
sys.stdin.read()
Interceptor.attach(revokeMsgFunAddr,{
//一旦进入hook的函数,该回调函数就会被调用
     onEnter(args){
      console.log("-----revokeMsg------")
      console.log(this.context.rdi);
      this.context.rdi=0;
     }
});
Interceptor.attach(revokeMsgFunAddr,{
//一旦进入hook的函数,该回调函数就会被调用
     onEnter(args){
      console.log("-----revokeMsg------")
      console.log(this.context.rdi);
      this.context.rdi=0;
     }
});
Java.perform(function(){
    console.log("==========begain==========")
    let RevokeMsgEvent = Java.use("com.tencent.mm.autogen.events.RevokeMsgEvent");
    RevokeMsgEvent["$init"].implementation = function () {
        console.log(`RevokeMsgEvent.$init is called`);
        this["$init"]();
    };
});
Java.perform(function(){
    console.log("==========begain==========")
    let RevokeMsgEvent = Java.use("com.tencent.mm.autogen.events.RevokeMsgEvent");
    RevokeMsgEvent["$init"].implementation = function () {
        console.log(`RevokeMsgEvent.$init is called`);
        this["$init"]();
    };
});
Java.choose("com.tencent.mm.autogen.events.RevokeMsgEvent",{//遍历内存中的所有对象
       onMatch:function(obj){ 
           obj.e.value=true;
           console.log("value  : ",obj.e.value);
       },onComplete:function(){  
           console.log("内存对象搜索完毕")
       }
   })
Java.choose("com.tencent.mm.autogen.events.RevokeMsgEvent",{//遍历内存中的所有对象
       onMatch:function(obj){ 
           obj.e.value=true;
           console.log("value  : ",obj.e.value);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 11
支持
分享
最新回复 (10)
雪    币: 1445
活跃值: (1575)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
厉害啊,大佬
2024-6-5 21:02
0
雪    币: 2354
活跃值: (3907)
能力值: ( LV6,RANK:81 )
在线值:
发帖
回帖
粉丝
3
看完了,我现在强得可怕
2024-6-6 10:54
3
雪    币: 1426
活跃值: (1455)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
KingSelyF 看完了,我现在强得可怕
牛的
2024-6-6 17:34
0
雪    币: 243
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
留个联系,大佬,互相交流,我的OO36811
2024-6-10 14:36
0
雪    币: 242
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
电脑版的好像没有这么复杂,之前看过 好像改一个jmp就可以实现了
2024-6-13 22:48
1
雪    币: 8641
活跃值: (6604)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
7
magisk有个模块frida inject,就可以在每次启动的时候注入hook了
2024-6-16 15:00
1
雪    币: 17
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
大佬,能帮写个vx的恶搞红包吗,业面一样,但点击就跳转到指定网页
2024-7-2 01:07
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
想做个群发助手增加个全选但是没hook对地方,楼主有思路么
2024-8-22 14:48
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
w2w
10
2024-8-22 16:58
1
雪    币: 207
活跃值: (144)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
paly版本直接干掉RevokeMsgEvent就行,但是这样撤回也没有提示了,有没有办法既阻止又加上提示
2024-9-10 14:13
0
游客
登录 | 注册 方可回帖
返回
//