飘易博客(作者:Flymorn)
订阅《飘易博客》RSS,第一时间查看最新文章!
飘易首页 | 留言本 | 关于我 | 订阅Feed

抖音创作者平台获取私信protobuf的方法探讨

Author:飘易 Source:飘易
Categories:网络技术 PostTime:2026/1/20 18:49:52
正 文:

抖音开放平台目前已逐渐转向封闭,不再“开放”了。2025年4月14日抖音开放平台通知:

”将于2025年4月14日起停止私信群聊能力权限申请和开放。对历史已开通私信能力的外部移动/网站应用,平台将分批回收以下私信能力权限(历史开通过的将无法继续使用):近90天无调用的,平台将于公告发布之日起,直接回收私信能力权限;近90天有调用的,平台将于2025年5月19日起,分批回收私信能力权限。“


然后,5月15日继续通知:“从2025年5月19日起,平台将对有调用的应用能力权限进行分批回收,于2025年5月30日回收完毕。检测到你所属的移动/网站应用有私信能力的调用(有授权/有Webhook调用/有OpenAPI调用),为避免应用报错,请充分自查,并及时完成调整和改造。”


此时,我们手里的私信并没有真正回收。直到2025年11月26日的通知:

“为维护平台良好生态,避免隐私安全风险,平台自2025年4月14日起,对移动应用、网站应用的私信群聊能力权限做调整,详情请参考:移动/网站应用的私信群聊能力下线/回收公告。此前,你所属的移动/网站应用通过内部业务方申请了服务私信能力延期回收 。现因业务调整,重新启动回收:平台将于2025年12月26日回收服务私信能力权限。为避免应用影响,请充分自查并及时完成调整改造。”


至此,私信能力真正回收掉了。不再能收发私信。


那目前,普通客户可以拿到私信的只有2种方式:1、手机里的抖音app里;2、网页端的抖音创作者平台。


手机端要拿到私信,如果是协议式的,手机需要root的。不是协议式的,可以利用无障碍开发者方式获取,也是需要大量适配工作的,每升级一个版本都要重新适配。


本文只探讨网页端的抖音创作者平台里如何获取私信。


打开:https://creator.douyin.com/creator-micro/data/following/chat 

可以看到抖音进行了特殊的处理,POST 

https://imapi.snssdk.com/v2/message/get_by_user_init ,并且使用了 

content-type :application/x-protobuf 的协议,protobuf是Google开发的新型网络协议,压缩率非常高,想破解这个,需要 .proto文件,如果没有这个.proto文件,工作量就会非常巨大。


常用的逆向破解方法

即使没有原始的 .proto 文件,开发者通常会通过以下手段进行破解:

1、静态分析(反汇编): 如果是安卓 App 或 PC 软件,可以通过反编译代码(如使用 jadx 逆向 Java,或使用 IDA Pro 逆向 C++)。Protobuf 的解析代码通常会包含字段编号与变量名的映射关系,逆向者可以据此手动还原出 .proto 文件。

2、动态抓包与猜测: 使用工具(如 Charles 或 Fiddler)配合插件,可以将二进制流自动解析为结构化数据。通过观察数据的变化(例如:修改用户名后,哪个字段变了),可以推断出每个编号代表的含义。

3、自动化工具(protoc --decode): Google 官方工具支持在不知道结构的情况下,强制以“原始 Wire Format”打印数据。


我们这里不去破解,使用巧劲。因为我们的目的只是拿到解密后的明文,完全不需要走这么复杂的方案。


通过跟踪js调用堆栈,我们找到加解密的函数:

sendRequest(e, t) {
    return (0,
    n.__awaiter)(this, void 0, void 0, (function*() {
        const r = yield this.send(e, "POST", this.encode(t));
        return this.decode(r)
    }
    ))
}
encode(e) {
    return (0,
    s.serialize)(e).buffer
}
decode(e) {
    return o.im_proto.Response.create((0,
    s.deserialize)(this.ctx, e))
}

我们只需要在 decode 函数里,把解码后的明文数据打印出来即可。


这里可以采用浏览器打断点的方式,输出调试信息,也可以打入 logprint,输出日志。还可以使用 Chrome 本地覆盖(Local Overrides)的方式覆盖js,具体的方法就不展开细述了。


经过调试,可以看出发出请求时,包的结构为:

