什么时候需要裸抓 TCP
HTTP 抓包工具(Charles/mitmproxy)失效的场景:
- App 走私有 TCP 长连接(IM、游戏、物联网协议),根本不是 HTTP
- WebSocket 流量被工具显示得不友好
- QUIC/UDP 协议(HTTP 工具完全盲区)
这时要回到网络层的祖师爷工具:tcpdump 抓包 + Wireshark 分析。
抓包:手机流量的三种捕获方式
方式一:路由器/热点抓包(最通用)
# Mac 开热点,手机连上,直接抓热点网卡
sudo tcpdump -i en0 -w phone.pcap host 手机IP
# 或抓特定端口
sudo tcpdump -i en0 -w phone.pcap 'tcp port 8888'方式二:Android 手机本地抓(root)
adb shell
su
tcpdump -i any -w /sdcard/capture.pcap
# 抓完 adb pull 出来方式三:VPN 型抓包 App(不 root):HttpCanary、Packet Capture 等,本质是本地 VPN 接管流量。方便但对私有协议的支持一般。
Wireshark 分析私有协议的方法论
打开 pcap 后,面对未知的二进制流,按这个流程来:
第一步:找到目标流。Statistics → Conversations 看所有连接,按流量大小和持续时间找到目标长连接。右键 Follow → TCP Stream 看完整数据流。
第二步:识别协议结构。盯着 hex 视图找规律:
0000 00 00 01 2c 08 01 12 03 61 62 63 ...
^^^^^^^^^^^ ^^^^^ ^^^^^
长度前缀 类型 字段开始私有协议的常见结构:魔数/版本 + 长度 + 类型 + 载荷。找几个特征:
- 每条消息开头的固定字节(魔数)
- 长度字段(值和后续字节数吻合)
- 类型字段(小范围枚举值)
第三步:写 Wireshark 插件(Lua)正式解析
流量大时手工看 hex 不现实,写个 Lua dissector:
local myproto = Proto("myapp", "MyApp Protocol")
function myproto.dissector(buffer, pinfo, tree)
local len = buffer(0, 4):uint()
local msg_type = buffer(4, 2):uint()
local subtree = tree:add(myproto, buffer(), "MyApp Protocol")
subtree:add(buffer(0, 4), "Length: " .. len)
subtree:add(buffer(4, 2), "Type: " .. msg_type)
subtree:add(buffer(6), "Payload")
end
tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(8888, myproto) -- 按端口挂接精髓:三个实战技巧
- TLS 加密的私有协议:很多私有协议外面套 TLS。Wireshark 可以配密钥解密——Android 上 hook SSL 库导出 SSLKEYLOGFILE,Wireshark 首选项里加载,TLS 流直接变明文
- 用"已知明文"锚定协议格式:你在 App 里输入"hello"发出去,在 pcap 里搜
68 65 6c 6c 6f(hello 的 hex),找到后往前推协议头——这是定位消息格式的最快方法 - 区分控制消息和业务消息:心跳/ack 消息短且周期出现,业务消息长且由操作触发。分析时先过滤掉心跳噪音(按长度过滤),聚焦业务消息
总结
- 非 HTTP 协议回网络层:tcpdump 抓包 + Wireshark 分析
- 手机抓包三方式:热点抓、root 本地抓、VPN App
- 私有协议结构 = 魔数 + 长度 + 类型 + 载荷,已知明文锚定最快
- TLS 套壳的私有协议用 SSLKEYLOGFILE 解密
交流微信:run1255