利用 Xposed 快速实现一个简易微信机器人

5

6

7

8

9

10

11

12

13

14

15

16

object WechatMessageHook : IMessageStorageHook {
  
  

override fun onMessageStorageInserted(msgId: Long, msgObject: Any) {

XposedBridge.log(“onMessageStorageInserted msgId= m s g I d < / s p a n > , m s g O b j e c t = < s p a n c l a s s = " v a r i a b l e " s t y l e = " c o l o r : r g b ( 200 , 40 , 41 ) ; " > msgId</span>,msgObject=<span class="variable" style="color:rgb(200,40,41);"> msgId</span>,msgObject=<spanclass="variable"style="color:rgb(200,40,41);">msgObject)

// 这些都是消息的属性,内容,发送人,类型等

val field_content = XposedHelpers.getObjectField(msgObject, “field_content”) as String?

val field_talker = XposedHelpers.getObjectField(msgObject, “field_talker”) as String?

val field_type = (XposedHelpers.getObjectField(msgObject, “field_type”) as Int).toInt()

val field_isSend = (XposedHelpers.getObjectField(msgObject, “field_isSend”) as Int).toInt()

XposedBridge.log(“field_content= f i e l d c o n t e n t < / s p a n > , f i e l d t a l k e r = < s p a n c l a s s = " v a r i a b l e " s t y l e = " c o l o r : r g b ( 200 , 40 , 41 ) ; " > field_content</span>,field_talker=<span class="variable" style="color:rgb(200,40,41);"> fieldcontent</span>,fieldtalker=<spanclass="variable"style="color:rgb(200,40,41);">field_talker,” +

“field_type= f i e l d t y p e < / s p a n > , f i e l d i s S e n d = < s p a n c l a s s = " v a r i a b l e " s t y l e = " c o l o r : r g b ( 200 , 40 , 41 ) ; " > field_type</span>,field_isSend=<span class="variable" style="color:rgb(200,40,41);"> fieldtype</span>,fieldisSend=<spanclass="variable"style="color:rgb(200,40,41);">field_isSend)

if (field_isSend == 1) { // 代表自己发出的,不处理

return

}

// 做其他事情

}

}

其中字段名含义如下:

  • field_content: 消息内容

  • field_talker: 发送者

  • field_type: 消息类型

  • field_isSend: 是谁发出的,我自己发出为1

    这步到此就完成了,下一步是机器人怎么将消息回复给好友。

机器人回复消息

机器人回复消息需要找到发送消息出去这个 API,然后 hook 它,在我们的代码里调用就行了。

利用 Monitor 的 Method Profiling 功能分析

首先在模拟器中打开微信聊天窗口,打开 Monitor,选中微信进程,点击Start Method Profiling,然后在聊天窗口随便发送一条消息,然后回来点击Stop Method Profiling,会生成分析文件。分析步骤如下:

  1. 先搜索 click,点击发送按钮,肯定是触发了点击事件的嘛,先找找看

    image.png

    image.png

  2. 发现调用了 ChatFooter$3.onClick() 方法,单从名字上来看,应该就是这里了,点进去,看这个函数调用了哪里

    image.png

    image.png

  3. 它调用了 chatting.o.FZ 方法,注意参数是 String,返回值是 Boolean,大胆猜测一下,这个字符串就是消息文本,返回值应该是发送是否成功。验证一下,直接 Hook 这个函数,运行发现猜测是真的,这里比较简单就不贴代码了。

  4. 分析到这里,已经知道了chatting.o.FZ 方法就是发送消息的,参数就是消息文本,但是有个很重要的地方忽略了,为什么没有接收者参数?,微信内部联系人 ID 一般是以 wx_idxxx 开头的,接收者 id 设置在哪,怎么设置 hook,现在就差这个问题了。

    到这里已经知道了发送消息的 API,hook 掉就可以搞事情了,但是缺少接收者这个重要参数的设置,分析下源码吧。

反编译查看源码分析

反编译之后分析 chatting.o.FZ 方法源码:

1

2

3

4

5

public final boolean FZ(String str) {
  
  

mS(false);

ctQ();

return this.yOg.yRO.dt(str, 0);

}

然后分析yOg.yRO.dt方法,它是com.tencent.mm.ui.chatting.b类的方法,看下源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public final boolean dt(String str, int i) {
  
  

int i2 = 0;

String Xf = bh.Xf(str);

if (Xf == null || Xf.length() == 0) {

w.e(“MicroMsg.ChattingUI.TextImp”, “doSendMessage null”);

return false;

}

x xVar = this.yXC;

if (!ah.oB(Xf)) {

az azVar = new az();

azVar.setContent(Xf);

azVar.eW(1);

xVar.aB(azVar);

}

bt btVar = new bt();

// 省略

}

可以看到在azVar.setContent(Xf);这里将发送的消息文本放在放在了az这个类中,setContent() 是 az 的父类com.tencent.mm.g.c.cg的方法,看下这个类的源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

// 截取了几个方法

public final void av(long j) {

this.field_createTime = j;

this.eRw = true;

}

public final long wQ() {

return this.field_createTime;

}

public final void ed(String str) {

this.field_talker = str;

this.feh = true;

}

public final String wR() {

return this.field_talker;

}

public final void setContent(String str) {

this.field_content = str;

this.eRE = true;

}

只截取了几个方法,可以看到这个类不仅仅包含消息文本,还包含了接受者field_talker,发送时间field_createTime等,大胆猜想,这个类就是消息的包装类,包含消息所有的属性,这里关注的字段是接收者 field_talker,只要知道在哪里调用了ed方法 hook 掉就可以为所欲为了。

但是,通过 AS 查找调用这个的地方有很多,根本无法判断具体发消息是哪里调用了,怎么办。

借助 Xposed 分析com.tencent.mm.g.c.cg.ed()方法,也就是设置接收者 field_talker 的方法,只要 hook 这个方法,然后打印出调用堆栈看看到底是哪里回调了。

1

2

3

4

5

6

7

8

val clz = XposedHelpers.findClass(“com.tencent.mm.g.c.cg”, WechatGlobal.wxLoader)

XposedHelpers.findAndHookMethod(clz, “ed”, String::class.java, object : XC_MethodHook() {

override fun beforeHookedMethod(param: MethodHookParam?) {

log(“set field_talker start”)

LogUtil.logStackTraces() // 打印调用堆栈

log(“set field_talker end”)

}

})

打印结果:

image.png

image.png

可以看到函数调用链,关键点在 com.tencent.mm.modelmulti.i.<init> ,看下这个方法的源码:

1

2

3

-right:20px;padding-left:0px;font-size:.85em;line-height:22.4px;color:rgb(114,114,114);font-family:Consolas, Monaco, courier, monospace;text-align:right;background:rgb(245,245,245);">1

2

3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值