{
    "t": {
        "headers": {
            "aid_new": 2906,
            "app_name": "douyin_creator"
        },
        "body": {
            "messages_per_user_init_v2_body": {
                "cursor": {
                    "low": 0,
                    "high": 0,
                    "unsigned": false
                }
            }
        },
        "cmd": 203,
        "sequence_id": {
            "low": 10001,
            "high": 0,
            "unsigned": false
        },
        "refer": 3,
        "token": "YSHGAwEBBwECBIEaKUQBZwFVqNYCl1B...",
        "device_id": 0,
        "sdk_version": "0.7.2-fix.1",
        "build_number": "2f4951d:fix/douyin-creator-fix",
        "inbox_type": 1,
        "device_platform": "douyin_creator",
        "auth_type": 3,
        "biz": "douyin_creator",
        "access": "web_sdk",
        "sdk_cert": "LS0tLS1CRUdJTiBDRVJU...",
        "ts_sign": "#KVBSUXpXvAQF1rk+r6db..."
    },
    "e": "https://imapi.snssdk.com/v2/message/get_by_user_init"
}

接收到的明文数据如下:

{
     "headers": {},
     "cmd": 203,
     "sequence_id": {
          "low": 10002,
          "high": 0,
          "unsigned": false
     },
     "status_code": 0,
     "error_desc": "OK",
     "inbox_type": 1,
     "body": {
          "messages_per_user_init_v2_body": {
               "messages": [
                    {
                         "ext": {
                              "awe:from:commerce": "1",
                              "s:visible": "111",
                              "chat_scene": "normal",
                              "s:refer": "4",
                              "s:high_priority_message": "commerce",
                              "s:saas_sdk": "false",
                              "a:msg_not_float": "receive",
                              "echat_forward_msg_info": "{\"ai\":337122,\"mi\":111,\"csi\":111,\"ci\":\"111\",\"ct\":2}",
                              "s:biz_aid": "1128",
                              "a:is_server": "true",
                              "a:access": "server",
                              "s:s_aid": "1128",
                              "a:msg_scene": "2",
                              "s:client_message_id": "7d2e8ce3-111",
                              "s:vcd_shark_detail": "",
                              "a:plv": "n",
                              "a:relation_type": "0:1",
                              "s:server_message_create_time": "1762163906284",
                              "source_aid": "1128",
                              "s:mode": "0",
                              "im_callback_status_code": "0",
                              "a:s_awe_push_close": "1",
                              "s:is_stranger": "false",
                              "s:sync_2_newdx": "1",
                              "s:vcd_shark_decision": "PASS",
                              "s:do_not_increase_unread": "true",
                              "a:biz": "aweme_im_service_script"
                         },
                         "property_list": {},
                         "conversation_id": "0:1:111:222",
                         "conversation_type": 1,
                         "server_message_id": {
                              "low": 873219633,
                              "high": 1,
                              "unsigned": false
                         },
                         "index_in_conversation": {
                              "low": -814695360,
                              "high": 1,
                              "unsigned": false
                         },
                         "conversation_short_id": {
                              "low": -2138947009,
                              "high": 1,
                              "unsigned": false
                         },
                         "message_type": 1,
                         "sender": {
                              "low": 419171323,
                              "high": 1,
                              "unsigned": false
                         },
                         "content": "{\"tips\":\"对方转移了账号主体,为保护你的隐私,已向对方隐藏了历史消息,你授权后对方才可查看 {{1}}\",\"aweType\":195}",
                         "create_time": {
                              "low": 1227314609,
                              "high": 1,
                              "unsigned": false
                         },
                         "version": {
                              "low": 1227315343,
                              "high": 1,
                              "unsigned": false
                         },
                         "status": 0,
                         "order_in_conversation": {
                              "low": 1348426240,
                              "high": 1,
                              "unsigned": false
                         },
                         "sec_sender": "MS4wLjABAAAARv3VI03dODthsvOt30"
                    }
               ],
               "conversations": [
                    {
                         "conversation_id": "0:1:111:222",
                         "conversation_short_id": {
                              "low": -2138947009,
                              "high": 1,
                              "unsigned": false
                         },
                         "conversation_type": 1,
                         "ticket": "111",
                         "first_page_participants": {
                              "participants": [
                                   {
                                        "user_id": {
                                             "low": 1330098236,
                                             "high": 1,
                                             "unsigned": false
                                        },
                                        "sec_uid": "MS4wLjABAAAA4HNV1M9GCjyV3Vc5"
                                   },
                                   {
                                        "user_id": {
                                             "low": 419171323,
                                             "high": 1,
                                             "unsigned": false
                                        },
                                        "sec_uid": "MS4wLjABAAAARv3VI03dODthsvOt30"
                                   }
                              ]
                         },
                         "participants_count": 2,
                         "is_participant": true,
                         "conversation_core_info": {
                              "ext": {
                                   "a:ds_b_scene": "1",
                                   "s:s_aid": "1128",
                                   "s:high_priority_conversation": "commerce",
                                   "awe:commerce": "1"
                              },
                              "conversation_id": "0:1:111:222",
                              "conversation_short_id": {
                                   "low": -2138947009,
                                   "high": 1,
                                   "unsigned": false
                              },
                              "conversation_type": 1,
                              "info_version": {
                                   "low": 1762163906,
                                   "high": 1,
                                   "unsigned": false
                              },
                              "name": "",
                              "desc": "",
                              "icon": "",
                              "inbox_type": 0,
                              "notice": "",
                              "owner": {
                                   "low": 1330098236,
                                   "high": 1,
                                   "unsigned": false
                              },
                              "sec_owner": "MS4wLjABAAAA4HNV1M9GCjyV3Vc5KqNB4GhUBuCQA8YQ-YZdjKu5iwo"
                         },
                         "conversation_setting_info": {
                              "ext": {
                                   "a:btm_tracking": ""
                              },
                              "conversation_id": "0:1:111:222",
                              "conversation_short_id": {
                                   "low": -2138947009,
                                   "high": 1,
                                   "unsigned": false
                              },
                              "conversation_type": 1,
                              "min_index": {
                                   "low": 0,
                                   "high": 0,
                                   "unsigned": false
                              },
                              "read_index": {
                                   "low": -814705360,
                                   "high": 1,
                                   "unsigned": false
                              },
                              "mute": 0,
                              "stick_on_top": 0,
                              "inbox_type": 0,
                              "setting_version": {
                                   "low": 1695617385,
                                   "high": 0,
                                   "unsigned": false
                              },
                              "favorite": 0,
                              "set_top_time": {
                                   "low": 0,
                                   "high": 0,
                                   "unsigned": false
                              },
                              "set_favorite_time": {
                                   "low": 0,
                                   "high": 0,
                                   "unsigned": false
                              }
                         }
                    }
               ],
               "per_user_cursor": {
                    "low": -649801037,
                    "high": 1,
                    "unsigned": false
               },
               "next_cursor": {
                    "low": 20,
                    "high": 0,
                    "unsigned": false
               },
               "has_more": true
          }
     },
     "log_id": "20260000",
     "request_arrived_time": {
          "low": -618177778,
          "high": 1,
          "unsigned": false
     },
     "server_execution_end_time": {
          "low": -618175822,
          "high": 1,
          "unsigned": false
     }
}


