hook 微信信息撤回功能

42 篇文章 9 订阅
15 篇文章 1 订阅

PC端

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

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

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

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

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

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

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

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()

运行测设脚本

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

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

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

 

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

1

2

3

4

5

6

7

8

Interceptor.attach(revokeMsgFunAddr,{

//一旦进入hook的函数,该回调函数就会被调用

     onEnter(args){

      console.log("-----revokeMsg------")

      console.log(this.context.rdi);

      this.context.rdi=0;

     }

});

最终实现的效果:

PC端显示

 

Android端

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

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

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

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

1

2

3

4

5

6

7

8

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"]();

    };

});

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

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

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

1

2

3

4

5

6

7

8

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("内存对象搜索完毕")

       }

   })

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

 

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

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

1

2

3

4

5

let s = Java.use("tj0.s");

s["h"].implementation = function (str, j15, n0Var, str2, str3, str4) {

    console.log(`s.h is called: str=${str}, j15=${j15}, n0Var=${n0Var}, str2=${str2}, str3=${str3}, str4=${str4}`);

    this["h"](str, j15, n0Var, str2, str3, str4);

};

 

 

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

function main() {

    Java.perform(function () {

        Java.enumerateClassLoaders({

            onMatch: function (loader) {

                try {

                    var factory = Java.ClassFactory.get(loader);

                    var s = factory.use("tj0.s");

                    s["h"].implementation = function (str, j15, n0Var, str2, str3, str4) {

                    console.log(`s.h is called: str=${str}, j15=${j15}, n0Var=${n0Var}, str2=${str2}, str3=${str3}, str4=${str4}`);

                    this["h"](str, j15, n0Var, str2, str3, str4);

                   };

                     

                     

                catch (e) {

                    console.log("Error accessing class or method: " + e);

                     

                }

            },

             

            onComplete: function () {}

             

        });

    });

}

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

 

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

Java.perform(function(){

    console.log("==========begain==========")

    let RevokeMsgEvent = Java.use("com.tencent.mm.autogen.events.RevokeMsgEvent");

     

    //hook构造方法

    RevokeMsgEvent["$init"].implementation = function () {

        console.log(`RevokeMsgEvent.$init is called`);

        showStacks();

        this["$init"]();

    };

    function showStacks(){

        console.log(

            Java.use("android.util.Log")    //首先找到log类

            .getStackTraceString(              //调用log类的该方法

                Java.use("java.lang.Throwable").$new()      //new一个对象

            )

        )

    }

});

 

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

1

2

3

4

var sClass=Java.use("ij0.s");

   sClass.i.implementation=function(){

        console.log("======================");

   };

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

 

Xposed实现hook的持久化

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

1

2

3

4

5

6

7

8

Java.perform(function(){

    var sClass=Java.use("ij0.s");

    sClass.i.implementation=function(){

         console.log("======================");

    };

});

xposed代码

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

28

29

30

31

32

33

34

35

36

37

38

39

40

package com.example.xposeddemo;

import android.util.Log;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

import java.util.ArrayList;

import java.util.Map;

import java.util.Objects;

import de.robv.android.xposed.IXposedHookLoadPackage;

import de.robv.android.xposed.XC_MethodHook;

import de.robv.android.xposed.XC_MethodReplacement;

import de.robv.android.xposed.XposedBridge;

import de.robv.android.xposed.XposedHelpers;

import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class Hook implements IXposedHookLoadPackage {

    @Override

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

        if(!loadPackageParam.packageName.equals("com.tencent.mm")) return;

        Class<?> clazz=XposedHelpers.findClass("ij0.s",loadPackageParam.classLoader);

        Log.d("mxy", clazz.toString());

        XposedHelpers.findAndHookMethod(clazz, "i"new XC_MethodReplacement() {

            @Override

            protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {

                Log.d("mxy""hook successfully");

                return null;

            }

        });

    }

}

 

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值