基于Lua语言的wireshark插件编写

一、两种语言开发插件的对比

  • 想要开发wireshark插件,我们可以使用C语言也可以使用Lua语言。如下图,是使用两种语言开发插件的对比。基于Lua语言的wireshark插件编写_第1张图片
  • 如上图,我最后选择使用Lua语言进行开发wireshark插件。

二、插件功能

  • 目前我有一个任务,需要解析RTP包的payload,这个payload前三个字节是自定义的字节,后面的才是H264的数据、或者OPUS的数据。
  • 因此我需要在RTP包的上层进行解析RTP包的payload,并且让H264的数据按照H264的格式或者OPUS的格式来显示。基于Lua语言的wireshark插件编写_第2张图片

本篇博文重点介绍如何基于Lua语言去编写wireshark插件。

  • 具备的基础:
    1. Lua语言基础,可以去这个网站去学习简单的Lua语言基础。https://www.runoob.com/lua/lua-miscellaneous-operator.html
    2. 熟悉wireshark的使用,并且去浏览一下wireshark支持Lua语言的API。https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html
    3. 剩下的就只需要看一下我的这篇博文就好了

三、Lua插件API介绍

3.1 Proto
  • 表示一个新的Protocol,在Wireshark中Protocol对象有很多用处,解析器是其中主要的一个。主要接口有:
接口 说明
proto:__call (name,desc) 创建Proto对象。name和desc分别是对象的名称和描述,前者可用于过滤器等
proto.name get名称
proto.fields get/set字段
proto.prefs get配置项
proto.init 初始化,无参数
proto.dissector 解析函数,3个参数tvb,pinfo,tree,分别是报文内容,报文信息和解析树结构
proto:register_heuristic (listname, func) 为Proto注册一个启发式解析器,被调用时,参数func将被传入与dissector方法相同的3个参数
  • 如下的例子,创建一个新的协议
local NAME1          = "red"
local PORT           = 5004
local RTP_PROTO_TYPE = 106
local red    = Proto(NAME1, "Red Protocol")
3.2 ProtoField
  • 表示协议字段,一般用于解析字段后往解析树上添加节点。根据字段类型不同,其接口可以分为两大类。

  • 整型:
    • ProtoField.{type} (abbr, [name], [desc],[base], [valuestring], [mask])
    type包括:uint8, uint16, uint24, uint32, uint64, framenum

  • 其他类型
    • ProtoField.{type} (abbr, [name], [desc])
    type包括:float, double, string, stringz, bytes, bool, ipv4, ipv6, ether,oid, guid

  • 这些接口都会返回一个新的字段对象。方括号内是可选字段,花括号内是可替换的类型字段。

  • 如下图的例子,

-- create fields of red
fields_M             = ProtoField.uint8 (NAME1 .. ".M", "M", base.HEX,Payload_type,0x80)
fields_pt            = ProtoField.uint8 (NAME1 .. ".PT", "PT", base.DEC,Payload_type,0x7F)
fields_seqno         = ProtoField.uint16(NAME1 .. ".seqno", "Sequence number")
fields_h264bytes     = ProtoField.bytes(NAME1 .. ".bytes", "H264Data")
fields_fec           = ProtoField.bytes(NAME1 .. ".fec", "FEC Payload")
  • 当添加这写字段后,我们看如下图的实际加载情况
    基于Lua语言的wireshark插件编写_第3张图片
3.3 Tvb
  • Tvb(Testy Virtual Buffer)表示报文缓存,也就是实际的报文数据,可以通过下面介绍的TvbRange从报文数据中解出信息。主要接口有:
接口 说明
tvb:__tostring() 将报文数据转化为字符串,可用于调试
tvb:reported_len() get tvb的(not captured)长度
tvb:len() get tvb的(captured)长度
tvb:reported_length_remaining() 获取当前tvb的剩余长度,如果偏移值大于报文长度,则返回-1
tvb:offset() 返回原始偏移
  • 我们最常使用应该就是“tvb:len()”
3.4 Pinfo
  • 报文信息(packet information)。主要接口有:
接口 说明
pinfo.len pinfo.caplen get报文长度
pinfo.abs_ts get报文捕获时间
pinfo.number get报文编号
pinfo.src pinfo.dst get/set报文的源地址、目的地址
pinfo.columns pinfo.cols get报文列表列(界面)
  • 取得报文列表列后,就可以设置该列的文本,比如
    -- show protocol name in protocol column
    pinfo.cols.protocol = red.name

在这里插入图片描述

  • 如上图所示,我们就可以将协议名称修改为RED。
3.5 DissectorTable
  • 表示一个具体协议的解析表,比如,协议TCP的解析表”tcp.port”包括http,smtp,ftp等。可以依次点击wireshark菜单“Internals”、“Dissector tables”,来查看当前的所有解析表。如下图,我们选择 rtp.pt解析表在“Integer tables”选项卡中,顾名思义,它是通过类型为整型的 rtp 端口号来识别下游协议的:
    基于Lua语言的wireshark插件编写_第4张图片
  • DissectorTable的主要接口有:
  • 接口说明
