写点什么

Wireshark 插件开发实战 -Lua 解析自定义二进制协议

  • 2025-05-26
    广东
  • 本文字数:2724 字

    阅读完需:约 9 分钟

Wireshark插件开发实战-Lua解析自定义二进制协议

在调试自定义 TCP 协议时,我们常常需要构造原始的二进制数据包并通过 Wireshark 进行抓包分析。这篇文章记录使用 lua 开发 Wireshark 插件解析私有二进制协议。


  • 使用 Python 构造二进制协议数据包

  • 使用 nc(netcat)发送数据

  • 通过 tcpdump 抓包

  • 通过 Wireshark + lua 插件解析数据包



🧩 协议结构

协议格式如下:


[ uint16: msgType ][ uint16: bodyLen ][ bytes[bodyLen]: JSON字符串 ]
复制代码


例如:


  • msgType = 1(0x0001)

  • bodyLen = 9(0x0009)

  • body = {"a":123}



🛠️ 步骤 1:使用 Python 构造二进制数据

使用 Python 将结构化数据写入一个二进制文件 msg.bin


python3 -c 'with open("msg.bin", "wb") as f: f.write((1).to_bytes(2, "big") + len(b"{\"a\":123}").to_bytes(2, "big") + b"{\"a\":123}")'
复制代码


也可以使用 xxd



echo '000100097b2261223a3132337d' | xxd -r -p > msg.bin
复制代码


文件内容即为:


  • 00 01: msgType = 1

  • 00 09: bodyLen = 9

  • 7b 22 61 22 3a 31 32 33 7d: JSON = {"a":123}


可以使用 xxd 验证内容:


xxd msg.bin
复制代码




🚀 步骤 2:使用 nc 模拟客户端向服务器发送数据

通过 nc 模拟 tcp 服务器监听端口,例如 12345


nc -l -p 12345
复制代码


通过 nc 模拟 tcp 客户端,往服务端发送消息:


# 发送数据到监听端口 12345nc 127.0.0.1 12345 < msg.bin# 也可以通过 xxd生成二进制数据直接发送echo '0001 0009 7b2261223a3132337d' | xxd -r -p | nc 127.0.0.1 12345
复制代码



📱 步骤 3:使用 tcpdump 抓包

sudo tcpdump -i lo port 12345 -w capture.pcap


  1. 启动 Wireshark 打开



  1. 基于 lua 开发 wireshark 插件


--[[    sample.lua © 2025 xinchen@af83f787e8911dea9b3bf677746ebac9
A simple Wireshark Lua dissector for a custom protocol whose payload is: [ uint16 msgType ][ uint16 bodyLen ][ bytes[bodyLen] containing a JSON string ]
To use: 1. Save this file as “sample.lua” (or any name ending in .lua). 2. Place it into your Wireshark plugins directory (e.g., on Windows: C:\Program Files\Wireshark\plugins\<version>\ or under ~/.config/wireshark/plugins/ for Linux/Mac). 3. Restart Wireshark. 4. If your protocol runs over TCP on port 12345, it will now decode automatically. (Adjust the port number in the last lines below to match your actual port.)--]]
-- 1. Define the protocollocal sample = Proto("sample", "My JSON‐Over‐Binary Protocol")
-- 2. Define the fields we want to extract:-- - msgType: uint16-- - bodyLen: uint16-- - jsonStr: the JSON text (bytes interpreted as string)local f_msgType = ProtoField.uint16("sample.msgType", "Message Type", base.DEC)local f_bodyLen = ProtoField.uint16("sample.bodyLen", "Body Length", base.DEC)local f_jsonStr = ProtoField.string("sample.json", "JSON Payload", base.ASCII)
sample.fields = { f_msgType, f_bodyLen, f_jsonStr }
-- 3. The dissector functionfunction sample.dissector(buffer, pinfo, tree) -- buffer: the entire packet’s raw bytes -- pinfo: packet metadata (e.g. columns, protocol) -- tree: the protocol tree to which we add our parsed fields
-- First, ensure we have at least 4 bytes for msgType + bodyLen if buffer:len() < 4 then return 0 end
-- Tell Wireshark which protocol column to display pinfo.cols.protocol = sample.name
-- Add a subtree “My JSON‐Over‐Binary Protocol” local subtree = tree:add(sample, buffer(), "My JSON‐Over‐Binary Protocol Data")
local offset = 0
-- 3.1 Parse msgType (2 bytes) local msgType_field = buffer(offset, 2) local msgType_val = msgType_field:uint() subtree:add(f_msgType, msgType_field) offset = offset + 2
-- 3.2 Parse bodyLen (2 bytes) local bodyLen_field = buffer(offset, 2) local bodyLen_val = bodyLen_field:uint() subtree:add(f_bodyLen, bodyLen_field) offset = offset + 2
-- 3.3 Check if full JSON payload is available if buffer:len() < offset + bodyLen_val then -- If not enough bytes, mark it as malformed/truncated subtree:add_expert_info(PI_MALFORMED, PI_ERROR, "Packet too short for advertised bodyLen") return end
-- 3.4 Extract the JSON string bytes, interpret as ASCII/UTF-8 local json_field = buffer(offset, bodyLen_val) -- We use :string() so that Wireshark will display it as text subtree:add(f_jsonStr, json_field) offset = offset + bodyLen_val
-- (Optional) If you want to pretty-print or validate JSON, -- you could attempt to parse it here or use a heuristic. -- But for most purposes, displaying the raw string is enough.end
-- 4. Register the dissector on a specific TCP port (e.g. 12345).-- Change “12345” to whatever port your protocol actually uses, or-- alternatively hook into a heuristic/UDP/etc. as desired.local tcp_port = DissectorTable.get("tcp.port")tcp_port:add(12345, sample)
-- If your protocol is over UDP, swap the last two lines with:-- local udp_port = DissectorTable.get("udp.port")-- udp_port:add(12345, sample)
复制代码


保存为 sample.lua 并放入 Wireshark 插件目录中(如 ~/.config/wireshark/plugins/,或 window 中 C:\Program Files\Wireshark\plugins\<version>\),重新打开 Wireshark 即可。


🥪 步骤 4(可选):使用 tcpdump 抓包到 .pcap 文件

如果你希望在终端中进行抓包或生成 .pcap 文件用于后续分析,可以在 Windows 主机上安装 WinDump(tcpdump 的 Windows 版本)


  1. 安装 Npcap

  2. 安装 WinDump

  3. 查看接口列表:

  4. 选择正确接口编号,开始抓包:

  5. 使用 Wireshark 打开 test.pcap 文件进行分析。



✅ 总结

通过以上方式,我们完成了以下目标:


  • ✅ 构造自定义协议的二进制数据

  • ✅ 使用 nc 模拟客户端及服务端发送数据

  • ✅ 使用 Wireshark 和 tcpdump 抓包

  • ✅ 编写 Lua 脚本进行协议解析


这种方法适合调试任何基于 TCP/UDP 的自定义协议,非常适合开发和测试场景。




如果你也在调试自己的私有协议,不妨用这个流程走一遍!希望对你有帮助 😎


发布于: 刚刚阅读数: 3
用户头像

Talk is cheap, show me the code. 2019-04-17 加入

勿在浮沙筑高台,沉淀、记录个人的技术笔记与总结。现某金融科技公司开发人员,主要负责网络编程,涉及相关网关组件架构设计与重构,低时延性能优化等。

评论

发布
暂无评论
Wireshark插件开发实战-Lua解析自定义二进制协议_歆晨技术笔记_InfoQ写作社区