使用Lua脚本为wireshark编写自定义通信协议解析器插件

使用Lua脚本为wireshark编写自定义通信协议解析器插件,第1张

概述在网络通信应用中,我们往往需要自定义应用层通信协议,例如基于UDP的Real-Time Transport Protocol以及基于TCP的RTP over HTTP。鉴于RTP协议的广泛性,wireshark(ethereal)内置了对RTP协议的支持,调试解析非常方便。RTP over HTTP作为一种扩展的RTP协议,尚未得到wireshark的支持。在《RTP Payload Format

在网络通信应用中,我们往往需要自定义应用层通信协议,例如基于UDPReal-Time Transport Protocol以及基于TCPRTP over http。鉴于RTP协议的广泛性,wireshark(ethereal)内置了对RTP协议的支持,调试解析非常方便。RTP over http作为一种扩展的RTP协议,尚未得到wireshark的支持。在《RTP Payload Format for Transport of MPEG-4 Elementary Streams over http》中,使用wireshark只能抓获到原始的TCP数据包,需要我们自己解析蕴含其中的RTP报文,剥离RTP over http 16字节的报文头,然后萃取出MP4V_ES码流数据。

怎么样使wireshark支持自定义通信协议的解析呢?基于GPL v2wireshark强大的插件系统支持用户编写自定义协议解析器插件。wireshark使用C语言编写而成,它支持动态链接库形式的插件扩展。除此之外,wireshark内置了Lua脚本引擎,可以使用Lua脚本语言编写dissector插件。打开C:/Program files/Wireshark/init.lua,确保disable_lua = false以开启wiresharkLua Console

Lua是一种功能强大的、快速的、轻量的、嵌入式的脚本语言,使用Lua编写wireshark dissector插件是非常方便的。本文例解使用Lua编写ROHRTP over http)协议解析插件。

以下为GET http://219.117.194.183:60151/rtpOverHttp?Url=nphMpeg4/nil-640x480,获取MP4V_ES的一个片段,在没有ROH解析支持时,Packet 294显示为TCP报文。

关于RTP over http报文的解析,参考《RTP Payload Format for Transport of MPEG-4 Elementary Streams over http》。关于Lua语法,参考Wireshark User’s GuIDe的《Lua Support in Wireshark》一节。

以下为自定义RTP over http协议解析器插件代码roh.lua

