使用lua作为wireshark的私有协议解析插件

--定义协议(第一个参数体现在过滤器中,第二个参数描述信息)
local hss_proto=Proto("Hss","Hss Protocol")

--定义字段(第一个参数为过滤条件,第二个参数为Tree列表中显示的名字,
--后面可以指定不同的进制显示方式:HEX为16进制,DEC为10进制)
--uint8,uint16,uint24,uint32分别表示1,2,3,4字节,即该字段的长度
local hss_proto_mark=ProtoField.uint16("hssMark","Mark",base.HEX,{[0x135d]="hss"})
local hss_proto_name=ProtoField.uint8("hssName","Name",base.HEX)
local hss_proto_version=ProtoField.uint8("hssVersion","Version",base.HEX)
local hss_proto_code=ProtoField.uint16("hssCode","Code",base.HEX,
						{
							[0x1B00]="JS_HSS_REGISTER_REQ",
							[0x1B01]="JS_HSS_REGISTER_ACK",
							[0X1B02]="JS_HSS_QUERY_REQ",
							[0X1B03]="JS_HSS_QUERY_ACK",
							[0X1B04]="JS_HSS_UNREGISTER_REQ",
							[0X1B05]="JS_HSS_UNREGISTER _ACK"
						}
					 )
local hss_proto_length=ProtoField.uint16("hssLength","Length",base.DEC)

local hss_proto_data=ProtoField.bytes("hssData","Data",base.NONE)
local data_tag=ProtoField.uint16("data_tag","Tag",base.HEX,
						{
							[0x1C00]="HANDLE",
							[0x1C01]="MSISDN",
							[0x1C02]="IMSI",
							[0x1C03]="IMEI",
							[0x1C04]="GWNAME",
							[0x1C05]="DOMAIN",
							[0x1C06]="EXPRIES",
							[0x1C07]="RESULT",
							[0x1C08]="ROUTER"
						}
					)
local data_length=ProtoField.uint16("data_length","Length",base.DEC)
local data_value_number=ProtoField.uint32("data_value_number","Value",base.DEC)
local data_value_string=ProtoField.string("data_value_string","Value")

--添加字段
hss_proto.fields={
	hss_proto_mark,
	hss_proto_name,
	hss_proto_version,
	hss_proto_code,
	hss_proto_length,
	hss_proto_data,
	data_tag,
	data_length,
	data_value_number,
	data_value_string
}


--buffer为数据流,pinfo为协议解析树上的信息,包括UI上的显示
function hss_proto.dissector(buffer,pinfo,tree)

	offset = pinfo.desegment_offset or 0
	--当前数据流长度
	local buffer_len=buffer:len()
	--该协议头部长度为8
	local hssheadlength=8
	local item=0

