内容简介

微信自动回复插件,基于 Xposed 开发,可以给女朋友一个聊天机器人,她再也不会打扰我们敲代码了!

前介

现如今最常用的社交工具是什么呢?必然是 微信 ,不得不说现在的微信不在简简单单是一个社交程序,它已经和我们生活紧密相关了。

做为一个程序员?最重要的是什么呢?。

我认为做为一个程序员最重要的是 

但是做为一个程序员进程没日没夜的敲代码,经常没有时间回复女朋友的微信或者 尬聊

 

 我做为一个资深的程序员,怎么能被这种小挫折打败呢?我们要用程序的去维护我们的 娇妻因此我要开发一款自动回复女朋友消息的微信插件。

你的 娇妻 再也不能打断你 打游戏 丶 敲代码丶 风流快活 ,让你的 娇妻 和机器人聊吧(维护家庭和谐)!

确定目标

  1. 自动回复高情商话术
  2. 微信无感知回复,在后台也不能遗漏回复
  3. 开关设置,能指定自动回复的娇妻
  4. 热修复,兼容多版本微信
  5. 找到女朋友

方案定制

我个人习惯,再开发之前,先做准备。把思路屡清楚事半功倍。

自动回复高情商话术

我的第一想法是先去下载类似 恋爱话术 的 App ,然后逆向其接口,接入我们的程序。

nagios 微信机器人 ios微信机器人插件_编程语言

本人下载了将近 10 款这种类型的应用,最终都发现收费很贵,并且话术都不是很全,最后放弃了。

然后找到了 图灵机器人 ,提供完整的聊天机器人 API,并且话术还是很精湛的,因此果断注册开发者账号。

微信无感知回复,在后台也不能遗漏回复

这种没有很好的办法,因为要想在后台回复,只能想办法向微信注入我们的代码(也就是说我们的代码要在微信的进程中运行,在专业点就是我们要想办法拿到微信的 ClassLoader)。

我的方案还是使用 Xposed 框架 + 分身大师 实现免 Root 注入。

如何开发 Xposed 插件,请参看本人文章 查看链接

开关设置,能指定自动回复的娇妻(我们的娇妻可不止一个)

逆向分析微信的聊天界面,找一个合适的地方,通过 Xposed 注入一个开关按钮。这个难点是分析微信代码,并且寻找到的 Hook 代码尽量保证版本兼容(我不希望微信版本更新,就要重新发布或安装插件)。

这里补充下,为啥要 Hook 点尽量保证版本兼容呢?其实说白了就是寻找微信没有混淆的点做入口。为啥呢?因为一旦微信版本升级,肯定会再次混淆。若你 Hook 点是混淆的,那若微信版本升级,若要兼容新版本必定要从新寻找混淆后新的 Hook 点(我们可不得不到微信混淆后的 mapping 文件)。

热修复,兼容多版本微信

在第 3 点我讲过,尽量寻找没有混淆的点做 Hook,但是若死活寻找不到没有混淆的 Hook 点呢?我们只能想办法进行动态修复插件了,让用户无感知使用,我提供的方案是通过 DexClassLoader 去修复 Hook 点代码。
这套技术方案我在曾经在我的项目 微信语音助手 使用过(以停止维护),具体方案看下图。

nagios 微信机器人 ios微信机器人插件_ios_02

找到女朋友

若有女程序员看到这里 

开始敲代码

都准备好啦,接下来我们开始 

对接图灵机器人

这个没啥好说的就是去注册账号,查看提供的API文档

搭建 Xposed 项目

首先在项目 build.gradle 加入依赖。

dependencies {
    ...
    compileOnly 'de.robv.android.xposed:api:82'
    compileOnly 'de.robv.android.xposed:api:82:sources'
    ...
}

注意一定要用 compileOnly 依赖。为啥呢?大家可以自行去看下 Xposed 的原理。我这里就叙述这个问题了,不再本文范畴。

nagios 微信机器人 ios微信机器人插件_移动开发_03

接下来创建上图中所提到的入口类。

class XpCore : IXposedHookLoadPackage {
    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
        MMCoreHook.hook(lpparam)
    }
}

寻找消息 Hook 点

其实寻找 Hook 点就是一个细心的活,我们要在微信的代码海中去寻找合适的 Hook 点,寻找尽量没有混淆的 Hook 点。

如何能快速找到呢?由于文章篇幅问题,请 参考 鄙人文章。

