在ICT(ICT,information and communications technology)人员用于网络分析的兵器库中,wireshark无疑是倚天剑,虽历史悠久,其锋利程度丝毫不减,由于开源,便于用户二次开发,这就使得此剑的颜值、功能都近乎完美。如果能够熟练的使用此剑,对于行走江湖也是百利而无一害。
对于当下的主流协议wireshark都有自带解析插件,如IP、ARP、TCP、UDP、HTTP、DHCP等。但是实际应用中,这些协议通常只是我们传输数据过程的载体,有不少软件之间的通信协议都是私有的,如游戏客户端和服务器之间的交互协议通常都是私有的,Wireshark无法具体解析出各种字段之间的含义,只能显示接收到的二进制数据,给协议的分析和问题的排查带来了一定的困难,尤其是协议内容比较复杂时。
通过wireshark可以知道每一个字段的内容,但如果消息结构复杂,需要计算偏移方可获取到指定字段值;再者,如果消息结构中含有位域字段则更加复杂,伤眼睛;最后,无法使用消息字段中的指定字段进行报文过滤操作。基于以上几点原因,为了帮助分析,编写插件脚本分析势在必行。本文从一个自定义的简单消息协议入手,分析如何通过Lua语言来编写Wireshark插件来解析自定义消息。
-- Tetra NM_Agnet message protocol Lua script
-- 3273070@qq.com
-- V1.0
-- 2020.06.08 10:34:16
-- create dissector message object
local tetra_fls_message_name = "Tetra_NM_Agent"
local tetra_fls_message_brief = "Dissector all message for Tetra NM Agent"
local tetra_fls_proto = Proto(tetra_fls_message_name, tetra_fls_message_brief)
--[[
local tetra_fls_proto_msg_id = ProtoField.uint8("msg_id","msg id",base.HEX,
{
[0xB1]="HELLO",
[0xB2]="TX_CONTROL",
[0XB3]="CELL_CONFIGURE",
[0XB4]="FLS_ALARM_REPORT",
[0XB5]="STILL-ALIVE",
[0XB7]="FLS-RESET",
[0xB8]="DSP_CLOSE",
[0xB9]="RRU_VERSION_UPGRADE",
[0xBA]="RRU_VERSION_REPORT/QUERY",
[0xBB]="RRU_VERSION_ACTIVE",
[0xBC]="RRU_ALARM_REPORT",
[0xBD]="CELL_DELETE"
}
)
--]]
local tetra_fls_proto_msg_id = ProtoField.uint8("msg_id","msg id",base.HEX)
local tetra_fls_proto_msg_length = ProtoField.uint32("msg_len","msg len",base.DEC)
local tetra_fls_proto_msg_crc = ProtoField.uint32("msg_crc","msg crc",base.HEX)
local tetra_fls_proto_msg_body = ProtoField.bytes("msg_body","msg body")
local tetra_fls_proto_hello_ver = ProtoField.uint8("version","version",base.HEX)
local tetra_fls_proto_hello_controller_identifier = ProtoField.uint8("controller_id","controller id",base.HEX)
local tetra_fls_proto_hello_session_identifier = ProtoField.uint8("session_id","session id",base.HEX)
local tetra_fls_proto_hello_still_alive = ProtoField.uint8("still_alive","still alive",base.HEX)
local tetra_fls_proto_hello_ack_status = ProtoField.uint8("dsp_status","dsp status",base.HEX)
local tetra_fls_proto_hello_ack_mem = ProtoField.uint32("share_memory","share memory",base.HEX)
local tetra_fls_proto_rru_upgrade_sw_path = ProtoField.string("rru_upgrade_sw_path","rru upgrade sw path")
local tetra_fls_proto_rru_upgrade_sw_name = ProtoField.string("rru_upgrade_sw_name","rru upgrade sw name")
local tetra_fls_proto_rru_upgrade_fw_path = ProtoField.string("rru_upgrade_fw_path","rru upgrade fw path")
local tetra_fls_proto_rru_upgrade_fw_name = ProtoField.string("rru_upgrade_fw_name","rru upgrade fw name")
local tetra_fls_proto_rru_upgrade_ack = ProtoField.uint8("rru_upgrade_ack","rru upgrade ack",base.HEX)
local tetra_fls_proto_rru_query = ProtoField.uint32("rru_query","rru query",base.HEX)
local tetra_fls_proto_rru_query_ack_sw = ProtoField.string("rru_upgrade_ack_sw_name","rru upgrade ack sw")
local tetra_fls_proto_rru_query_ack_fw = ProtoField.string("rru_upgrade_ack_fw_name","rru upgrade ack fw")
local tetra_fls_proto_rru_active_sw = ProtoField.string("rru_upgrade_active_sw_name","rru upgrade active sw")
local tetra_fls_proto_rru_active_fw = ProtoField.string("rru_upgrade_active_fw_name","rru upgrade active fw")
local tetra_fls_proto_rru_active_ack = ProtoField.uint8("rru_upgrade_active_ack","rru upgrade active ack",base.HEX)
local tetra_fls_proto_rru_alarm_valid = ProtoField.uint16("rru_alarm_valid","rru alarm valid",base.HEX)
local tetra_fls_proto_rru_alarm_code = ProtoField.uint32("rru_alarm_code","rru alarm code",base.HEX)
local tetra_fls_proto_rru_alarm_sucode = ProtoField.uint32("rru_alarm_sucode","rru alarm sucode",base.HEX)
local tetra_fls_proto_rru_alarm_clear_flag = ProtoField.uint32("rru_alarm_clear_flag","rru alarm clear flag",base.HEX)
local tetra_fls_proto_rru_alarm_timestamp = ProtoField.string("rru_alarm_timestamp","rru alarm timestamp")
local tetra_fls_proto_rru_alarm_additional = ProtoField.string("rru_alarm_additional","rru alarm additional")
local tetra_fls_proto_cell_delete = ProtoField.uint32("cell_delete","cell delete",base.HEX)
local tetra_fls_proto_cell_delete_ack = ProtoField.uint8("cell_delete_ack","cell delete ack",base.HEX)
tetra_fls_proto.fields = {
tetra_fls_proto_msg_id,
tetra_fls_proto_msg_length,
tetra_fls_proto_msg_crc,
tetra_fls_proto_msg_body,
tetra_fls_proto_hello_ver,
tetra_fls_proto_hello_controller_identifier,
tetra_fls_proto_hello_session_identifier,
tetra_fls_proto_hello_still_alive,
tetra_fls_proto_hello_ack_status,
tetra_fls_proto_hello_ack_mem,
tetra_fls_proto_rru_upgrade_sw_path,
tetra_fls_proto_rru_upgrade_sw_name,
tetra_fls_proto_rru_upgrade_fw_path,
tetra_fls_proto_rru_upgrade_fw_name,
tetra_fls_proto_rru_upgrade_ack,
tetra_fls_proto_rru_query,
tetra_fls_proto_rru_query_ack_sw,
tetra_fls_proto_rru_query_ack_fw,
tetra_fls_proto_rru_active_sw,
tetra_fls_proto_rru_active_fw,
tetra_fls_proto_rru_active_ack,
tetra_fls_proto_rru_alarm_valid,
tetra_fls_proto_rru_alarm_code,
tetra_fls_proto_rru_alarm_sucode,
tetra_fls_proto_rru_alarm_clear_flag,
tetra_fls_proto_rru_alarm_timestamp,
tetra_fls_proto_rru_alarm_additional,
tetra_fls_proto_cell_delete,
tetra_fls_proto_cell_delete_ack
}
------------------------------------------------ message table --------------------------------------------------
local colomn_message = {
[0xB1] = "HELLO",
[0xB2] = "TX_CONTROL",
[0xB3] = "CELL_CONFIGURE",
[0xB4] = "FLS_ALARM_REPORT",
[0xB5] = "STILL_ALIVE",
[0xB6] = "RESERVED",
[0xB7] = "FLS_RESET",
[0xB8] = "DSP_CLOSE",
[0xB9] = "RRU_VERSION_UPGRADE",
[0xBA] = "RRU_VERSION_REPORT/QUERY",
[0xBB] = "RRU_VERSION_ACTIVE",
[0xBC] = "RRU_ALARM_REPORT",
[0xBD] = "CELL_DELETE",
}
function tetra_fls_proto.dissector(buffer,pinfo,tree)
pinfo.cols.protocol:set("Tetra NM Agent message")
pinfo.cols.info:set("Tetra NM Agent proto")
local buffer_total_len = buffer:len()
local buffer_tree = tree:add(tetra_fls_proto, buffer:range(buffer_total_len))
local buffer_header_len = 12
local buffer_body_len = buffer_total_len - buffer_header_len
local offset = 0
buffer_tree:add(tetra_fls_proto_msg_length, buffer(offset, 4))
local msg_len = buffer(offset,4):uint()
offset = offset + 4
buffer_tree:add(tetra_fls_proto_msg_id, buffer(offset, 1))
local msg_id = buffer(offset, 1):uint()
offset = offset + 1
--buffer_tree:add(tetra_fls_proto_msg_id, buffer(offset, 1))
offset = offset + 1
--buffer_tree:add(tetra_fls_proto_msg_id, buffer(offset, 1))
offset = offset + 1
--buffer_tree:add(tetra_fls_proto_msg_id, buffer(offset, 1))
offset = offset + 1
buffer_tree:add(tetra_fls_proto_msg_crc, buffer(offset, 4))
offset = offset + 4
local tetra_nm_msg_body = buffer_tree:add(tetra_fls_proto_msg_body, buffer(offset, buffer_total_len - offset))
local body_0 = buffer(offset, 1):uint()
local nm_msg = "#NM_Agent_MSG#".." ".."APP <-> FLS".." "
local nm_msg_to_fls = "#NM_Agent_MSG#".." ".."APP -> FLS".." "
local nm_msg_to_app = "#NM_Agent_MSG#".." ".."FLS -> APP".." "
if (msg_id == 0xB1) then
if (buffer_body_len == 4) then
tetra_nm_msg_body:add(tetra_fls_proto_hello_ver, buffer(offset, 1))
offset = offset + 1
tetra_nm_msg_body:add(tetra_fls_proto_hello_controller_identifier, buffer(offset, 1))
offset = offset + 1
tetra_nm_msg_body:add(tetra_fls_proto_hello_session_identifier, buffer(offset, 1))
offset = offset + 1
tetra_nm_msg_body:add(tetra_fls_proto_hello_still_alive, buffer(offset, 1))
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
elseif (buffer_body_len == 12) then
offset = offset + 3
tetra_nm_msg_body:add(tetra_fls_proto_hello_ack_status, buffer(offset, 1))
offset = offset + 1
tetra_nm_msg_body:add(tetra_fls_proto_hello_ack_mem, buffer(offset, 4))
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xB3) then
if (buffer_body_len == 19) then
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
elseif (buffer_body_len == 4) then
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xB4) then
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id])
elseif (msg_id == 0xB5) then
if (body_0 == 0xff) then
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
elseif (body_0 <= 2) then
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xB9) then
if (buffer_body_len == 432) then
tetra_nm_msg_body:add(tetra_fls_proto_rru_upgrade_sw_path, buffer(offset, 200))
offset = offset + 200
tetra_nm_msg_body:add(tetra_fls_proto_rru_upgrade_sw_name, buffer(offset, 16))
offset = offset + 16
tetra_nm_msg_body:add(tetra_fls_proto_rru_upgrade_fw_path, buffer(offset, 200))
offset = offset + 200
tetra_nm_msg_body:add(tetra_fls_proto_rru_upgrade_fw_name, buffer(offset, 16))
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
elseif (buffer_body_len == 4) then
tetra_nm_msg_body:add(tetra_fls_proto_rru_upgrade_ack, buffer(offset, 1))
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xBA) then
if (buffer_body_len == 4) then
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
elseif (buffer_body_len == 80) then
tetra_nm_msg_body:add(tetra_fls_proto_rru_query_ack_sw, buffer(offset, 40))
offset = offset + 40
tetra_nm_msg_body:add(tetra_fls_proto_rru_query_ack_fw, buffer(offset, 40))
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xBB) then
if (buffer_body_len == 80) then
tetra_nm_msg_body:add(tetra_fls_proto_rru_active_sw, buffer(offset, 40))
offset = offset + 40
tetra_nm_msg_body:add(tetra_fls_proto_rru_active_fw, buffer(offset, 40))
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
elseif (buffer_body_len == 1) then
tetra_nm_msg_body:add(tetra_fls_proto_rru_active_ack, buffer(offset, 1))
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xBD) then
if (buffer_body_len == 4) then
pinfo.cols.info:set(nm_msg_to_fls..colomn_message[msg_id])
elseif (buffer_body_len == 1) then
tetra_nm_msg_body:add(tetra_fls_proto_cell_delete_ack, buffer(offset, 1))
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id].."_ACK")
else
pinfo.cols.info:set("#ERROR# unknown message")
end
elseif (msg_id == 0xBC) then
tetra_nm_msg_body:add(tetra_fls_proto_rru_alarm_valid, buffer(offset, 2))
offset = offset + 2
tetra_nm_msg_body:add(tetra_fls_proto_rru_alarm_code, buffer(offset, 4))
offset = offset + 4
tetra_nm_msg_body:add(tetra_fls_proto_rru_alarm_sucode, buffer(offset, 4))
offset = offset + 4
tetra_nm_msg_body:add(tetra_fls_proto_rru_alarm_clear_flag, buffer(offset, 4))
offset = offset + 4
tetra_nm_msg_body:add(tetra_fls_proto_rru_alarm_timestamp, buffer(offset, 20))
offset = offset + 20
tetra_nm_msg_body:add(tetra_fls_proto_rru_alarm_additional, buffer(offset, 20))
pinfo.cols.info:set(nm_msg_to_app..colomn_message[msg_id])
else
pinfo.cols.info:set(nm_msg..colomn_message[msg_id])
end
end
-- register for wireahark
local udp_port_table = DissectorTable.get("udp.port")
-- bind udp port
for i,port in ipairs{5025,5045} do
udp_port_table:add(port,tetra_fls_proto)
end
Lua语言为弱语言,无需编译。Lua插件的使用方法如下:
1、直接将该脚本文件放在wireshark安装目录中
2、再在当前路径下找到init.lua文件,在其中结尾处添加dofile(DATA_DIR.."test.lua)语句
3、重启wireshark。