while true do
	item=item+1

 	if offset==buffer_len then
 		return
 	end

	--判断如果剩下的数据不到hssheadlength,即proto_length取不出来,就把pinfo.desegment_len返回
	--DESEGMENT_ONE_MORE_SEGMENT表示不知道后面传进来的数据有多少
	if offset+hssheadlength>buffer_len then
		pinfo.desegment_offset=offset
		pinfo.desegment_len=DESEGMENT_ONE_MORE_SEGMENT
		return pinfo.desegment_len
	end

	local proto_length=buffer(offset+6,2):le_uint()

	--剩下的数据能够取到hssheadlength的长度,判断剩下的数据能否够一条消息的长度,
	--如果不够也返回pinfo.desegment_len
	if offset+hssheadlength+proto_length>buffer_len then
		pinfo.desegment_len=DESEGMENT_ONE_MORE_SEGMENT
		pinfo.desegment_offset=offset
		return pinfo.desegment_len
	end

	--ui层显示hss
	pinfo.cols.protocol:set("hss")
	--ui上添加信息,源端口和目标端口
	pinfo.cols.info:set("hss protocol"..pinfo.src_port.."->"..pinfo.dst_port)

	--解析树上添加协议,取前8个字节(head头部信息),显示为Hss Protocol。
  	local hssProtoTree=tree:add(hss_proto,buffer(offset,hssheadlength+proto_length),"Hss Protocol")
	--解析树上添加信息,源端口和目标端口
	hssProtoTree:append_text(",Src Port:"..pinfo.src_port..",Dst Port:"..pinfo.dst_port.."->".."item:"..item)
	--添加字段到解析树上
 	hssProtoTree:add(hss_proto_mark,buffer(offset,2))
	offset=offset+2
 	hssProtoTree:add(hss_proto_name,buffer(offset,1))
	offset=offset+1
 	hssProtoTree:add(hss_proto_version,buffer(offset,1))
	offset=offset+1
 	hssProtoTree:add(hss_proto_code,buffer(offset,2))
	offset=offset+2
	--le:uint()表示按小字节序将buffer(offset,2)的数据转换成无符号整数,uint()表示按照正常字节序转换
	hssProtoTree:add(hss_proto_length,buffer(offset,2):le_uint())
	offset=offset+2
	doLength=offset-offset

	--head解析完后,获取tlv格式的数据,并添加节点到树上
 	local hss_data=hssProtoTree:add(hss_proto_data,buffer(offset,proto_length))
	--message()为调试函数,可以打印输出信息,可以在wireshark工具栏中,打开工具-lua-console,然后双击该协议,就会出现打印的信息
	--message(buffer(offset,2))

	--循环解析tlv格式的数据,doLength表示已解析的tlv数据长度
	while proto_length>doLength do
		--获取tag的值,为后面作判断使用
 		local data_tag_v=buffer(offset,2):uint()
		hss_data:add(data_tag,buffer(offset,2))
		offset=offset+2
		doLength=doLength+2
		local value_length=buffer(offset,2):le_uint()
		hss_data:add(data_length,buffer(offset,2):le_uint())
		offset=offset+2
		doLength=doLength+2
		--判断tag的类型,number类型和string类型分别处理,number为4字节固定,string不固定
		if data_tag_v==0x1c00  or
		   data_tag_v==0x1c05  or
		   data_tag_v==0x1c06  or
		   data_tag_v==0x1c07  or
		   data_tag_v==0x1c08
		then
			hss_data:add(data_value_number,buffer(offset,value_length):le_uint())
		else
			hss_data:add(data_value_string,buffer(offset,value_length))
 		end
		offset=offset+value_length
		doLength=doLength+value_length
	end
end
end

--向wireshark注册协议插件被调用的条件
local tcp_port_table=DissectorTable.get("tcp.port")
tcp_port_table:add(14983,hss_proto)







 

 

  1. 创建*.lua的文件,此文件就是放入wireshark的插件。将该文件存放至wireshark目录下的plugins目录下版本号文件夹下
  2. 开始写插件

(1).定义新的协议(Proto主要用途是声明一个新的协议,括号中第一个参数体现在过滤 器中,第二个参数描述信息)

举例:

local hss_proto=Proto("Hss","Hss Protocol")

 

(2).定义字段

(第一个参数为过滤条件,第二个参数为Tree列表中显示的名字,

后面可以指定不同的进制显示方式:HEX为16进制,DEC为10进制

uint8,uint16,uint24,uint32,分别表示1,2,3,4字节,即该字段的长度

bytes表示该字段的字节有哪些,string表示该字段用字符串表示,

后面还可以显示指定特定字节所表示的含义)

举例:

Local hss_proto_mark=ProtoField.uint16("hssMark","Mark",base.HEX,

{[0x5d13]="hss",[0x135d]="hss"})

local hss_proto_name=ProtoField.uint8("hssName","Name",base.HEX)

local hss_proto_data=ProtoField.bytes("hssData","Data",base.NONE)

local data_value_string=ProtoField.string("data_value_string","Value")

    

(3).将字段添加到定义好的协议中,不然无法添加到解析树上

hss_proto.fields={

hss_proto_mark,

hss_proto_name,

hss_proto_version,

hss_proto_code,

hss_proto_length,

hss_proto_data,

data_tag,

data_length,

data_value_number,

data_value_string

}

 

 

      (4).创建解析器

function hss_proto.dissector(buffer,pinfo.tree)

在方法里面写具体的解析过程

