1 月
10
众所周知Wireshark是分析网络协议不可或缺的工具之一,Wireshark为我们提供了很多的协议支持,如果我们有自定义的协议需要分析,则可以通过自己用Lua写插件来解析。Lua是一个小巧的脚本语言,是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组(由Roberto Ierusalimschy、Waldemar Celes 和Luiz Henrique de Figueiredo所组成)于1993年开发。Wireshark默认提供了对Lua的支持,我们可以很方便地调用Wireshark提供的API来解析网络协议。
下面我通过一个简单的例子来说明一下写插件的方法和步骤。
— 协议格式:
—- 文件名称:mypro.lua —–
do
——————————————–
—
— Version: v1.0
— Author: bryan.whp 2012-11-27
— Description: Analyze My Proprietary Protocol Interface v1.0 package
—
——————————————–
— Create a new dissector
local my_proto = Proto ("mypro","My Proprietary Protocol Interface v1.0")
local f = my_proto.fields
— Create the protocol fields
local pkeys = {
[0x01] = "publish",
[0x02] = "unpublish",
}
local tlvtypes = {
[1] = "uint",
[2] = "string",
[3] = "tlv",
}
— 定义状态码对应的含义,Wireshark会自动将该值转为相应的字符串。
local tagNames = {
[1] = "nid",
[2] = "nna",
[3] = "node",
}
f.f_Header = ProtoField.bytes("mypro.header","Message Header")
f.f_Headerpkey = ProtoField.uint8("mypro.pkey", "pkey", base.HEX, pkeys)
f.f_Headernid = ProtoField.uint8("mypro.nid", "nid", base.DEC)
f.f_HeaderLength = ProtoField.uint16("mypro.length", "Length", base.DEC)
f.f_HeaderReserve = ProtoField.uint16("mypro.reserve", "Reserve", base.DEC)
f.f_HeaderSeq = ProtoField.uint16("mypro.seq","Seq", base.DEC)
f.f_Headeradrressa = ProtoField.uint32("mypro.adrressa","adrressa", base.DEC)
f.f_Headeradrressb = ProtoField.uint32("mypro.adrressb","adrressb", base.DEC)
f.f_HeaderTLVs = ProtoField.bytes("mypro.tlvs","Message TLVs")
f.f_TLV = ProtoField.bytes("mypro.tlv","TLV")
f.f_TlvTag = ProtoField.uint8("mypro.tag","TagNum", base.DEC)
f.f_TlvLength = ProtoField.uint8("mypro.taglength","Length", base.DEC)
f.f_TlvLongLength = ProtoField.uint16("mypro.taglonglength","Length", base.DEC)
f.f_TlvBody = ProtoField.bytes("mypro.value", "Value")
f.f_TlvUintBody = ProtoField.uint32("mypro.value", "Value", base.DEC)
f.f_TlvUlongBody = ProtoField.uint64("mypro.value", "Value", base.DEC)
f.f_TlvStringBody = ProtoField.string("mypro.value", "Value")
f.f_TlvByteBody = ProtoField.uint8("mypro.value", "Value", base.DEC)
— RTP package Dissector
local rtp_dissector = Dissector.get("rtp")
——————————————–
—
— Main function
—
——————————————–
— add tlv
function tlv_bundle(subtree, tagNum, tagLength, tagValue, subbuffer)
local tagNum_int = tagNum:uint()
local tlv_tree = subtree:add_le(f.f_TLV, subbuffer)
if tlvtypes[tagNum_int] ~= "tlv" then
tlv_tree:add(f.f_TlvTag, tagNum)
local tagLengthDec = subbuffer(1,2):uint()
if tagLengthDec > 127 then
tlv_tree:add(f.f_TlvLongLength, tagLength)
else
tlv_tree:add(f.f_TlvLength, tagLength)
end
if tlvtypes[tagNum_int] == "ulong" then
tlv_tree:add(f.f_TlvUlongBody, tagValue)
tagValue = tagValue:uint64()
elseif tlvtypes[tagNum_int] == "string" then
tlv_tree:add(f.f_TlvStringBody, tagValue)
tagValue = tagValue:string()
elseif tlvtypes[tagNum_int] == "uint" then
tlv_tree:add(f.f_TlvUintBody, tagValue)
tagValue = tagValue:uint()
elseif tlvtypes[tagNum_int] == "byte" then
tlv_tree:add(f.f_TlvByteBody, tagValue)
tagValue = tagValue:uint()
else
tlv_tree:add(f.f_TlvBody, tagValue)
end
tlv_tree:set_text(tagNames[tagNum_int]..": "..tagValue)
else
tlv_bundles(tagValue, tlv_tree)
tlv_tree:set_text(tagNames[tagNum_int]..": TLVs")
end
end
— add tlvs
function tlv_bundles(buffer, subtree)
local tagNum = 0
local tagLength = 0
local tagValue = 0
local offset = 0
local buffter_len = buffer:len()
local tlv_tree = subtree:add(f.f_HeaderTLVs)
tlv_tree:set_text("Message TLVs")
while offset < buffter_len do
tagNum = buffer(offset,1)
tagLength = buffer(offset+1,1)
local tagLengthDec = tagLength:uint()
if tagLengthDec > 127 then
tagLength = buffer(offset+1,2)
tagLengthDec = tagLength:uint() – 32768
tagLength = tagLength:bitfield(1,15)
inc = 3
else
tagLength = buffer(offset+1,1)
tagLengthDec = tagLength:uint()
inc = 2
end
— tlv_tree:set_text(offset..":"..inc..":"..tagLengthDec..":"..buffer)
tagValue = buffer(offset+inc, tagLengthDec)
tlv_bundle(tlv_tree, tagNum, tagLength, tagValue, buffer(offset, inc+tagLengthDec))
offset = offset + inc + tagLengthDec
end
end
— 解析函数,这里就是解析消息包内容的过程
— add header and body
function my_proto.dissector(buffer, pinfo, tree)
— 在主窗口的Protocol 字段显示的名称为“Mypro”
— 在主窗口的Protocol 字段显示的名称为“Mypro”
pinfo.cols.protocol:set("Mypro")
local offset = 0
local pkey = buffer(offset,1)
local IsmyPPI = 0 — not My PPI V4.0 default
local key
local value
for key,value in pairs(pkeys) do
if pkey:uint() == key then
IsmyPPI = 1
end
end
if IsmyPPI == 0 then
return false
end
— 增加一个子项目到Packet Details窗口
local buffer_len = buffer:len()
local my_proto_tree = tree:add(my_proto, buffer(0, buffer_len), "My Proprietary protocol interface v1.0")
local header_tree = my_proto_tree:add(f.f_Header)
header_tree:set_text("Message Header (p_key: 0x"..pkey..")")
header_tree:add(f.f_Headerpkey, pkey)
— 提取1个字节,该字节代表的是id。
offset = offset + 1
header_tree:add(f.f_Headernid, buffer(offset,1))
offset = offset + 1
header_tree:add(f.f_HeaderLength, buffer(offset,2))
offset = offset + 2
header_tree:add(f.f_HeaderReserve, buffer(offset,2))
offset = offset + 2
header_tree:add(f.f_HeaderSeq, buffer(offset,2))
offset = offset + 2
local adrressa = buffer(offset,4):uint()
header_tree:add(f.f_Headeradrressa, buffer(offset,4))
offset = offset + 4
header_tree:add(f.f_Headeradrressb, buffer(offset,4))
— BODY: AMR: p_key == 0x0d TLVs: others
offset = offset + 4
local tlvsstream = buffer(offset, (buffer_len-16))
if buffer_len ~= 16 then
if pkey:uint() ~= 96 then
tlv_bundles(tlvsstream, my_proto_tree)
else
— Body is rtp message
rtp_dissector:call(tlvsstream:tvb(), pinfo, header_tree)
end
end
pinfo.cols.info:set(pkeys[pkey:uint()].." (0x"..pkey.."), adrressa: "..adrressa)
return True
end
— 将该解析器应用于61020号端口。因该协议使用的是61020号端口,采用UDP协议传输
— 这就意味着通过61020号端口的UDP将由这个解析器来分析
local my_port = 61020
— UDP package
local udp_port_table = DissectorTable.get("udp.port")
udp_port_table:add(my_port, my_proto)
end
—- 文件:mypro.lua 完毕—-
用法:
将mypro.lua放入wireshark根目录下,同时在根目录下的init.lua文件末尾添加 dofile(DATA_DIR.."mypro.lua")
重启wireshark即可
解析结果如下:
你好,我在用SciTE调试的时候第一句总是报错attempt to call global ‘Proto’ (a nil value),单独编译运行这一句话也是这样,想请教一下你是用什么调试的
你好,我把你的源码复制了一份,可是wireshark提示出错,你能把你当时写的源码发我邮箱一份吗,不甚感激。
已经QQ交流