接口 说明
DissectorTable.get(name) get名为name的解析表的引用
dissectortable:add(pattern, dissector) 将Proto或Dissector对象添加到解析表,即注册。pattern可以是整型值,整型值范围或字符串,这取决于当前解析表的类型
dissectortable:remove(pattern, dissector) 将满足pattern的一个或一组Proto、Dissector对象从解析表中删除

四、代码框架

-- create a new dissector
local NAME = "red"
local PORT = 5004
local red = Proto(NAME, "Red Protocol")


-- dissect packet
function red.dissector (tvb, pinfo, tree)
end

-- register this dissector
DissectorTable.get("udp.port"):add(PORT, red)
  • 如上图,就是整体的三部分式的代码框架,首先需要定义一个新协议,就是给这个新协议起一个新的名字。
  • 接下来,就是对这个新协议进行解析,在 red.dissector 这个函数中写我们解析这种包的逻辑。
  • 最后就是将这个新协议添加到 udp 这个已有协议的的底下,用端口号进行区分。基于Lua语言的wireshark插件编写_第5张图片

五、完善代码

local version_str = string.match(_VERSION, "%d+[.]%d*")
local version_num = version_str and tonumber(version_str) or 5.1
local bit = (version_num >= 5.2) and require("bit32") or require("bit")

-- create a new dissector to decode rtp private payload
local NAME1          = "red"
local PORT           = 5004
local RTP_PROTO_TYPE = 106


local red            = Proto(NAME1, "Red Protocol")

-- create fields of red
fields_M             = ProtoField.uint8 (NAME1 .. ".M", "M", base.HEX,Payload_type,0x80)
fields_pt            = ProtoField.uint8 (NAME1 .. ".PT", "PT", base.DEC,Payload_type,0x7F)
fields_seqno         = ProtoField.uint16(NAME1 .. ".seqno", "Sequence number")
fields_h264bytes     = ProtoField.bytes(NAME1 .. ".bytes", "H264Data")
fields_fec           = ProtoField.bytes(NAME1 .. ".fec", "FEC Payload")

red.fields           = { fields_M, fields_pt, fields_seqno, fields_h264bytes,fields_fec }

local RTP_dis        = Dissector.get("rtp")
local H264_dis       = Dissector.get("h264")
local Data_dis       = Dissector.get("data")


-- dissect packet
function red.dissector(tvb, pinfo, tree)
	length = tvb:len()
	if length == 0 then return end
    -- decode private header
    local subtree = tree:add(red, tvb(0,3))
	subtree:add(fields_M, tvb(0,1))
	subtree:add(fields_pt, tvb(0,1))
    subtree:add(fields_seqno, tvb(1,2))

    -- show protocol name in protocol column
    pinfo.cols.protocol = red.name
   	
	local fec_id = tvb(0,1):uint()
	local fec_type = bit.band(fec_id,0x7F)
	if fec_type == 109 then 
		tree:add(fields_fec,tvb(3))
	else 
		H264_dis:call(tvb(3):tvb(), pinfo, tree)
	end 
end


--decode first layer  as rtp
local udp_dissector_table = DissectorTable.get("udp.port")
udp_dissector_table:set(PORT,RTP_dis)

-- register this dissector
-- DissectorTable.get("rtp.pt"):add(PORT, red)
--decode private protocol layer  3-bytes private datas + standard h264
local rtp_dissector_table = DissectorTable.get("rtp.pt")
rtp_dissector_table:set(RTP_PROTO_TYPE,red)
  • 如上的代码就是扩展代码框架来正确达成我的目的的。
  • 我们可以根据不同的需求编写不同的解析代码。

六、加载到wireshark中

  • 将Lua文件保存到wireshark的根目录下。比如:基于Lua语言的wireshark插件编写_第6张图片
  • 然后在 wireshark 的根目录下找到 “init.lua” 文件。 打开它,使用记事本或者notepad++或者其他软件都可以。在这个文件的开头修改”enable_lua = true“,请参考这段代码上面的注释,不同版本可能不一样。
    基于Lua语言的wireshark插件编写_第7张图片
  • 接下来在这个文件”init.lua“ 的最后将我们增加到wireshark根目录的Lua文件添加。如下图:基于Lua语言的wireshark插件编写_第8张图片
  • 这个时候Lua文件就已经被嵌入到wireshark中了,有两种启动Lua插件的办法,要么就是重启wireshark,要么就是在wireshark的”分析“菜单下点击“重新载入Lua插件”。基于Lua语言的wireshark插件编写_第9张图片

七、后记

  • 我的整体代码放在我githup上了,链接:https://github.com/zhangyi-13572252156/Wireshark-Plug-In
  • 如果需要交流,欢迎交流。QQ:1251108673

你可能感兴趣的:(脚本语言,wireshark插件,lua)