目标

当前微信网页版限制越来越多,考虑尝试在手机上实现类似机器人的功能。本文目的是利用 Xposed 快速实现简易机器人功能,包括获取好友发来的消息,以及回复消息。后续可以增加智能回复,比如接入图灵机器人,或者自己自定义实现一些功能。

快速实现

项目框架的搭建

WechatSpellbook - 站在"巨人"的肩膀上

WechatSpellbook 是微信巫师作者在微信巫师的基础提取出来的通用微信 Xposed 插件框架。它提供了友好的的 API,提供自动分析微信内部结构特征的API(忽略微信版本差异),对 hook 微信出现的常见问题都做了优化,总之就是使用它会更容易对微信 hook,感谢作者的贡献,项目的集成和详细介绍参见wiki,以下步骤的实现都是基于这个框架的。

以下源码均基于微信 6.6.6 版本,由于使用了 WechatSpellbook 框架动态匹配的原理,大部分微信版本均可自动适配。

获得好友发来的消息

实现机器人功能的首要步骤就是获得好友发来的消息,获得消息之后才能回复吧,才能叫“机器人”吧。

使用了 WechatSpellbook,获取消息是很容易的,参见api,当新消息存入数据库后回调,具体代码:

object WechatMessageHook : IMessageStorageHook {

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

XposedBridge.log("onMessageStorageInserted msgId=$msgId,msgObject=$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=$field_content,field_talker=$field_talker," +

"field_type=$field_type,field_isSend=$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,会生成分析文件。分析步骤如下:

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

image.png

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

image.png

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

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

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

反编译查看源码分析

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

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类的方法,看下源码:

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的方法,看下这个类的源码:

// 截取了几个方法

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 这个方法,然后打印出调用堆栈看看到底是哪里回调了。

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

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

public i(String str, String str2, int i, int i2, Object obj) {

w.d("MicroMsg.NetSceneSendMsg", "dktext :%s", new Object[]{bh.cjG()});

if (!bh.oB(str)) {

cg azVar = new az();

azVar.eV(1);

azVar.ed(str);

azVar.av(bd.in(str));

azVar.eW(1);

azVar.setContent(str2);

azVar.setType(i);

String a = a(((o) g.l(o.class)).s(azVar), obj, i2);

if (!bh.oB(a)) {

azVar.ej(a);

w.d("MicroMsg.NetSceneSendMsg", "NetSceneSendMsg:MsgSource:%s", new Object[]{azVar.fnF});

// 省略很多代码

}

可以看到这个类的构造方法实例化了cg azVar = new az();,并调用了ed()方法。分析下这个构造函数,很有意思的是:参数 str 就是微信 id,str2是文本内容,后几个不知道,大胆猜测下这个类就是去发送消息的,从源码很难分析,hook 掉看看。

hook com.tencent.mm.modelmulti.i的构造方法打印参数,看下是否和发送消息有关。这里就不贴代码和截图了,结论是有关。那可以 hook 这个类的构造方法发送消息啊。

找到的 hook 关键点

com.tencent.mm.ui.chatting.o.FZ(String) 方法,参数是消息文本,调用该方法可以发消息,但是无法设置接收者

com.tencent.mm.modelmulti.i()构造方法,第0个参数是接收者 id,第1个参数是消息文本

机器人回复消息思路:调用第一个 API 发送消息文本,hook 第二个 API 修改接收者 id,然后就可以愉快的发消息了

关键点存在的问题

上述 hook 思路存在的问题:当 hook 第二个API 时,不知道该条消息的接收者是谁,不太好设置。

问题解决方法

既然我能 hook 这两个 API,那么我可不可以直接在调用第一个 API 的时候,将接收者 id 放在文本消息前面,然后在 hook 第二个 API 时将文本消息中的接收者 id 解析出来赋值给第0个参数。

新消息文本 = 接收者ID + 分隔符号 + 真实消息文本

分割符号可以采用特殊字符,用户不会输入的字符,比如 \t 等

代码实现

源码在这里,关键地方都有注释,有兴趣可以 star

效果图

image.png

xposed微信长视频转发_利用 Xposed 快速实现一个简易微信机器人相关推荐

  1. xposed微信长视频转发_实现可以跨版本使用的微信 Xposed 模块

    众所周知的,微信每个版本升级后,变量名都会有一些变化,引起过去的 xposed 模块失效,所以针对微信的 xposed 模块都有版本判断,以便告知用户该模块适应哪个版本.而一旦用户不小心把版本升级了, ...

  2. xposed微信长视频转发_Xposed微信之发送文件

    本帖最后由 randompath 于 2019-8-27 16:34 编辑 本文主要介绍通过静态分析微信发送文件的逻辑,并通过xposed实现文件自动发送.分析的微信版本为当前最新版(v7.0.6), ...

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

    目标 当前微信网页版限制越来越多,考虑尝试在手机上实现类似机器人的功能.本文目的是利用 Xposed 快速实现简易机器人功能,包括获取好友发来的消息,以及回复消息.后续可以增加智能回复,比如接入图灵机 ...

  4. 2020.2idea怎么创建html模块_利用idea快速搭建一个项目

    一.前提准备:电脑安装好jdk1.8,安装好IDEA 二.步骤 1.点击创建一个新项目 2.选择 Spring initializr选项,这是一个非常方便的生成Springboot的工具,确认信息无误 ...

  5. 钉钉一行代码_利用Python快速搭建钉钉和邮件数据推送系统

    前面的文章我们写到了利用Python实现钉钉和邮件的数据推送,在数据处理这一块实现了对mysql和odps的数据获取和处理,可以满足常规业务大部分数据场景需求,在一家初创公司数据基础建设还不完善的时候 ...

  6. 微信小程序是什么?如何快速搭建一个微信小程序?

    目录 一.微信小程序是什么 二.安全管理 三.微信小程序的功能 四.快速开发一个微信小程序APP 1.集成即构实时音视频SDK 2.初始化SDK引擎 3.创建房间与登录房间 4.房主创建房间 5.推流 ...

  7. windows和Linux利用Python快速搭建一个网站

    windows和Linux利用Python快速搭建一个网站 一.windows 步骤1:安装Python3(自行百度) 步骤2:在cmd窗口输入ipconfig查看本机ip地址,IPV4那一行.如:1 ...

  8. Android studio设计一个简易微信界面

    一.设计要求及实现构想 1.设计一个简易微信界面框架,包含至少4个tab页面(我设计的4个分别为message.contact.find.config),要求能实现四个页面之间的点击切换. 2.首先分 ...

  9. 利用java swing编写一个简易的计算器,实现了括号,优先级,三角函数,阶乘等功能

    利用java swing编写一个简易的计算器 背景 效果图 一.默认图 二.计算三角函数 三.阶乘运算 四.常见的四则运算(实现了优先级) 代码 本文借鉴了"初识Java,实现简易计算器(带 ...

最新文章

  1. 对于正交频分复用的异构网络的理解
  2. 解决MySQL报错... right syntax to use near ‘password ‘XXX‘ at line 1...ERROR 1064 42000: You have an erro
  3. 多线程三种同步方式(模拟银行取款)
  4. Python机器学习:评价分类结果005precisoion-Recall的平衡
  5. 从用户空间直接访问系统调用
  6. js引用类型和基本类型、隐式类型转换以及强制类型转换面试题
  7. Quart2D文字图像绘制
  8. 什么是超级浏览器?目前超级浏览器有哪些分类?
  9. iot软件测试,IoT研发测试工程师
  10. 亚马逊服务器443端口开放配置aws
  11. 2023全新纯净版本知识付费微信小程序源码_附搭建教程_亲测可用
  12. 计算机 管理 mmc 注册表,我的注册表没有MMC文件
  13. Mysql时间函数的坑
  14. 软件定义和硬件重构知多少(二)
  15. 汽车动力性仿真matlab程序,汽车理论课程设计:基于Matlab的汽车动力性的仿真
  16. 上海工程技术大学计算机专硕,上海工程技术大学2019年硕士研究生调剂公告
  17. Codeforces Round #143 (Div. 2)-D. Magic Box
  18. 智慧园区BIM智能化系统平台建设方案
  19. 在WIN7中找回你熟悉的记事本字体Fixedsys
  20. 人工智能-逻辑回归、分类评估方法、ROC曲线、类别不平衡

热门文章

  1. 崔炜:全面分析学生行为数据,AI正在改变中国基础教育
  2. PIXHAWK:LED灯意义
  3. 【明解C语言】之do... while循环
  4. 反思:你的装饰公司为什么签单能力差?
  5. 完整解释 Monad -- 程序员范畴论入门
  6. php强行横屏,android强制横屏apk下载
  7. 如何使用winscp工具连接windows(windows to windows)
  8. 【搭建NextCloud私有云盘服务】采用docker在linux上进行部署,内含nextCloud移植(迁移服务器)方法
  9. DIOR HOMME_百度百科
  10. java如何枚举定义一个数组_java 枚举(Enum)笔记