编写微信聊天机器人4《聊天精灵WeChatGenius》:实时获取到微信聊天消息,hook数据库插入操作。

版权声明:允许转载,请注明来源。 https://blog.csdn.net/weixin_42127613/article/details/81840536

接上篇,使用Xposed来hook微信,找到微信进程:https://blog.csdn.net/weixin_42127613/article/details/81839537

既然已经找到了微信进程,那么就可以对微信的数据进行拦截获取了。

hook到微信的聊天消息,比较简单,只需要hook住数据库的插入方法即可。

因为一旦来了新消息,微信就会往本地数据库插入聊天消息,将聊天消息保存到本地。所以我们只要hook住消息的插入动作,就能实时的获取到聊天消息。

微信的数据库操作有很多类和实例,但最终都是调用了com.tencent.wcdb.database.SQLiteDatabase这个类。

插入方法用的是insert,insert内部又调用了insertWithOnConflict方法。我们可以hook住insert方法,也可以hook住insertWithOnConflict方法。

我们采用hook最终方法吧。hook这个insertWithOnConflict方法。

反编译微信,去查看com.tencent.wcdb.database.SQLiteDatabase这个类的insertWithOnConflict方法,看看都有什么参数,才能编写hook代码。如下图所示,有4个参数。

现在编写hook代码。在MainXposed中新建一个方法hookDatabaseInsert,进行hook。

//hook数据库插入操作
    private void hookDatabaseInsert(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
        Class<?> classDb = XposedHelpers.findClassIfExists(WECHAT_DATABASE_PACKAGE_NAME, loadPackageParam.classLoader);
        if (classDb == null) {
            XposedBridge.log("hook数据库insert操作:未找到类" + WECHAT_DATABASE_PACKAGE_NAME);
            return;
        }
        XposedHelpers.findAndHookMethod(classDb,
                "insertWithOnConflict",
                String.class, String.class, ContentValues.class, int.class,
                new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        XposedBridge.log("HOOK住微信数据库插入操作。");
                    }
                });
    }

在主函数handleLoadPackage方法中加入调用,如下代码。

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (!lpparam.processName.equals(WECHAT_PROCESS_NAME)) {
            return;
        }
        XposedBridge.log("进入微信进程:" + lpparam.processName);
        //调用 hook数据库插入。
        hookDatabaseInsert(lpparam);
    }

现在开始执行,测试,查看日志。如下图所示,发现了很多数据库操作。

为了能清晰的查看消息。我们过滤掉非聊天消息的插入动作,同时将聊天消息的内容解析出来。

微信的新聊天消息,会插入2个表:message和rconversation。

  • message表:消息内容总表。所有的聊天消息,都会存入到这个表。
  • rconversation表:当前的会话表。就是进入微信,在主界面看到的列表。这个表保存的是最后一条聊天记录,每次有新消息,都会更新这个表。

我们hook这2个表中的任意一个都可以,但是rconversation表不仅有insert,还有update操作,所以我们还是只取message表即可。

为了能输出数据库的插入数据,我们特意定义一个函数printInsertLog,用于输出数据库插入日志。

    //输出插入操作日志
    private void printInsertLog(String tableName, String nullColumnHack, ContentValues contentValues, int conflictValue) {
        String[] arrayConflicValues =
                {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
        if (conflictValue < 0 || conflictValue > 5) {
            return;
        }
        XposedBridge.log("Hook数据库insert。table:" + tableName
                + ";nullColumnHack:" + nullColumnHack
                + ";CONFLICT_VALUES:" + arrayConflicValues[conflictValue]
                + ";contentValues:" + contentValues);
    }

改进代码,去掉之前的日志输出,过滤掉非聊天消息表,输出消息日志。现在hookDatabaseInsert的代码为:

 //hook数据库插入操作
    private void hookDatabaseInsert(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
        Class<?> classDb = XposedHelpers.findClassIfExists(WECHAT_DATABASE_PACKAGE_NAME, loadPackageParam.classLoader);
        if (classDb == null) {
            XposedBridge.log("hook数据库insert操作:未找到类" + WECHAT_DATABASE_PACKAGE_NAME);
            return;
        }
        XposedHelpers.findAndHookMethod(classDb,
                "insertWithOnConflict",
                String.class, String.class, ContentValues.class, int.class,
                new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        String tableName = (String) param.args[0];
                        ContentValues contentValues = (ContentValues) param.args[2];
                        if (tableName == null || tableName.length() == 0 || contentValues == null) {
                            return;
                        }
                        //过滤掉非聊天消息
                        if (!tableName.equals("message")){
                            return;
                        }
                        //打印出日志
                        printInsertLog(tableName, (String) param.args[1], contentValues, (Integer) param.args[3]);
                    }
                });
    }

编译、运行、重启,查看日志。没有日志输出,那么给当前的微信号,发送一条消息试试看。如下图所示,已经成功的获取到了聊天消息。

查看日志详情,可以看到插入的contentValues数据内容。

Hook数据库insert。table:message;nullColumnHack:msgId;CONFLICT_VALUES:;contentValues:bizClientMsgId= msgId=2622 msgSvrId=6403889649528004581 talker=wxid_e77yg22 content=在不在 flag=0 status=3 msgSeq=680182320 createTime=1534678573000 lvbuffer=[B@4428279 isSend=0 type=1 bizChatId=-1 talkerId=378

我们想要什么数据,只需要从contentValues的相应字段中取即可。

好了,现在我们已经成功的hook到微信的实时聊天消息,想怎么处理,就看你了。

代码已提交:https://github.com/dalu2048/WeChatGenius.git

接下来,下篇文章,测试文本消息自动回复功能:https://blog.csdn.net/weixin_42127613/article/details/81841099

猜你喜欢

转载自blog.csdn.net/weixin_42127613/article/details/81840536
今日推荐