资讯动态

网络协议逆向分析实战:从抓包选型到加密识别与动态调试

发布时间:2026/10/16 6:42:34 来源:尧图企业网站定制
简介面向网络协议分析与逆向方向的学习者这套资料整合了法国学者Georges Bossert与Frédéric Guihéry开发的协议分析工具以及香港中文大学关于微信协议分析的研究论文可用于理解网络通信机制、抓包逆向思路尤其适合安全竞赛、移动应用分析与微信游戏场景中的协议特征研究。压缩包约3.11MB核心内容以PDF论文及相关工具说明文档为主体积精炼但主题聚焦便于快速获取关键知识。已有1387人浏览学习说明该题材具备一定关注度适合协议逆向入门者、安全专业学生以及游戏协议研究者参考。从基础概念到实战思路读者可掌握工具的设计逻辑与实际用法同时借助论文深入了解微信协议的分析路径包括流量捕获、字段定位、报文比对、请求响应推断等环节从而在游戏或即时通信场景中形成系统的逆向分析框架。1. 网络协议分析不是玄学一次联调把我从黑匣子里拽了出来有次做模拟项目X的联调服务端把响应体整个加密了客户端这边抓到的全是乱码文档只写了“加密传输”连算法都没标。A同学对着日志调了一下午最后发现根本不是加密算法的问题而是客户端和服务端的时间戳格式差了八个小时。那一次我就明白了一个道理所谓协议分析不是靠猜是给黑匣子装观察窗用抓包把“猜”变成“看”。这篇我打算以网络协议逆向分析为主线拆开讲抓包选型、报文解读、加密特征识别、动态调试四个环节最后用某主流社交App内置小游戏这个场景把完整链路走一遍。想照着复现的新手能拿到可直接执行的命令和判断顺序已经写过抓包脚本的熟手能在选工具、断边界、认加密这些环节看到我的判断依据。咱们平时遇到的绝大多数联调问题、客户端性能问题、反作弊规则设计问题根源都在协议层。你不需要把每个字节都读懂但要知道怎么快速定位关键字段、判断加密方案、验证载荷有没有被篡改。这套能力一次抓包就够入门但想不翻车得把底层逻辑理清楚。2. 抓包不是玄学工具按场景选环境按目标搭2.1 三套抓包方案怎么选我一般这么比先说结论没有万能的抓包工具只有适合当前场景的方案。做协议分析这几年我一般把抓包工具按抓取层级分成三类每一类都有它擅长的位置和明显的短板。第一类是网卡级抓包典型代表是WireShark 和 tcpdump。它直接抓网卡上的原始数据包能看到完整的 TCP 连接过程、TLS 握手细节、连接断开时序这是代理类工具给不了的。缺点是如果流量是 TLS 加密的你只能看到握手过程和加密后的密文除非你能把会话密钥导出来否则看不到业务层内容。第二类是代理级抓包典型代表是 mitmproxy 和 Burp Suite。它在客户端和服务端之间插入一个中间层把 TLS 流量解密后展示成明文请求。这类工具上手最快移动端开发、接口联调、安全测试基本都从它开始。短板也很明显只要客户端做了证书固定Certificate Pinning代理直接失效抓到的全是握手失败。第三类是 Hook 级抓包典型代表是 frida。它直接跑在目标进程里Hook 网络库的函数在数据发送前或接收后把参数和返回值捞出来。它的优势是能看到加密前和解密后的原始数据甚至能直接定位到是哪个函数、哪一行代码在处理这个字段缺点是技术门槛高而且需要调试设备。方案抓取层级适用场景上手成本主要局限网卡级WireShark/tcpdump网卡原始数据包协议时序、TLS 握手、异常连接排查中密文流量看不到业务内容代理级mitmproxy/Burp SuiteHTTP/HTTPS 应用层接口联调、参数分析、抓明文低证书固定直接失效Hook 级frida进程内函数调用拿到加密前/解密后数据、定位生成函数高需要可调试设备我的选型顺序一般是这样先确认目标流量是不是 TLS是 TLS 就先上代理级代理失效再判断是不是证书校验把校验绕过去最后才考虑用 Hook 直接在函数层捞数据。很多新手一上来就上 frida看起来高级其实连目标用的什么协议都没搞清楚反而把问题复杂化了。2.2 本地流量分析环境的三个关键开关工具选好之后环境搭建决定你后面能不能顺利抓到数据。这里以某主流社交App内置小游戏场景为例讲本地流量分析环境的三个关键开关注意都是针对自有设备、模拟训练环境未经授权不要对他人系统做同样的事。第一个开关是系统代理。模拟器里把 Wi-Fi 代理指到本机的 mitmproxy 监听端口这一步通常没问题但如果 App 不走系统代理就要用 iptables 做强制转发把目标端口的流量重定向过来。判断有没有生效看代理工具里有没有连接日志没日志就是流量没过来。第二个开关是 CA 证书信任。代理工具会生成自己的 CA 证书你需要把它安装进系统信任区。Android 7 以上默认不信任用户 CA要把证书挪到系统证书目录或者用 magisk 模块挂载。这里最常见的翻车点就是证书装进用户区后以为成功了一抓全是“无法验证服务器身份”。第三个开关是绕过证书校验。现在大多数App都有 SSL Pinning即使系统信任了 CA客户端仍然只认自己内置的证书。在自有设备上用 frida 脚本绕过常见的思路是 Hook 证书校验相关的函数在客户端要验证证书时直接返回校验成功。一段最基础的 frida 脚本长这样// 在自有测试设备上绕过证书校验仅限授权环境 Java.perform(function () { var TrustManagerImpl Java.use(com.android.org.conscrypt.TrustManagerImpl); TrustManagerImpl.verifyChain.implementation function (unverifiedChain, authMethod, host, clientAuth) { // 直接返回原本要校验的证书链跳过实际验证 return this.verifyChain(unverifiedChain, authMethod, host, clientAuth); }; console.log([*] SSL Pinning bypass loaded); });这段脚本的思路是替换 verifyChain 的实现原本客户端会拿着服务器证书和内置证书做比对比对失败就断开连接现在直接返回验证通过。注意这个脚本只适合在测试设备上验证协议流程用真实业务环境里的证书校验往往还嵌套了多层需要配合调用栈分析去定位具体拦截点。环境搞定后先抓一个正常的请求确认 HTTP 状态码和请求体都正常再开始分析报文。很多人上来就改请求参数最后发现是证书没配好白白浪费时间。3. 把黑匣子拆开从报文结构到加密特征识别3.1 报文怎么读先找边界再看字段最后跟状态拿到一堆抓包数据第一件事不是看内容而是确认报文类型。常见的有三种HTTP/JSON 文本型、自定义二进制型、TLS 加密流。不同类型读法完全不同。HTTP 报文最好读找 CRLF 空行就能区分请求头和请求体Content-Type 和 Content-Length 两个字段一配合就知道载荷边界在哪。JSON 直接格式化看字段名一眼能看出哪些是业务参数、哪些是签名。联调场景里大部分问题在头里比如 Content-Type 写错、Content-Length 对不上就够双方吵半天。我一般会先看响应状态码和返回体的 JSON key再去核对请求参数效率最高。自定义二进制报文稍微难一点常见于游戏对局上报、长连接推送这类场景。判断顺序是先找包边界和长度字段——这些协议的公共头部里通常会有一个固定魔数比如 0x5A 开头和一个长度字段再找字段顺序一般协议文档里会规定字段排列最后看有没有校验码通常放在包尾可能是 CRC32 或者简单的 XOR 校验。定位边界有一个土办法把同样类型的包多抓几个对齐相同 offset 看哪些字节是固定的、哪些是变化的。TLS 加密流最特殊你在 WireShark 里看到的只有握手过程和密文拿不到业务数据。这时候要么靠代理解密要么导出会话密钥给 WireShark 解密。教大家一个判断链路是否正常的命令用 tcpdump 抓包看 TLS 握手状态# 抓取某端口上的 TLS 握手过程分析协议时序 tcpdump -i eth0 -A -s 0 tcp port 443 and (tcp[((tcp[12] 0xf0) 2)] 0x16) -w handshake.pcap这里用tcp[((tcp[12] 0xf0) 2)] 0x16过滤出 TLS 握手报文0x16 是 Handshake 协议类型。抓到包后打开 pcap只看 ClientHello 和 ServerHelloServerHello 里带了加密套件和随机数如果这个报文能正常看到说明 TLS 握手已经建立问题多半在应用层如果 ClientHello 发出去没有响应先怀疑端口不对或者网络不通。读报文最后一步是跟状态。别只看单条请求要把有因果关系的几条串起来登录接口拿 token → 带 token 请求游戏配置 → 上报对局数据。状态跟住了你才能判断一个字段是服务端下发后回传的还是客户端本地计算的这在后面加密识别里是关键的判断依据。3.2 三种常见加密特征的识别思路很多人拿到密文第一反应是“这是什么加密算法”想靠特征去猜。我一般会反过来先判断它是不是加密再判断是什么编码最后才考虑算法的可能性。常见的思路是按熵值和可读性分层判断。第一类是纯编码Base64、Hex、URL-encoding 这类。特征是字符集受限Base64 只会有A-Za-z0-9/Hex 只会有0-9a-f而且长度严格对齐。识别方法很简单直接把字符串丢进解码工具解出来看可读性解出来是 JSON 或者可读文本说明根本没有加密就只是编码传输。很多游戏协议里的用户信息就是 Base64解出来直接能改。第二类是自定义编码常见于协议魔改比如把标准 Base64 的字符表换掉或者在每个字节后插入一个固定干扰字节。特征是看似可读但解码工具解出来全是乱码。遇到这种我一般会对比同一字段在不同包里的值如果长度固定、前缀固定、只有中间一段变化大概率是个加了盐的编码或简单 XOR。特征的典型表现是同一字段加密后长度不变或者只多一个固定长度。第三类是标准加密AES/DES/RSA 这类。特征最明显的是长度AES 加密后一定是 16 的整数倍RSA 公钥加密结果是固定的块长度比如 128 字节/256 字节。还有一个判断角度是看相同输入的输出是否一致——把同一个请求原样重发如果密文每次都一样说明没有加随机 IV大概率是 ECB 模式或自定义简单加密如果每次都不一样但长度固定大概率是 CBC 模式或带了随机盐。特征表现初步判断下一步操作只含字母数字和/Base64 类编码直接解码看可读性长度固定、前缀固定、中间变化自定义编码或带盐 XOR对齐多个包找干扰字节密文长度是 16 的整数倍且每次相同AES-ECB 或固定密钥简单加密尝试找密钥或分析 IV密文长度固定 128/256 字节RSA 类非对称加密找公钥文件、确认填充模式这里要注意一个常见误区把 Base64 当成加密。我见过不止一个朋友对着 Base64 字符串研究了一晚上“解密算法”最后我告诉他 Base64 是编码不是加密当场翻车。判断“是不是加了密”最简单的办法是计算信息熵纯文本编码后字符分布有规律真加密后的字节分布接近均匀随机高熵值才是加密信号。识别完特征下一步才是定位加密算法的实现位置。这一步通常要结合动态调试也就是我们下一章要走的完整实战链路。4. 某社交App协议分析实战登录态与游戏流量定位4.1 登录态的参数从哪来从接口到本地计算的完整链路拿某主流社交App内置小游戏来走一遍完整流程。目标是对局上报接口它每次上报时会带一串固定的参数里面有用户标识、对局时长、得分、以及一个签名。我们想知道这个签名算法在哪里生成。最常见的分析路径是从抓包定位到接口再从接口反查调用位置。先用代理抓一次正常对局上报拿到完整 URL 和参数名然后在 frida 里按字符串搜索这个 URLHook 到发起请求的类// 定位对局上报接口的调用位置与参数拼装点 Java.perform(function () { var OkHttpClient Java.use(okhttp3.OkHttpClient); OkHttpClient.newCall.implementation function (request) { var url request.url().toString(); if (url.indexOf(reportGame) 0) { console.log([*] 捕获上报接口: url); console.log([*] Headers: request.headers().toString()); console.log([*] Body: request.body().toString()); } return this.newCall(request); }; });这段代码的意图是在请求发出前拦截 OkHttp 的 newCall 方法把所有带reportGame关键字的请求打出来URL、Headers、Body。跑一次游戏对局frida 日志里就能看到完整的调用链源头。接下来就是顺着日志往上层追谁调用了 newCall参数从哪里组装。用 frida 的栈回溯功能能看到一个调用栈列表一般能找到几个关键类名。定位到调用点之后判断哪些参数是服务端下发的、哪些是本地拼装的。比如用户标识通常存在本地数据库或登录接口返回后缓存对局时长和得分必然是本地实时计算剩下的签名参数一般是一个独立函数生成。把那个函数的入参和返回值各打一遍 log就能还原出整个拼装链路参数字段排序 → 拼接字符串 → 计算摘要 → 作为签名请求字段提交。走完这一步你就掌握了这个接口从业务逻辑到网络传输的全部细节。很多人会卡在“签名不知道从哪里来的”这个坎其实方法就一个——顺着发起请求的位置往回追逐个函数打 log总能找到源头。不要试图去猜算法要去找实现。4.2 游戏数据包的重放与校验一次模拟请求的完整过程拿到签名生成链路后验证我们的理解对不对最直接的办法是构造一个模拟请求修改对局时长重新生成签名重放给服务端看服务端能不能接受。这里先说明一个关键点签名能不能被正确生成取决于你对参数拼装顺序的还原准不准确。大多数签名算法就是把一堆参数按固定顺序拼成一个字符串再算个摘要。只要你在 frida 里把原始拼接串完整打印出来对比自己的实现就很容易确认。我用 Python 构造一个本地重放脚本来做验证# 模拟对局上报请求验证签名算法理解是否准确 import hashlib import time import requests # 从抓包日志中提取的参数模板 base_params { uid: user_10086, game_id: 2048_v1, duration: 120, # 原始对局时长 score: 32000, ts: int(time.time()) } # 根据 frida 栈回溯还原出的签名拼装顺序 raw_string uid{uid}game_id{game_id}duration{duration}score{score}ts{ts}.format(**base_params) sign hashlib.md5(raw_string.encode(utf-8)).hexdigest() base_params[sign] sign # 重放请求观察服务端校验结果 resp requests.post(https://target.example/reportGame, jsonbase_params, timeout5) print(resp.status_code, resp.text)这个脚本的作用是验证我们对签名算法的理解如果服务端返回正常接受说明拼装顺序和摘要算法都还原正确如果返回签名错误就把 frida 抓到的原始拼接串和脚本里的 raw_string 逐字节对比找出差异。差异通常出现在参数排序、空值字段、时间戳单位这几个地方。有了重放能力接下来就能做更细的校验判断。把同样的请求原样重发两次如果第二次被拒绝说明服务端有防重放机制常见的实现是时间戳窗口加上一次性 nonce 校验。这时把脚本里的 ts 改成服务器返回的时间再算一次签名往往就能通过。反过来如果改一个参数不影响签名校验说明这个参数没参与签名——这在反作弊规则里是个明显的漏洞点。到这一步这个游戏的上报接口分析就完成了你不但知道协议长什么样还能自己构造一个合法请求。对做安全测试的人来说接下来可以继续验证服务的校验强度对做反作弊规则的人来说你清楚攻击者会从哪里下手才能在那个点做加固。同一个分析结果不同角色拿到的价值完全不同。5. 协议分析避坑指南五个翻车现场5.1 证书信任了还是解密失败现象代理工具已经安装了 CA 证书系统设置里也显示信任但抓 HTTPS 请求时仍然提示“无法解密”客户端直接报证书错误。原因这里大部分人只做了第一步——把 CA 装进用户信任区但目标App用的是系统级证书校验甚至自己实现了证书固定逻辑。系统信任不等于应用信任两层是分开的。解决先用 frida 脚本验证是不是 Pinning 拦截上一章那个 verifyChain 脚本如果是就在自有设备上过掉校验。另外要注意 Android 7 以上用户 CA 默认不被应用信任需要把证书挂载到系统证书目录。经验之谈模拟器里能过真机上不一定能过真机调试多准备一台备用机别把时间耗在环境上。5.2 抓到包但找不到调用方现象代理工具里能看到某个接口在定时请求但 frida 里搜 URL 字符串也搜不到代码里也搜不到这个路径像凭空出现的一样。原因最常见的有三种接口路径是客户端从服务端动态下发的配置中心拉取路径经过了拼接比如 base URL 加路径前缀在运行时拼出来或者请求走了 native 层根本不是 Java/Kotlin 发起OkHttp 的 Hook 自然拦不到。解决先把抓包数据里的请求头全部打出来看 User-Agent、自定义 Header 是否有特征用这些特征去 Hook。其次在 frida 里 Hook 更底层的 socket 写入函数看字节流先经过谁确认走了 native 层之后再考虑 Hook so 层导出函数。不要死磕字符串搜索路是动态拼的。5.3 把 Base64 当成加密现象拿到一段“密文”看着像乱码研究了两天算法最后发现解码出来就是明文 JSON压根没加密。原因Base64 这种编码方式输出的字符看起来很随机尤其是后面带着填充符主观上会以为是被处理过的加密数据。很多客户端开发者也只是“为了安全”套一层编码并没有真正加密。解决拿到任何不可读字符串第一步永远先是尝试 Base64 解码和 Hex 解码解出来能读出语义的哪怕只是部分字段都说明没有加密或只有轻量混淆。从信息熵角度判断真正的加密数据在字节分布上是均匀的字符种类会覆盖所有可见字符。以后我每拿到一个奇怪字符串第一反应都是先解码再谈算法。5.4 重放成功一次第二次就被踢现象模拟请求第一次重放服务端正常返回数据间隔几秒原样重发第二次直接被拒绝或者账号被临时限制。原因服务端有防重放机制。常见的实现是时间戳窗口校验请求里的 ts 和服务器当前时间差超过阈值就拒绝比如超过 5 分钟失效或者用一次性 nonce 字段每个 nonce 只能使用一次。第一次成功是因为 timestamp 还算新鲜第二次原样重发时 ts 没有更新服务端发现时间戳过期或 nonce 重复直接判定为异常请求。解决让脚本里的 ts 每次取当前时间重放前从最新抓包里重新提取所有需要动态更新的字段如果服务端下发 nonce就先去请求一次新 nonce 再上报。还有一个容易被忽略的细节——某些时间戳是毫秒单位有些是秒单位差了三位数就会得出“时间永远不对”的结论踩过一次这个坑的人都会记得先看单位。5.5 只看明文不确认来源现象代理工具里看到了某个关键参数直接在测试环境改了它结果服务端返回“非法请求”排查了半天发现这个参数根本不是客户端生成的而是服务端登录时下发的会话数据。原因没有区分字段的来源就动手改是协议分析里最常见的翻车原因。有些字段是一次性下发的服务端内存里存着副本请求时原样传回去校验。你以为改了就能绕过其实服务端拿它跟自己的记录比对对不上就直接拒绝。解决在任何字段被修改前先完成一次“来源确认”看它是登录接口返回的、配置接口下发的、本地数据库读的还是实时计算的。方法就是前面 4.1 说的顺着调用链往回追。判断完来源再决定这个字段能不能改、怎么改、改了会触发哪一层校验。血泪经验不要拿到包就改先追来源再动手能省下大半天排查时间。6. 让分析结果变成可复现的能力6.1 把刚才这一套压缩成一个最小流程分析完案例之后我会把这些零散步骤压缩成一套可复用的操作流程任何新协议拿到手都能按这个顺序走一遍而不是每次从零开始想。流程一共五步第一步抓包确认协议类型和报文边界判断是 HTTP 还是自定义二进制第二步用代理或 Hook 定位关键接口的调用链路确认每个字段的来源第三步对所有不可读字段做编码识别先解码再看熵值确认是否真有加密第四步还原签名或校验参数的生成方式用本地脚本验证理解第五步做重放测试确认服务端校验强度同时记录哪些字段能改、哪些不能碰。这里面最容易被跳过的就是第二步但也是最值得花时间的。我对这套流程的信任来自一次我自己的教训有一回我分析某跨平台系统的登录接口凭经验觉得签名是 MD5直接按 MD5 去生成重放请求连续失败三次。后来老老实实走了全流程才发现签名前还有一次自定义异或处理MD5 只是最后一层。从那以后我每次拿到新协议都强制走一遍完整流程不跳步、不猜算法宁可多花半小时追链路也不靠玄学试错。6.2 两个原则比具体工具更保值工具会过时抓包环境也会变但两个原则这几年一直没变过。第一个原则是“先确认边界再分析内容” —— 不管是报文结构还是证书校验先把边界画清楚后面的工作才有意义。第二个原则是“用重放来验证理解” —— 你能构造一个服务端接受的请求才说明你真的读懂了它。这两条是我踩了无数坑之后总结出来的希望对你有帮助。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