因为平时工作中对外提供的产品,使用了私有的自定义协议,wireshark抓包分析时需要一个个对序号和字段,十分不方便,学习后,发现wireshark支持lua插件的形式编写自定义的协议解析,将相关方法、学习中的心得进行分享。
插件的加载配置
- 打开wireshark -->帮助-->关于wireshark -->文件夹 -->全局配置
- 点击进入全局配置文件夹,找到init.lua文件,打开(ubuntu需要通过chmod修改文件权限,可以直接无脑777)
- 打开init.lua,最后一行,将自定义解析的lua脚本也放到init.lua同目录下,然后,红框中替换为自己编写的自定义脚本 先确认enable_lua:true
- 而后重启wireshark或者使用快捷键ctrl+shift+h便可以重载脚本,新创建的解析脚本即开始生效。
lua脚本相关知识
创建Proto对象
local Customize_Protocol = Proto('Protocol_Name','Protcol_Desc')
local protoName = 'protocol_name'
上述代码,Protocol_Name字段用于自定义Wireshark报文界面的Protocol列的名称
Protocol_Desc用于定义报文解析字段中的协议字段名称,类似于UDP/TCP
protocol_name用于自定义wireshark显示过滤器时输入的协议名称字段
关于Proto对象的详细说明,参考wireshark官方文档:
11.3. Functions For New Protocols And Dissectors
添加协议字段(使用ProtoField对象)
用于在wireshark解析树中增加节点
local section1 = ProtoField.type1(protoName .. ".name1", "Desc1", parse_type1)
local section2 = ProtoField.type2(protoName .. ".name2", "Desc2", parse_type2)
参数说明:
ProtoFiled.type:指字段的类型,不同参数对应的后续参数说明也可以参考该文档
name1:显示过滤器中可以以该名字来进行显示过滤,比如protocol_name.name1==xxx,用于过滤自定义协议指定字段中特定值
Desc1:在Wireshark解析树中的名称
parse_type1:Wireshark中显示的类型
以ProtoFiled.byte为例子:
关于ProtoFiled对象的参数说明,可以参考官方文档:
11.3. Functions For New Protocols And Dissectors
定义完成各个字段的信息后,需要添加到自定义协议的field中
-- (1) register fields
Customize_Protocol.fields = {section1,section2...sectionx}
具体的解析功能
可以定义函数进行复杂逻辑的解析,一般会针对指定数据进行解析,使用到的方法有:
function Customize_Protocol.dissector(buffer, pinfo, tree)
local buffer_length = buffer:len()
if buffer_length == 0 then return end
local identifier = buffer(0,x)
if (identifier:uint() ~= 0xFFFF) then return end
-- set the name of protocol column
pinfo.cols.protocol = Customize_Protocol.name
-- create a sub tree representing the PTC data
local subtree = tree:add(Customize_Protocol, buffer(), "Protocol Desc")
local section1_subtree = subtree:add(Customize_Protocol, buffer(), "Section1")
-- (2) add fields
section1_subtree:add_le(section2, buffer(0, 2))
section1_subtree:add(section3, buffer(4, 4)) --network endian
end
参数解释:
buffer:某个报文的报文内容(如果后续绑定了tcp/udp就是tcp/udp的payload字段,否则就是抓取到的整个报文)
文档描述:11.6. Functions For Handling Packet Data
pinfo:报文界面的显示内容
文档描述:
11.5. Obtaining Packet Information
tree:协议解析时的结构,需要添加子节点则操作该参数
文档描述:
11.7. Adding Information To The Dissection Tree
子树节点可以继续添加节点,tree.add返回的是新的treeitem节点
local section1_subtree = subtree:add(Customize_Protocol, buffer(), "Section1")
-- (2) add fields
section1_subtree:add_le(section2, buffer(0, 2))
section1_subtree:add(section3, buffer(4, 4)) --network endian
上述就是在sub_tree节点下添加了section2/3两个节点
下面代码用于判断如果没有报文字段,退出不解析
local buffer_length = buffer:len()
if buffer_length == 0 then return end
local identifier = buffer(0,2)
if (identifier:uint() ~= 0xFFFF) then return end
上面代码用于判断特殊的头部标识,例子为头部为ffff
在添加字段,即使用sub_tree.add方法时需要注意:
add/add_le是针对解析时不同端序来处理(也就是大小端)
如果sub_tree后想增加新的备注项目,可以使用方法:
绑定端口
使用TCP时
local tcp_port = DissectorTable.get("tcp.port")
-- bind port to protocol
tcp_port:add(xxxx, Customize_Protocol)
使用UDP时:
local udp_port = DissectorTable.get("udp.port")
-- bind port to protocol
udp_port:add(xxxx, Customize_Protocol)