美文网首页
Xposed第五课(微信篇) 聊天机器人

Xposed第五课(微信篇) 聊天机器人

作者: KingZd | 来源:发表于2018-06-12 23:53 被阅读0次

    经过了前段日子基于微信的学习,今天终于折腾除了一点干货,微信聊天机器人。先上个图

    一对一聊天 群聊
    device-2018-06-12-220825.gif device-2018-06-12-221655.png

    为了完成这个,人都蒙蔽了,不多说了开始分析把。

    首先进行如下图的操作

    DDMS 轨迹
    QQ截图20180612223149.png QQ截图20180612223157.png

    左图选中要记录的进程点击左图右上角那个图标进行轨迹录制之后,再次点击这个停止录制,就有了右边的图,我是从点击微信发送按钮开始录制的,所以在有图下面输入过滤关键字 onClick

    public final boolean FZ(String str) {
            mS(false);
            ctQ();
            return this.yOg.yRO.dt(str, 0);
        }
    

    从这个开始入手进入 dt(String str, int i)

    public final boolean dt(String str, int i) {
            ...此处省略...
            this.ejx.cuJ().post(new y$1(this, Xf, i));
            this.ejx.mZ(true);
            return true;
        }
    

    接下来是关键点了,后面关联的地方有多处,我一一列出来
    首先是 y$1

    package com.tencent.mm.ui.chatting.b;
    
    import android.database.Cursor;
    import com.tencent.mm.ac.l;
    import com.tencent.mm.ai.a;
    import com.tencent.mm.compatible.e.n;
    import com.tencent.mm.modelmulti.i;
    import com.tencent.mm.plugin.appbrand.jsapi.audio.d;
    import com.tencent.mm.plugin.bbom.h;
    import com.tencent.mm.plugin.report.service.g;
    import com.tencent.mm.pluginsdk.ui.chat.ChatFooter;
    import com.tencent.mm.sdk.platformtools.an;
    import com.tencent.mm.sdk.platformtools.bh;
    import com.tencent.mm.sdk.platformtools.w;
    import com.tencent.mm.storage.aw;
    import com.tencent.mm.storage.ax;
    import com.tencent.mm.storage.bj;
    import com.tencent.mm.storage.x;
    import com.tencent.mm.z.au;
    import com.tencent.mm.z.br;
    import com.tencent.mm.z.q;
    import com.tencent.mm.z.s;
    import java.util.LinkedList;
    
    class y$1 implements Runnable {
        final /* synthetic */ String fNk;
        final /* synthetic */ int ra;
        final /* synthetic */ y yXJ;
    
        y$1(y yVar, String str, int i) {
            this.yXJ = yVar;
            this.fNk = str;
            this.ra = i;
        }
    
        public final void run() {
            g.vX(20);
            int i = (this.yXJ.ejx.cuz().field_username.equals("medianote") && (q.GG() & 16384) == 0) ? 1 : 0;
            if (i != 0) {
                this.yXJ.ejx.cuM();
                au.Dv().a(new a(this.yXJ.ejx.cuz().field_username, this.fNk), 0);
                return;
            }
            String cuB;
            if (this.yXJ.ejx.cuP().getCount() == 0 && x.XM(this.yXJ.ejx.ctS())) {
                br.ID().c(10076, new Object[]{Integer.valueOf(1)});
            }
            String ctS = this.yXJ.ejx.ctS();
            int hC = s.hC(ctS);
            String str = this.fNk;
            q qVar = this.yXJ.yRE;
            if (qVar.ejx.cuC()) {
                w.i("MicroMsg.ChattingUI.LbsImp", "[oneliang]encrypt:" + qVar.ejx.wG() + ",raw:" + qVar.ejx.cuB());
                cuB = bh.oB(qVar.ejx.wG()) ? qVar.ejx.cuB() : qVar.ejx.wG();
            } else {
                cuB = ctS;
            }
            if (bh.oB(cuB)) {
                w.w("MicroMsg.ChattingUI.TextImp", "tempUser is null");
                return;
            }
            ChatFooter cuS = this.yXJ.ejx.cuS();
            int i2 = this.ra;
            int i3 = cuS.vST.vTU.containsKey(ctS) ? ((LinkedList) cuS.vST.vTU.get(ctS)).size() > 0 ? d.CTRL_INDEX : i2 : i2;
            l iVar = new i(cuB, str, hC, i3, this.yXJ.ejx.cuS().fu(ctS, str));
            q qVar2 = this.yXJ.yRE;
            if (qVar2.ejx.cuC()) {
                aw awVar;
                cuB = qVar2.klH;
                ax SB = com.tencent.mm.bb.d.SB();
                String wG = qVar2.ejx.wG();
                Cursor b = SB.fOK.b("SELECT * FROM " + SB.getTableName() + " where sayhiencryptuser=? and isSend=0 and flag=0" + " ORDER BY createtime desc LIMIT 1", new String[]{wG}, 2);
                if (b == null) {
                    awVar = null;
                } else if (b.moveToFirst()) {
                    awVar = new aw();
                    awVar.c(b);
                    b.close();
                } else {
                    b.close();
                    awVar = null;
                }
                if (!(awVar == null || bh.oB(awVar.field_ticket))) {
                    cuB = awVar.field_ticket;
                }
                if (bh.oB(cuB)) {
                    awVar = com.tencent.mm.bb.d.SB().YM(qVar2.ejx.wG());
                    if (!(awVar == null || bh.oB(awVar.field_ticket))) {
                        cuB = awVar.field_ticket;
                    }
                }
                if (cuB != null) {
                    iVar.gJj = new h(cuB);
                }
            }
            au.Dv().a(iVar, 0);
            if (s.hy(ctS)) {
                au.Dv().a(new com.tencent.mm.plugin.setting.model.i(com.tencent.mm.compatible.e.q.zI(), this.fNk + " key " + bj.cnt() + " local key " + bj.cns() + "NetType:" + an.getNetTypeString(this.yXJ.ejx.cuH().getContext().getApplicationContext()) + " hasNeon: " + n.zj() + " isArmv6: " + n.zl() + " isArmv7: " + n.zk()), 0);
            }
        }
    }
    

    这个类就是 消息处理的过程 调用关键方法
    au.Dv().a(l lVar, int i)

    我在分析到这个地方被卡了很久

    这个au.Dv().a(l lVar, int i) 有三种形式

    以下面的方式调用可以实现自动回复,自能自己看到,对方看不到消息

    au.Dv().a(new a(this.yXJ.ejx.cuz().field_username, this.fNk), 0);
    

    以下面的方式调用可以实现自动回复,自能自己看到,对方也能看到消息

           l iVar = new i(cuB, str, hC, i3, this.yXJ.ejx.cuS().fu(ctS, str));
           
    au.Dv().a(iVar, 0);
    

    以下面的方式暂未试验,有兴趣的小伙伴可以自己尝试调用,如果方便的话可以以反馈给我

                au.Dv().a(new com.tencent.mm.plugin.setting.model.i(com.tencent.mm.compatible.e.q.zI(), this.fNk + " key " + bj.cnt() + " local key " + bj.cns() + "NetType:" + an.getNetTypeString(this.yXJ.ejx.cuH().getContext().getApplicationContext()) + " hasNeon: " + n.zj() + " isArmv6: " + n.zl() + " isArmv7: " + n.zk()), 0);
    
    

    接下来就是给上面的方法拼接参数,等会给的代码里面会提到。这里就不多重复了

    到此我们能够回复了,那么我们回复的时机是什么呢?
    于是我们需要找到什么时候收到消息,然后进行调用上面的代码

    重复DDMS的操作进行接收消息通知的筛选 如下图

    QQ截图20180612232854.png

    看到筛选后关键类com.tencent.mm.booter.notification.b$1

    package com.tencent.mm.booter.notification;
    
    import android.os.Looper;
    import android.os.Message;
    import com.tencent.mm.sdk.platformtools.ac;
    import com.tencent.mm.sdk.platformtools.af;
    import com.tencent.mm.sdk.platformtools.w;
    
    class b$1 extends af {
        final /* synthetic */ b fEw;
    
        b$1(b bVar, Looper looper) {
            this.fEw = bVar;
            super(looper);
        }
    
        public final void handleMessage(Message message) {
            super.handleMessage(message);
            ac.getContext().getSharedPreferences("notify_prep", 0).edit().putBoolean("longNoopIntervalFlag", true).apply();
            String string = message.getData().getString("notification.show.talker");
            String string2 = message.getData().getString("notification.show.message.content");
            int i = message.getData().getInt("notification.show.message.type");
            int i2 = message.getData().getInt("notification.show.tipsflag");
            w.i("MicroMsg.MMNotification", "notify need to deal: %s", new Object[]{string});
            try {
                if (message.what == 1) {
                    b.a(this.fEw, string, string2, i, i2, true);
                } else {
                    b.a(this.fEw, string, string2, i, i2, false);
                }
            } catch (Throwable e) {
                w.printErrStackTrace("MicroMsg.MMNotification", e, "showNotifiHandler", new Object[0]);
            }
        }
    }
    
    

    看着这关键字貌似挺匹配的,于是进行hook发现确实接收的时候会执行这里

    结合上面的得到如下代码

    @Override
        public void autoRepeat() {
    
            final Class<?> afClass = XposedHelpers.findClass("com.tencent.mm.sdk.platformtools.af", mClassLoader);
    //        //获取收到消息的标记通知栏
            Class<?> b$1Class = XposedHelpers.findClass("com.tencent.mm.booter.notification.b$1", mClassLoader);
            XposedHelpers.findAndHookMethod(b$1Class, "handleMessage", Message.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    Message message = (Message) param.args[0];
                    final String string = message.getData().getString("notification.show.talker");
                    String string2 = message.getData().getString("notification.show.message.content");
                    int i = message.getData().getInt("notification.show.message.type");
                    int i2 = message.getData().getInt("notification.show.tipsflag");
                    LogUtils.i(string, string2, i, i2, afClass);
                    Class<?> gClass = XposedHelpers.findClass("com.tencent.mm.kernel.g", mClassLoader);
                    Object g = XposedHelpers.callStaticMethod(gClass, "Ea");
                    Object filedA = XposedHelpers.getObjectField(g, "fVR");
    
                    Class<?> oClass = XposedHelpers.findClass("com.tencent.mm.ac.o", mClassLoader);
                    Class<?> lClass = XposedHelpers.findClass("com.tencent.mm.ac.l", mClassLoader);
                    Method methodA = XposedHelpers.findMethodExact(oClass, "a", lClass, int.class);
                    Object o = XposedHelpers.callStaticMethod(oClass, "a", filedA);
    
                    //这里只能自己看到回复消息 对方看不到
    //                Class<?> aClass = XposedHelpers.findClass("com.tencent.mm.ai.a", mClassLoader);
    //                Object a = XposedHelpers.newInstance(aClass, new Class[]{String.class, String.class}, string, "haha");
    //                Object[] p = new Object[]{a, 0};
    
                    //调用这里可以实现自动回复 并发送到对方
                    Class<?> iClass = XposedHelpers.findClass("com.tencent.mm.modelmulti.i", mClassLoader);
                    Object io = XposedHelpers.newInstance(iClass, new Class[]{String.class, String.class, int.class, int.class, Object.class}, string, "haha", 1, 1, new HashMap<String, String>() {{
                        put(string, string);
                    }});
                    Object[] pp = new Object[]{io, 0};
    //                LogUtils.i(gClass, g, filedA, oClass, lClass, methodA, o, aClass, a, p, iClass, io, pp);
                    LogUtils.i(gClass, g, filedA, oClass, lClass, methodA, o, iClass, io, pp);
                    try {
    //                    XposedBridge.invokeOriginalMethod(methodA, o, p);
    
                        XposedBridge.invokeOriginalMethod(methodA, o, pp);
                    } catch (Exception e) {
                        e.printStackTrace();
                        LogUtils.e(e.getLocalizedMessage());
                    }
                    LogUtils.i("send ok");
                }
            });
    
        }
    

    令我感到头痛的是在进行匹配参数,因为有些关联的引用不是很明显,找的时候有很多误区。
    根据以上内容今后可以扩展聊天机器人,群助手,以及方便学习微信抢红包的流程。哈哈

    以上为本课内容,我所有的内容都是以学习为主,请各位小伙伴勿要用来违法,造成的一切违法后果与本人无任何关系

    垃圾代码已上传

    相关文章

      网友评论

          本文标题:Xposed第五课(微信篇) 聊天机器人

          本文链接:https://www.haomeiwen.com/subject/xwxdeftx.html