do

    --[[

    Proto.new(name,desc)

        name: displayed in the column of “Protocol” in the packet List

        desc: displayed as the dissection tree root in the packet details

    --]]

    local PROTO_ROH = Proto("ROH","Rtp Over http")

 

    --[[

    protofield:

        to be used when adding items to the dissection tree

    --]]

    --[[

    (1)Rtp Over http header

    --]]

    -- rtp over http header flag(1 byte)

    local f_roh_headerflag = protofield.uint8("ROH.headerFlag","header Flag",base.HEX)

    -- rtp over http interleaved channel(1 byte)

    local f_roh_interleave = protofield.uint8("ROH.InterleavedChannel","Interleaved Channel",base.DEC)

    -- rtp over http packet length(2 bytes)

    local f_roh_packlen = protofield.uint16("ROH.PacketLen","Packet Length",base.DEC)

    --[[

    (2)RTP Over http

    --]]

    -- rtp header(1 byte = V:2+P:1+X:1+CC:4)

    local f_rtp_header = protofield.uint8("ROH.header","Rtp header",base.HEX)

    -- rtp payloadtype(1 byte = M:1+PT:7)

    local f_rtp_payloadtype = protofield.uint8("ROH.PayloadType","Rtp Payload Type",base.HEX)

    -- rtp sequence number(2 bytes)

    local f_rtp_sequence = protofield.uint16("ROH.Sequence","Rtp Sequence Number",base.DEC)

    -- rtp timestamp(4 bytes)

    local f_rtp_timestamp = protofield.uint32("ROH.Timestamp","Rtp Timestamp",base.DEC)

    -- rtp synchronization source IDentifIEr(4 bytes)

    local f_rtp_ssrc = protofield.uint32("ROH.SSRC","Rtp SSRC",base.DEC)

 

    -- define the fIElds table of this dissector(as a protofield array)

    PROTO_ROH.fIElds = {f_roh_headerflag,f_roh_interleave,f_roh_packlen,f_rtp_header,f_rtp_payloadtype,f_rtp_sequence,f_rtp_timestamp,f_rtp_ssrc}

 

    --[[

    Data Section

    --]]

    local data_dis = dissector.get("data")

 

    --[[

    ROH dissector Function

    --]]

    local function roh_dissector(buf,pkt,root)

 

        -- check buffer length

        local buf_len = buf:len()

        if buf_len < 16

        then

            return false

        end

 

        -- check header flag

        if buf(0,2):uint() ~= 0x2400

        then

            return false

        end

 

        --[[

        packet List columns

        --]]

        pkt.cols.protocol = "ROH"

        pkt.cols.info = "Rtp Over http"

 

        --[[

        dissection tree in packet details

        --]]

        -- tree root

        local t = root:add(PROTO_ROH,buf(0,16))

        -- child items

        -- ROH header

        t:add(f_roh_headerflag,1))

        t:add(f_roh_interleave,buf(1,1))

        t:add(f_roh_packlen,buf(2,2))

        -- ROH

        -- (1)header

        t:add(f_rtp_header,buf(4,1))

        -- (2)payloadtype

        t:add(f_rtp_payloadtype,buf(5,1))

        -- (3)sequence number

        t:add(f_rtp_sequence,buf(6,2))

        -- (4)timestamp

        t:add(f_rtp_timestamp,buf(8,4))

        -- (5)ssrc

        t:add(f_rtp_ssrc,buf(12,4))

 

        if buf_len > 16

        then

            local data_len = buf:len()-16;

 

            local d = root:add(buf(16,data_len),"Data")

            d:append_text("("..data_len.." bytes)")

            d:add(buf(16,"Data: ")

            d:add(buf(16,0),"[Length: "..data_len.."]")

 

            local start_code = buf(16,4):uint()

            if start_code == 0x000001b0

            then

                d:add(buf(16,"[Stream Info: VOS]")

            elseif start_code == 0x000001b6

            then

                local frame_flag = buf(20,1):uint()

                if frame_flag<2^6

                then

                    d:add(buf(16,"[Stream Info: I-Frame]")

                elseif frame_flag<2^7

                then

                    d:add(buf(16,"[Stream Info: P-Frame]")

                else

                    d:add(buf(16,"[Stream Info: B-Frame]")

                end

            end

        end

 

        return true

    end

 

    --[[

    dissect Process

    --]]

    function PROTO_ROH.dissector(buf,root)

        if roh_dissector(buf,root)

        then

        -- valID ROH diagram

        else

            data_dis:call(buf,root)

        end

    end

 

    --[[

    Specify Protocol Port

    --]]

    local tcp_encap_table = dissectortable.get("tcp.port")

    tcp_encap_table:add(60151,PROTO_ROH)

end

通过菜单“ToolsàLuaàEvaluate”打开Lua调试窗口,将以上代码输入Evaluate窗口,然后点击“Evaluate”按钮,若无错误提示,且末尾提示“--[[  Evaluated --]]”,则说明代码无语法错误。这时,通过菜单“HelpàSupported Protocols”可以发现,wireshark已经添加了ROH协议调试支持,在display Filter中输入“roh”,则可以看到具体解析结果。

将以上代码保存为C:/Program files/Wireshark/roh.lua。在C:/Program files/Wireshark/init.lua末尾添加代码行:dofile("roh.lua")。这样在以后启动wireshark时,自动加载roh.lua

增加roh.Lua插件扩展后,Packet 294将解析为RTP over http报文。最后的Data部分为剥离16字节报文头后的码流。

由于尚未掌握Lua的位域(bitfIEld) *** 作,因此上面对于RTP的解析不完整,第一个字节(V:2+P:1+X:1+CC:4)和第二字节(M:1+PT:7)的相关位域没有解析出来。

既然wireshark内置了对RTP协议的支持,我们在解析完RTP over http的头4个字节后,可以将余下的报文交由RTP协议解析器解析。以下为调用内置RTP协议解析器代码roh_rtp.lua

do

    --[[

    Proto.new(name,"Rtp Over http")

    local PROTO_PANASONIC_PTZ = Proto("PANASONIC_PTZ","Panasonic PTZ Protocol")

 

    --[[

    protofield:

        to be used when adding items to the dissection tree

    --]]

    --[[

    1.ROH protofield

    --]]

    --rtp over http header flag(1 byte)

    local f_roh_headerflag = protofield.uint8("ROH.headerFlag",base.HEX)

    --rtp over http interleaved channel(1 byte)

    local f_roh_interleave = protofield.uint8("ROH.InterleavedChannel",base.DEC)

    --rtp over http packet length(2 bytes)

    local f_roh_packlen = protofield.uint16("ROH.PacketLen",base.DEC)

    --define the fIElds table of this dissector(as a protofield array)

    PROTO_ROH.fIElds = {f_roh_headerflag,f_roh_packlen}

 

    --[[

    2.PANASONIC_PTZ protofield

    --]]

    -- panasonic ptz header flag(32 ascii)

    local f_panasonic_ptz_flag = protofield.bytes("PANASONIC_PTZ","header Flag")

    -- panasonic ptz command(6~17 ascii)

    local f_panasonic_ptz_cmd = protofield.bytes("PANASONIC_PTZ","Command")

    --define the fIElds table of this dissector(as a protofield array)

    PROTO_PANASONIC_PTZ.fIElds = {f_panasonic_ptz_flag,f_panasonic_ptz_cmd}

 

    --[[

    Data Section

    --]]

    local data_dis = dissector.get("data")

 

    --[[

    ROH dissector Function

    --]]

    local function roh_dissector(buf,root)

        -- check buffer length

        local buf_len = buf:len()

        if buf_len < 16

        then

            return false

        end

       

        -- check header flag

        if buf(0,2):uint() ~= 0x2400

        then

            return false

        end

 

        --[[

        packet List columns

        --]]

        pkt.cols.protocol = "ROH"

        pkt.cols.info = "Rtp Over http"

 

        --[[

        dissection tree in packet details

        --]]

        -- tree root

        local t = root:add(PROTO_ROH,4))

        -- child items

        t:add(f_roh_headerflag,2))

 

        return true

    end

 

    --[[

    PANASONIC_PTZ dissector Function Helper

    --]]

    local function get_cmd_len(buf)

        local found=0

        for i=0,17 do

            if buf(i,1):uint() == 0x26

            then

                found = i

                break

            end

        end

        return found

    end

 

    --[[

    PANASONIC_PTZ dissector Function

    --]]

    local function panasonic_ptz_dissector(buf,root)

 

        -- check buffer length

        local buf_len = buf:len()

        if buf_len < 32

        then

            return false

        end

 

        -- check header flag

        if buf(0,32):string() ~= "GET /nphControlCamera?Direction="

        then

            return false

        end

 

        -- check direction

        local sub_buf = buf(32,18):tvb()

        local cmd_len = get_cmd_len(sub_buf)

 

        if cmd_len > 0

        then

            --[[

            packet List columns

            --]]

            pkt.cols.protocol = "PANASONIC_PTZ"

            pkt.cols.info = "Panasonic PTZ Protocol"

 

            --[[

            dissection tree in packet details

            --]]

            -- tree root

            local t = root:add(PROTO_PANASONIC_PTZ,buf_len))

            -- child items

            local flag = t:add(f_panasonic_ptz_flag,32))

            flag:add(buf(0,31),"["..buf(0,31):string().."]")

            local cmd = t:add(f_panasonic_ptz_cmd,buf(32,cmd_len))

            cmd:add(buf(32,cmd_len),"["..buf(32,cmd_len):string().."]")

        else

            return false

        end

 

        return true

    end

 

    --[[

    dissect Process

    --]]

    function PROTO_ROH.dissector(buf,root)

        then

            -- skip over rtp over http header

            local rtp_buf = buf(4,buf:len()-4):tvb()

            -- call internal rtp dissector

            local rtp_dissector = dissector.get("rtp")

            rtp_dissector:call(rtp_buf,root)

        elseif panasonic_ptz_dissector(buf,root)

        then

            -- valID ptz datagram

        else

            data_dis:call(buf,root)

        end

    end

 

    --[[

    Specify Protocol Port

    --]]

    local tcp_encap_table = dissectortable.get("tcp.port")

    tcp_encap_table:add(60151,PROTO_ROH)

end

此外,wireshark内置了对MP4V_ES码流解析器,选择菜单“EditàPreferencesàProtocolsàMP4V_ES”,在“MP4V_ES dynamic payload type:”中填写“96”。

将以上代码保存为C:/Program files/Wireshark/roh_rtp.lua。在C:/Program files/Wireshark/init.lua末尾添加代码行:dofile("roh_rtp.lua"),在dofile("roh.lua")前添加“--”注释,以免端口冲突(在roh.luatcp.port=60151)。保存init.lua后,重启wireshark

自定义应用层协议基于传输层(UDP/TCP),自定义的协议端口号不能与wireshark内置应用层协议冲突。若将ROH协议指定为TCP 80,则需要选择菜单“AnalyzeàEnabled Protocols”勾掉http,这样TCP 80的报文将按照ROH协议解析。

display Filter中输入“roh”可查看RTP+MP4V_ES解析结果,如下图所示:

此外,在display Filter中输入“panasonic_ptz”可查看PTZ控制报文。

 

参考:

Programming in Lua

Lua 5.0 Reference Manual

Small is Beautiful: the design of Lua

Lua Scripting in Wireshark

 

为Wireshark 开发插件

使用lua脚本编写wireshark协议插件

使用lua编写Wireshark的dissector插件

用Lua语言编写Wireshark dissector插件

Lua和Wireshark配合,调试通信程序

总结

以上是内存溢出为你收集整理的使用Lua脚本为wireshark编写自定义通信协议解析器插件全部内容,希望文章能够帮你解决使用Lua脚本为wireshark编写自定义通信协议解析器插件所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1267574.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)