(参数含义:buffer为数据流,pinfo为协议解析树上的信息和UI层上的显示,tree 为协议解析树,将我们定义好的字段添加到树上)

end

具体解析过程:

Hss模块(mark,name,version,code,length,value),由于数据发送过来的长度不确定,解析需循环处理

1.获取buffer数据流长度:local buffer_len=buffer:len()

          定义一个变量offset,表示指针位置

2.往解析树上添加协议,取前8个字节(head头部信息),显示为Hss Protocol

local hssProtoTree=tree:add(hss_proto,buffer(offset,8+proto_length),"Hss Protocol")

3.添加字段到解析树上

hssProtoTree:add(hss_proto_mark,buffer(offset,2))

offset=offset+2

  hssProtoTree:add(hss_proto_name,buffer(offset,1))

offset=offset+1

  hssProtoTree:add(hss_proto_version,buffer(offset,1))

offset=offset+1

  hssProtoTree:add(hss_proto_code,buffer(offset,2))

offset=offset+2

hssProtoTree:add(hss_proto_length,buffer(offset,2):le_uint())

offset=offset+2

le:uint()表示按小字节序将buffer(offset,2)的数据转换成无符号整数

4.head头部解析完后,获取tlv格式的value数据,并添加到节点树上

local hss_data=hssProtoTree:add(hss_proto_data,buffer(offset,proto_length))

doLength=0

5.循环解析tlv格式的数据,doLength表示已解析的当条消息的tlv数据长度

while proto_length>doLength do

  local data_tag_v=buffer(offset,2):le_uint()

hss_data:add(data_tag,buffer(offset,2))

offset=offset+2

doLength=doLength+2

local value_length=buffer(offset,2):le_uint()

hss_data:add(data_length,buffer(offset,2):le_uint())

offset=offset+2

doLength=doLength+2

--判断tag的类型,number类型和string类型分别处理,number为4字节固定,string不固定

if data_tag_v==28    or

   data_tag_v==1308  or

   data_tag_v==1564  or

   data_tag_v==1820  or

   data_tag_v==2076

then

hss_data:add(data_value_number,buffer(offset,value_length):le_uint())

else

hss_data:add(data_value_string,buffer(offset,value_length))

  end

offset=offset+value_length

doLength=doLength+value_length

end

3.向wireshark注册协议插件被调用的条件

local tcp_port_table=DissectorTable.get("tcp.port")

tcp_port_table:add(14983,hss_proto)

 

4.至此,整条的协议能循环解析出来,后面处理0.5条之类的数据

 pinfo有两个属性pinfo.desegment_len,和pinfo.desegment_offset,分别表示后面的数据长度和已解析的标志位,当遇到含有1.3条之类的数据的时候,取出后面的0.3条,放入下一条的头部,在解析器中体现在返回值上(DESEGMENT_ONE_MORE_SEGMENtT表示不知道后面数据的长度),用一个判断语句去表示

if offset+8+proto_length>buffer_len then

pinfo.desegment_len=DESEGMENT_ONE_MORE_SEGMENT  pinfo.desegment_offset=offset

return pinfo.desegment_len

end

 

5.lua解析器会自动把前一条未解析的数据和当条数据合并后再解析

 

  1. 不同的lua协议解析插件有不同的默认端口,比如该hss协议解析器的默认端口为14983,如果服务端的程序不是14983端口,假如端口号为14000,此时需要在wireshark中重新设置下,在菜单栏的:分析--解码为(Decode As),添加一条信息,字段为Tcp port,端口号为此时通信双方的端口号14000,当前设置为该hss协议,添加好后,保存即可,此时就能解析hss协议的数据了。(如图所示)

(1)使用lua作为wireshark的私有协议解析插件_第1张图片

 

(2)

使用lua作为wireshark的私有协议解析插件_第2张图片

(3)

使用lua作为wireshark的私有协议解析插件_第3张图片

  1. save保存之后,指定14000端口,就会显示hss协议

使用lua作为wireshark的私有协议解析插件_第4张图片

解析出来的hss协议如图所示:

使用lua作为wireshark的私有协议解析插件_第5张图片

你可能感兴趣的:(使用lua作为wireshark的私有协议解析插件)