为wireshark
编写自定义lua
插件解析自定义协议
1.怎么写lua
脚本?写完放在哪生效?
wireshark
自定义lua
插件进行解析需要使用官方的预留给lua
的API
,其中想实现解析功能必须实现自己的dissector
这个函数,该函数对应每个协议需要实现一个实体,并注册到wireshark
插件中。
基本开发步骤如下:
- 注册协议名称
- 定义协议基本字段
- 实现
dissector
函数 - 将插件注册到
wireshark
写完的lua
脚本根据个人安装wireshark
的路径不同或者配置不同,可能需要放到不同位置,默认路径可以在wireshark
中查看(帮助->关于->文件夹->个人lua
插件)
一般默认路径为:C:\Users\Administrator\AppData\Roaming\Wireshark\plugins
,将写好的插件代码放到该目录,重启程序即可生效
2.基本框架代码及详细说明
背景说明:
假定自定义应用层协议采用如下结构体,传输层协议使用UDP
,基本框架如下
| 自定义协议结构体 |------------------------->msgType //表示消息类型 Uint8
|_________________________| bodyLengthSpecific //消息的特定校验数 Uint8
| | bodyLength //表示当前消息的长度 Uint16
| UDP Protol | msgBody //可变长数组,消息体的实际内容,具体长度由bodyLength标识
|_________________________|
--设置基本信息 [可选]
local plugin_info = {
version = "1.0.0",
description = "wireshark plugins",
author = "xiaowang"
}
set_plugin_info(plugin_info) --官方API函数,这里设置的信息可以在wireshark的插件信息中看到
local demo_protol = Proto("demo_protol","demo_protol") --利用Proto函数注册自己的协议,协议名称为demo_protol [必选]
--向自己的协议中添加字段,这里是自己的协议格式
--定义字段
--ProtoField.uint 注册字段 [必选]
-- 第一个参数是字段名称,该字段在协议主体上
-- 第二个字段是字段显示在wireshark中显示时候的名称
-- 第三个字段是该字段显示的格式,十六进制或者十进制 [可选]
local Header_msgType = ProtoField.uint8("demo_protol.msytype","Msg Type", base.HEX)
local Header_bodyLengthSpecific = ProtoField.uint8("demo_protol.bodyLengthSpecific","Body Length Specific", base.DEC)
local Header_bodyLength = ProtoField.uint16("demo_protol.bodyLength","Body Length", base.DEC)
--把字段添加到协议的子项中 [必选]
demo_protol.fields = {
Header_msgType,
Header_bodyLengthSpecific,
Header_bodyLength,
}
--使用默认方法解析的数据部分,此方法用于最后不处理的数据部分显示到解析栏中
local data_dis = Dissector.get("data") --[可选]
function dlcfg_header_parser(buf,pkt,tree,offset)
local subtree = tree:add(demo_protol, buf(offset),"Dlcfg_Header")
--不再继续演示怎么解析Dlcfg_Header的消息体部分
--do something
--后续字段调用默认解析函数
data_dis:call(buf(offset+2):tvb(),pkt,tree) --第一个参数表示解析数据的长度,buf(offset+2):tvb()表示从offset+2开始到结束
end
--协议解析函数主体,wireshark运行之后,会自动调用此函数
--[[
tree:add(demo_protol, buf(0)) 表示将UDP协议之后的数据的初始字段交给demo_protol协议进行解析
subtree 表示在wireshark界面添加一个解析子树
subtree:add 表示向解析子树中添加字段
第一个参数是解析协议名称,该名称由Proto注册
第二个参数是解析字段在bit流中的位置 buf(a,b)表示从a位置开始,几个字节属于当前字段
第三个参数是设置显示界面上该子树的名称
]]--
--demo_protol.dissector可以理解为这个函数就是解析该协议的入口函数
--buf表示数据流指针,按照自定义协议注册的位置开始,第一个字节起始处,本协议下层依赖UDP
--那么buf(0)就表示从UDP协议结束之后的第一个字节开始
--pkt表示该数据包,可以通过pkt获取到数据包的其他属性
--tree在这里是根树,所有的解析数据最后都会通过add方法挂接到这个上面
function demo_protol.dissector(buf,pkt,tree)
local subtree = tree:add(demo_protol, buf(0),"Demo Msg Header")
pkt.cols.protocol = "demo_protol" --这里是显示在wireshark每一行中的名称
local msgtype = buf(0,1):uint()
subtree:add(Header_msgType,buf(0,1))
subtree:add(Header_bodyLengthSpecific,buf(1,1))
subtree:add(Header_bodyLength,buf(2,2))
--调用函数解析API_DLCFG_REQ消息头部
if(msgtype == 0x80) then
dlcfg_header_parser(buf,pkt,tree,4)
else
data_dis:call(buf(offset+2):tvb(),pkt,tree) --不符合要msgtype求的直接采用默认解析
end
end
--注册本插件到wireshark中
--指定本协议传输层采用的udp协议,在udp协议端口列表的8888端口中,协议名称demo_protol
--注意:协议名称一旦由Proto注册之后,不可以更改,凡是使用协议名称的地方均使用该名称
DissectorTable.get("udp.port"):add(8888, demo_protol)