WireShark之Lua插件

在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
-- [email protected]
-- 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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章