我们只需要解析 body -> messages_per_user_init_v2_body -> messages 就可以获取私信的明文数据了。

注意,这里还没有用户的昵称和头像信息,我们需要通过加密的用户id(sec_sender) 去匹配另一个请求。


昵称+头像请求:

https://creator.douyin.com/aweme/v1/creator/im/user_detail/

这个请求里有具体的昵称、头像:

{
    "extra": {
        "now": 1768383888000
    },
    "status_code": 0,
    "status_msg": "",
    "user_list": [
        {
            "user": {
                "SecretUseId": "MS4wLjABAAAAH3pc3DValg",
                "ShareQrcodeUri": "",
                "ShortId": "111",
                "avatar_thumb": {
                    "uri": "aweme-avatar/tos-cn-i-0813_8de015",
                    "url_list": [
                        "https://p3.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_8de015.jpeg?from=2956013662",
                        "https://p11.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_8de015.jpeg?from=2956013662",
                        "https://p26.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_8de015.jpeg?from=2956013662"
                    ]
                },
                "nickname": "飘易",
                "signature": "一个青年。飘易。"
            },
            "user_id": "MS4wLjABAAAAH3pc3DValg"
        },
        
    ]
}

然后,通过加密的用户id 来匹配私信的发送者。


上面只是调试的信息,如果我们需要自动化部署,可以开发一套软件自动去捕获,目前飘易就是采用的软件捕获的方案,目前稳定获取私信中。

作者:飘易
来源:飘易
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
上一篇:没有了
下一篇:AWStats网站统计服务器/VPS部署流程介绍
0条评论 “抖音创作者平台获取私信protobuf的方法探讨”
No Comment .
发表评论
名称(*必填)
邮件(选填)
网站(选填)

记住我,下次回复时不用重新输入个人信息
© 2007-2019 飘易博客 Www.Piaoyi.Org 原创文章版权由飘易所有