Facebook Messenger API 逆向技术难点详解本文档详细分析 项目中遇到的 API 逆向技术难点及其解决方案目录E2EE 端到端加密协议逆向GraphQL API 的 doc_id 逆向动态 Token 提取MQTT WebSocket 消息同步协议ID 生成算法逆向移动 APP 登录协议逆向响应反混淆处理技术难点总结表一、E2EE 端到端加密协议逆向 ⭐⭐⭐⭐⭐最难技术挑战Facebook Messenger 的 E2EE 使用Signal Protocol Meta 内部Labyrinth/Lightspeed协议纯 Python 实现几乎不可能原因如下涉及10 万 行 Go 代码已有成熟实现需要处理Curve25519、Double Ratchet、Sender Keys等复杂密码学算法协议频繁更新维护成本极高安全审计要求严格自行实现风险大解决方案Go 桥接混合架构核心思路Python 不自己实现加密而是调用成熟的 Go 库mautrix/meta进程间通信设计# _listening_e2ee.py - 启动 Go 桥接进程class_BridgeProcess:def__init__(self,binary:Path,*,log_stderr:boolTrue)-None:# 启动 Go 子进程self._procsubprocess.Popen([str(binary)],stdinsubprocess.PIPE,# Python → Gostdoutsubprocess.PIPE,# Go → Pythonstderrsubprocess.PIPE,bufsize0,)# 启动线程异步读取事件self._readerthreading.Thread(targetself._read_loop,daemonTrue)self._reader.start()JSON-RPC 协议封装defcall(self,method:str,params:Optional[dict]None,timeout:float60.0):# 构建 JSON-RPC 请求ridnext(self._next_id)payload{id:rid,method:method,params:paramsor{}}line(json.dumps(payload,separators(,,:))\n).encode(utf-8)# 写入 Go 进程 stdinself._proc.stdin.write(line)self._proc.stdin.flush()# 等待响应respq.get(timeouttimeout)returnresp.get(data)or{}发送 E2EE 消息defsend_e2ee_message(self,chat_jid:str,text:str,...):returnself._bridge.call(sendE2EEMessage,{chatJid:chat_jid,text:text,replyToId:reply_to_id,replyToSenderJid:reply_to_sender_jid,})架构优势优势说明✅ 安全性高使用经过审计的成熟代码库✅ 维护简单无需自己维护加密算法✅ 性能好Go 更适合加密计算✅ 稳定性强Go 崩溃不会影响 Python二、GraphQL API 的 doc_id 逆向 ⭐⭐⭐⭐技术挑战Facebook 使用Relay Modern GraphQL框架每个查询都有固定的doc_iddoc_id是 GraphQL 查询的哈希标识从前端 JavaScript 代码中提取随着 Facebook 版本更新而变化没有公开文档需要逆向查找代码实现GraphQL 查询构建# _search.py - 搜索功能实现deffunc(dataFB,keywordSearch):# doc_id6866854183333610 是通过逆向分析得到的dataFormformAll(dataFB,SearchCometResultsInitialResultsQuery,6866854183333610)# GraphQL variables 需要严格匹配前端格式dataForm[variables]json.dumps({count:5,args:{callsite:COMET_GLOBAL_SEARCH,context:{bsid:str(randStr(8)-randStr(4)-randStr(4)-randStr(4)-randStr(12)),tsid:str(random.random())},text:str(keywordSearch)},cursor:None,feedbackSource:23,fetch_filters:True,# ... 更多参数少一个都可能失败})工具函数封装# _utils.py - GraphQL 表单构建defformAll(dataFB,FBApiReqFriendlyNameNone,docIDNone,requireGraphqlTrue):dataForm{fb_dtsg:dataFB[fb_dtsg],jazoest:dataFB[jazoest],__a:1,__user:str(dataFB[FacebookID]),__req:str_base(__reg,36),__rev:dataFB[clientRevision],av:dataFB[FacebookID],}ifrequireGraphql:dataForm[fb_api_caller_class]RelayModerndataForm[fb_api_req_friendly_name]FBApiReqFriendlyName dataForm[doc_id]str(docID)# 关键逆向得到的查询 IDreturndataForm三、动态 Token 提取 ⭐⭐⭐⭐技术挑战动态 Tokenfb_dtsg,jazoest,hash等嵌入在 HTML 中的 JavaScript 变量里格式经常变化Facebook 不定期修改需要从混淆的 JS 代码中提取没有固定的 DOM 结构不能用 XPath/CSS 选择器解决方案字符串分割技术Token 提取实现# _session.py - 从首页提取 TokendefdataGetHome(setCookies):# 请求首页 HTMLsendRequestsrequests.get(**mainRequests).text# 使用字符串分割技术比 HTML 解析更稳定splitDataList[# 格式[变量名, 前缀标记, 后缀标记][fb_dtsg,DTSGInitialData,[],{token:,],[fb_dtsg_ag,async_get_token:,],[jazoest,jazoest,],[hash,hash:,],[sessionID,sessionId:,],[FacebookID,actorID:,],[clientRevision,client_revision:, ,],]dictValueSaved{}foriinsplitDataList:nameValuei[0]try:exportValuedataSplit(i[1],i[2],HTMLsendRequests,defaultValueTrue)except(IndexError,AttributeError,TypeError):exportValuefUnable to retrieve data for{nameValue}dictValueSaved[nameValue]exportValuereturndictValueSaved分割工具函数# _utils.py - 字符串分割工具defdataSplit(string1,string2,numberSplit1None,numberSplit2None,HTMLNone,...):ifdefaultValue:numberSplit1,numberSplit21,0# 先按前缀分割取后半部分再按后缀分割取前半部分returnHTML.split(string1)[numberSplit1].split(string2)[numberSplit2]四、MQTT WebSocket 消息同步协议 ⭐⭐⭐⭐技术挑战实现实时消息监听需要解决MQTT 主题和消息格式的逆向sequence_idsync_token的增量同步机制断线重连和队列溢出处理消息去重和状态维护代码实现MQTT 连接配置# _listening.py - MQTT 连接实现defconnect_mqtt(self):# 构建连接参数完全模拟浏览器user{u:self.dataFB[FacebookID],s:session_id,chat_on:json_minimal(True),fg:False,d:generate_client_id(),ct:websocket,aid:219994525426954,# Facebook 应用 IDst:/t_ms,cp:3,ecp:10,}hostfwss://edge-chat.facebook.com/chat?regioneagsid{session_id}# MQTT 客户端配置self.mqttmqtt.Client(client_idmqttwsclient,clean_sessionTrue,protocolmqtt.MQTTv31,transportwebsockets,)增量同步机制def_messenger_queue_publish(client:mqtt.Client,userdata,flags,rc):# 关键先获取 last_seq_idself.get_last_seq_id()queue{sync_api_version:10,max_deltas_able_to_process:1000,delta_batch_size:500,encoding:JSON,entity_fbid:self.dataFB[FacebookID],orca_version:1.2.0}# 首次连接 vs 后续增量同步ifself.syncTokenisNone:topics/messenger_sync_create_queuequeue[initial_titan_sequence_id]self.lastSeqIDelse:topics/messenger_sync_get_diffsqueue[last_seq_id]self.lastSeqID queue[sync_token]self.syncToken# 发布同步请求client.publish(topics,json_minimal(queue),qos1)消息处理与错误恢复defon_message(client,userdata,msg):jjson.loads(msg.payload.decode())# 解析消息 deltaifj.get(deltas)isnotNone:deltaj[deltas][0]ifdelta.get(messageMetadata)isnotNone:self.bodyResults[body]delta.get(body)self.bodyResults[userID]delta[messageMetadata][actorFbId]self.bodyResults[messageID]delta[messageMetadata][messageId]# 更新同步标记避免重复消息ifsyncTokeninjandfirstDeltaSeqIdinj:self.syncTokenj[syncToken]self.lastSeqIDj[firstDeltaSeqId]# 队列溢出处理errorCode100iferrorCodeinjandj[errorCode]100:print(Queue overflow - resetting and retrying...)self.syncTokenNoneself.get_last_seq_id()五、ID 生成算法逆向 ⭐⭐⭐技术挑战Facebook 使用多种自定义 ID 算法threading_id时间戳 随机数的二进制组合client_idUUID 格式但非标准 UUIDsession_id随机 64 位整数这些算法没有公开文档必须通过抓包分析逆向得到。代码实现Threading ID最复杂# _utils.py - threading_id 生成defgen_threading_id():returnstr(int(# 步骤1时间戳毫秒转二进制format(int(time.time()*1000),b)# 步骤232位随机数转二进制取后22位(0000000000000000000000format(int(random.random()*4294967295),b))[-22:]# 步骤3合并后转十进制,2))Client IDdefgenerate_client_id():defgen(length):return.join(random.choices(string.ascii_lowercasestring.digits,klength))# 格式xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxreturngen(8)-gen(4)-gen(4)-gen(4)-gen(12)Session IDdefgenerate_session_id():# 1 到 2^53-1 范围的随机整数returnrandom.randint(1,2**53)六、移动 APP 登录协议逆向 ⭐⭐⭐⭐技术挑战模拟Facebook Android 客户端登录需要生成完整的设备指纹device_id, machine_id, adid提取固定的 API Key 和 Access Token处理 2FA 双因素认证流程构建正确的请求签名代码实现设备指纹生成# _facebookLogin.py - 登录类初始化classloginFacebook:def__init__(self,username,password,AuthenticationGoogleCodeNone):# 生成设备指纹UUID 格式self.deviceIDself.adIDself.secureFamilyDeviceID\f{randStr(8)}-{randStr(4)}-{randStr(4)}-{randStr(4)}-{randStr(12)}self.manchineIDrandStr(24)self.usernameFacebookusername self.passwordFacebookpassword self.twoTokenAccessAuthenticationGoogleCode请求头构建def_headers(self):return{Host:b-graph.facebook.com,# 模拟 Android 客户端 User-AgentUser-Agent:Dalvik/2.1.0 (Linux; U; Android 7.1.2; SM-G988N Build/NRD90M) [FBAN/FB4A;FBAV/340.0.0.27.113;FBPN/com.facebook.katana;FBLC/vi_VN;],X-Fb-Friendly-Name:authenticate,Authorization:OAuth null,X-Fb-Connection-Type:unknown,X-Fb-Connection-Quality:EXCELLENT,}登录表单构建def_base_form(self,password,credentials_type,try_num):return{adid:self.adID,device_id:self.deviceID,machine_id:self.manchineID,email:self.usernameFacebook,password:password,credentials_type:credentials_type,# 逆向得到的固定值api_key:882a8490361da98702bf97a021ddc14d,access_token:350685531728|62f8ce9f74b12f84c123cc23437a4a32,jazoest:22421ifcredentials_typepasswordelse22327,# ... 更多参数}2FA 处理流程defmain(self):# 第一步密码登录data_formself._base_form(self.passwordFacebook,password,1)dataJsonself._login(data_form)# 如果需要 2FAerror_subcode 1348162errordataJson.get(error)iferroranderror.get(error_subcode)1348162:token_2faGetToken2FA(self.twoTokenAccess)data_form_2faself._base_form(token_2fa,two_factor,2)data_form_2fa[twofactor_code]token_2fa data_form_2fa[userid]error.get(error_data,{}).get(uid,)data_form_2fa[first_factor]error.get(error_data,{}).get(login_first_factor,)returnself._login(data_form_2fa)returndataJson七、响应反混淆处理 ⭐⭐技术挑战Facebook API 响应会添加for (;;);前缀防止 JSON 劫持攻击必须先移除前缀才能解析 JSON所有 POST API 都有这个特性代码实现# _send.py - 消息发送响应处理sendRequestsrequests.post(**_main).text# 移除 for (;;); 前缀sendRequestsjson.loads(sendRequests.split(for (;;);)[1])# _attachments.py - 附件上传响应处理resultRequestsrequests.post(...).text resultRequestsjson.loads(resultRequests.replace(for (;;);,))[payload]八、技术难点总结表难点难度核心技术解决方案文件位置E2EE 加密⭐⭐⭐⭐⭐Signal ProtocolGo 桥接进程 JSON-RPC_listening_e2ee.pyGraphQL doc_id⭐⭐⭐⭐Relay Modern逆向前端 JS 获取 ID_search.py,_utils.pyToken 提取⭐⭐⭐⭐字符串分割HTML 字符串分割技术_session.py,_utils.pyMQTT 协议⭐⭐⭐⭐WebSocket增量同步 队列管理_listening.pyID 生成算法⭐⭐⭐位运算时间戳随机数组合_utils.pyAPP 登录⭐⭐⭐⭐HTTP 请求模拟设备指纹 2FA_facebookLogin.py响应反混淆⭐⭐字符串处理移除for (;;);前缀_send.py,_attachments.py附录逆向工程工具推荐工具用途Charles ProxyHTTP/HTTPS 抓包分析Wireshark网络协议分析MQTT/WebSocketChrome DevTools前端 JS 调试、网络请求分析Frida移动端 App 逆向Ghidra二进制逆向分析⚠️ 重要声明本文档仅供技术研究和学习使用。使用逆向技术访问 Facebook 服务可能违反其服务条款请遵守相关法律法规和平台规定。