百趣云 百趣云的博客

闲鱼消息协议分析:mtop 长连接与消息收发

闲鱼 IM 的技术栈

闲鱼的消息系统建立在阿里 mtop 体系之上:信令走 mtop HTTP 接口,消息收发走长连接(阿里自研的 ACCS 通道)。这种"HTTP 信令 + 长连接消息"的双通道设计是阿里系 IM 的标准架构(淘宝、1688 同构)。

逆向闲鱼 IM 要先分清两条通道的职责:

  • mtop 接口:会话列表、历史消息拉取、发送消息的 HTTP 兜底
  • ACCS 长连接:实时消息推送、在线状态、消息即时下发

mtop 侧:会话与历史消息

闲鱼消息相关的 mtop 接口(以抓包为准,接口名随版本变):

mtop.taobao.idlemessage.*    ← 消息相关接口族

调用需要完整的 mtop 签名体系(x-sign + x-mini-wua,前文"闲鱼 x-sign"篇已详述)。会话列表、未读数、历史消息都能通过 mtop 接口拿到——只读场景不需要碰长连接

ACCS 长连接:实时消息的通道

ACCS(Ali Channel Connection Service)是阿里的统一推送通道。闲鱼 App 启动后建立 ACCS 长连接,消息实时推下来。

协议特征:

  • TCP 长连接,自定义二进制协议(阿里 ACCS 协议)
  • 连接建立后有鉴权(用 mtop 的登录态换 ACCS 的 token)
  • 心跳保活(分钟级)
  • 消息是压缩+加密的二进制帧

分析姿势:从 Frida 入手而非网络层

ACCS 协议是加密二进制,从网络层逆(tcpdump)性价比极低。正确姿势是 hook App 内部的消息处理层

// 思路:hook 消息接收的回调类,拿解密后的消息对象
// 类名以实际逆向为准(搜 "message" / "receive" 相关类)
Java.perform(function() {
    var MessageHandler = Java.use('com.taobao.accs.xxx.MessageHandler');
    MessageHandler.onMessage.implementation = function(msg) {
        console.log('[ACCS] 收到消息: ' + msg.toString());
        // 消息对象的字段逐个反射打印
        this.onMessage(msg);
    };
});

更上游的 hook 点:消息到达 UI 层之前必经"反序列化"环节,hook 反序列化函数能拿到结构化的消息对象。

发消息:mtop 接口兜底

发消息不一定要走长连接——闲鱼的发消息有 mtop HTTP 接口兜底(弱网场景 App 自己也这么干):

def send_message(session, sign_service, peer_id, content):
    data = {
        "peerId": peer_id,
        "content": json.dumps({"type": "text", "text": content}),
        # ... 其他业务字段
    }
    # 走 mtop 签名流程(x-sign 体系)
    return mtop_request(session, sign_service, 'mtop.taobao.idlemessage.send', data)

工程上"发消息走 mtop HTTP、收消息轮询 mtop 历史接口"可以完全绕开 ACCS 长连接——牺牲一点实时性(轮询间隔 5-10 秒),换来协议复杂度的大幅下降。这是 IM 协议模拟的通用取舍。

精髓:IM 协议模拟的通用决策

  1. 先评估"只读+HTTP 发送"能否满足需求。能,就别碰长连接——90% 的业务场景(客服机器人、消息监控)这样就够了
  2. 必须长连接时,hook 应用层而非逆网络协议。加密二进制协议的网络层逆向是月级工程,hook 消息回调是天级工程
  3. 长连接模拟的成本是持续的。ACCS 这类协议会随版本升级变化,维护成本高。除非实时性是硬需求(抢单、秒杀通知),否则轮询是更可持续的方案

总结

  1. 闲鱼 IM = mtop 信令 + ACCS 长连接双通道
  2. 只读场景 mtop 接口全覆盖,不用碰长连接
  3. 长连接分析走 Frida hook 消息回调,别逆加密二进制
  4. 发消息有 HTTP 兜底,轮询换 simplicity 是明智取舍

交流微信:run1255

By 百趣云 阅读量:2 On