object MsgHook {
    fun hook(actvity: Activity) {
        hookFun(
            {
                if (TextUtils.equals("message", it.args[0].toString())) {
                    try {
                        val contentValues = it.args[2] as ContentValues
                        contentValues.apply {
                            val msgSvrId = getAsString("msgSvrId")
                            if (TextUtils.isEmpty(msgSvrId)) {
                                return@hookFun
                            }
                            val talker = getAsString("talker")
                            val type = getAsString("type")
                            val content = contentValues.getAsString("content")
                            Core.msgGo(talker, type, content, actvity)
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                        Core.toast("消息拦截失败!!")
                    }
                }
            },
            {},
            "com.tencent.wcdb.database.SQLiteDatabase",
            actvity.classLoader,
            "insert",
            String::class.java,
            String::class.java,
            ContentValues::class.java
        )
    }
}

寻找开关Hook点

前面说我们只想守护我们自己的 娇妻 所以需要一个开关,我可不想所有人都自动回复,更不想和一个男的暧昧,更重要的是 图灵机器人 收费啊。

最终通过不断的断点,分析,看源码,找到了一个非常好的 Hook 点。这个流程非常的长,我就不细讲了。具体如何逆向丶断点丶分析代码教程可以 参考 此文章。

部分核心代码,如下:

object ViewHook {
    fun hook(actvity: Activity) {
        log("view Hook开始")
        hookFun({}, {
            val viewGroup = it.thisObject as ViewGroup
            val wxId = it.args[0] as String
            Core.addClickView(viewGroup, wxId)
        }, "com.tencent.mm.pluginsdk.ui.chat.ChatFooter", actvity.classLoader,
            "setUserName",
            String::class.java
        )
    }
}

来看看效果:

nagios 微信机器人 ios微信机器人插件_ios_04

是否打开守护状态的数据,我使用的是 GreenDao 来进行存储的。我挺喜欢这个数据库框架的哦。

回复消息

我们已经通过 Xposed 将我们的代码注入到微信当中了,并且获取到了微信的 ClassLoader。有 ClassLoader 我们当然能通过反射去调用微信的方法啦。

这又是一个很长很长的过程,我就不叙述了,反正就是逆向丶断点丶分析。

我的 张美丽丶李花丶杨柳絮又离我而去了。

在分析过程中我一直想寻找没有混淆的发消息 Hook 点,我找了很久,也想尽了所有的办法,包括构造上面的开关按钮 Hook 点 ChatFooter 对象,通过调用 View 的方法。

我这里就跑题下,我当时想寻找到一个合适的微信发消息的 Hook 点(没有混淆的点),顺便给大家分享下我当时巧夺天工的想法 

我们前面分析到了 ChatFooter 对象,他是一个 FrameLayout,提示这个布局就是我们聊天的布局,如下图:

nagios 微信机器人 ios微信机器人插件_移动开发_05

思路很简单,我通过遍历 View 寻找到消息输入框,然后调用 setText 设置文本,然后在寻找 发送 按钮,在调用其 performClick 方法。

然后查看微信 ChatFooter 源码,在其构造方法中看到了。

nagios 微信机器人 ios微信机器人插件_移动开发_06

接下来寻找发送消息按钮,我是通过搜索 setOnClickListener 方法,搜索到的。

nagios 微信机器人 ios微信机器人插件_编程语言_07

接下来只需要递归遍历,寻找到消息输入框的 View 对象。

/**
   * 递归遍历寻找 微信输入框 EditText 对象
   */
  private fun findMsgEditText(view: View): EditText? {
      if (view is EditText) {
          return view
      } else {
          if (view is ViewGroup) {
              for (index in 0 until view.childCount) {
                  val editText = findMsgEditText(view.getChildAt(index))
                  if (editText != null) {
                      return editText
                  }
              }
          }
      }
      return null
  }

在开发过程中我发现个优化点,现在我们是通过递归查找到了,输入框 EditText 对象,本来还需要通过递归查找发送按钮的 View 对象,这样效率有点低,但是突然我想到了输入框,按回车也能发消息,因此从新去看了下微信代码,如下图:

nagios 微信机器人 ios微信机器人插件_ios_08

啊哈哈,更能确定我的 View 对象是对的,然后就是通过反射获取到了 EditText 对象的 OnEditorActionListener 对象,然后调用了 onEditorAction 方法(由于无效,代码删除了,找不到了),这样如果能成功,我们的 护妻宝 就能兼容所有微信版本啦,也不用做什么热修复啦,好开心测试下。

既然无效,不应该啊。接下里我断点看了下,发送按钮的点击事件方法。

nagios 微信机器人 ios微信机器人插件_ios_09

一直到我看到 ChatFooter 的这个方法。

nagios 微信机器人 ios微信机器人插件_移动开发_10

死的心都有了,这个 xTi 对象又被混淆了,还是不行啊!回头我又想了想,腾讯微信这种大厂怎么可能将 View 层和逻辑层代码写在一起呢?

最终这种方案我还是放弃了,花费了这么长的篇幅讲这个,只是给大家提供一个思路,有时候我们可以通过这种手段去 Hook ,虽然微信不适用不代表,其他应用不适用,我曾经分析过 FacebookMessenge聊天工具就用的这种方案。

最终我还是没找到,没混淆的发消息方法。

/**
 * hook 发消息方法
 */
private fun receiverMsg(activity: Activity, msg: String, talker: String) {
    val azClzz = XposedHelpers.findClass("com.tencent.mm.model.az", activity.classLoader)
    val obj = XposedHelpers.callStaticMethod(azClzz, "ZS")
    val msgClzz = XposedHelpers.findClass("com.tencent.mm.modelmulti.h", activity.classLoader)
    XposedHelpers.callMethod(obj, "b", XposedHelpers.newInstance(msgClzz, talker, msg, 1))
}

若有有能人,能找到没有混淆的发消息的 Hook(尽量兼容所有版本的),并且愿意无私提供给我,请留言哦。

热修复

其实我们大部分工作完成了,但是热修复还需要很多注意点。由于篇幅问题(代码还没写,哈哈)。

但是我们方案有了,其实大家也应该看我代码注意到,我在构建代码的时候,已经将核心的注入方法都抽取在了 Core 类,为了就是将来热修复方便。

总结

首先由于 图灵机器人 开发者账号,没审核下来(审核2天了)。我暂时没有集成,只是到收到 娇妻 信息后,自动回复 你好可爱哦

当前效果

nagios 微信机器人 ios微信机器人插件_编程语言_11

补充

由于作者分析的微信版本是 7.0.7,等软件完成后在兼容最新版本微信,若想测试,可以安装微信 7.0.7 版本测试哦。

我是用我公司的 360分身大师X版 做的免 Root 使用 Xposed(微信版本是7.0.7哦)。

代码仓库:https://github.com/makeloveandroid/ProtectLove

--END--