網(wǎng)站版權(quán)文字seo排名賺app最新版本
本?主要介紹 Lua 腳本在 Wireshark 中的應(yīng)?, Lua 腳本可以在 Wireshark 中完成如下功能:
-
從?絡(luò)包中提取數(shù)據(jù), 或者統(tǒng)計(jì)?些數(shù)據(jù)包(
Dumper
) -
需要解析?種 Wireshark 不提供原??持的協(xié)議(
Dissector
)
?例
協(xié)議解析
VREP
協(xié)議是 NOGD
框架對(duì)于 TRIP
協(xié)議的?種延伸和擴(kuò)展. Wireshark 原?并不提供對(duì)于 VREP
協(xié)議的?持, 下圖展?了腳本前后對(duì)?.
(a) VREP 原始字節(jié)流如下
(b) 腳本解析過后的信息
數(shù)據(jù)流提取
Wireshark 對(duì) RTP
和 RTSP
均提供?持, 但是沒提供對(duì)于 RTP over RTSP
協(xié)議的?持, 可以利?此處腳本提供的協(xié)議對(duì)此完成解析. 下圖展?了這種差異.
(a) RTP over RTSP 原始信息
(b) 腳本加強(qiáng)解析后的信息
使??法
假定你要使? foo.lua
腳本
- 將腳本拷?到 Wireshark home ?錄, 如
C:\Program\Files\Wireshark\foo.lua
- 修改
init.lua
腳本(C:\Program\Files\Wireshark\init.lua
), 在末尾添加??dofile("foo.lua")
- 重啟 Wireshark 使腳本?效
不同類型的腳本的使??法:
Dissector
在選定的數(shù)據(jù)流中右擊->
解碼為… -> 選擇腳本注冊(cè)的協(xié)議, 如 RTPP.Dumper
在?具菜單下?選擇注冊(cè)的 dumper.(如Dump MPEG TS Packet
)
解析器(Dissector)
注冊(cè)新協(xié)議
注冊(cè)新協(xié)議的?般步驟.
-
注冊(cè)新協(xié)議
- 基于 UDP 相對(duì)而??較簡(jiǎn)單, 逐個(gè)解析 IP 包即可
- 基于 TCP 解析器?較復(fù)雜, 需要考慮 TCP 重組(TCP Reassembly)
-
定義協(xié)議字段
-
注冊(cè)協(xié)議字段
-
定義解析函數(shù)
-
注冊(cè)到協(xié)議端口號(hào)
解析器代碼框架
local ror = Proto("ror", "RTP over RTSP Protocol")-- 定義協(xié)議字段
local pf_ror_magic = ProtoField.uint8("ror.magic", "Magic", base.HEX)
local pf_ror_channel = ProtoField.uint8("ror.channel", "Interleaved Channel", base.HEX)
local pf_ror_length = ProtoField.uint16("ror.length", "Length")-- 注冊(cè)協(xié)議字段
ror.fields = {pf_ror_magic ,pf_ror_channel ,pf_ror_length ,
}-- 在此處定義你精妙絕倫的解析函數(shù)function ror.dissector(tvbuf, pinfo, root)-- tvbuf: TCP segment-- pinfo: packet column info-- root: node info in the display zoneend-- 指定協(xié)議端?, 此處是tcp 端?
local tcp_dissector_table = DissectorTable.get("tcp.port")
tcp_dissector_table:add(554, ror)
TCP 包重組問題
作為 tcp 解析器必須要?能?處理下??種情況
- TCP 數(shù)據(jù)段只含有協(xié)議數(shù)據(jù)包的前?部分
- TCP 數(shù)據(jù)段含有多個(gè)協(xié)議數(shù)據(jù)包
- 協(xié)議數(shù)據(jù)包在 TCP 數(shù)據(jù)段的中間部分, 因?yàn)閰f(xié)議包的前?部分可能沒有被捕獲到
- 數(shù)據(jù)包可能有被截?cái)嗟那樾?/li>
- 以上?種情形的任意組合
對(duì)以上問題的應(yīng)對(duì)策略.
- 針對(duì) 4, 簡(jiǎn)單來說就是不解析切斷的包(
return 0
) - 針對(duì) 3, 解析函數(shù)必須要做?定的合法性檢查, 如果不是屬于該協(xié)議的包, 那么就丟棄該包(
return 0
) - 針對(duì) 2, 在解析函數(shù)??做?個(gè)
while
循環(huán)(return 已解析的?度
) - 針對(duì) 1, 盡最?可能去確定協(xié)議數(shù)據(jù)包的?度, 如果不能確定, 那么就返回?個(gè)默認(rèn)值
DESEGMENT_ONE_MORE_SEGMENT
dissector 函數(shù)的返回值如下:
- 如果 TCP 數(shù)據(jù)段攜帶的數(shù)據(jù)不屬于當(dāng)前協(xié)議, 那么返回
0
- 如果需要更多的數(shù)據(jù)才能繼續(xù)解析, 那么設(shè)置
desegment_len
,desegment_offset
, 返回值為nil
或者已解析的?度都可以 - 如果不需要更多數(shù)據(jù), 那么返回 nil 或者已經(jīng)解析的?度都可以
Dumper
可以導(dǎo)出指定的協(xié)議字段到?件. 可選的字段:
- 來?預(yù)定義的字段(
ip.src
,tcp.port
,rtsp.length
) - ?定義的字段(
ror.magic
)
Dumper 代碼框架
-- 定義感興趣的字段
-- wireshark 現(xiàn)已?持的協(xié)議的字段
local mpeg_pid = Field.new("mp2t.pid")
local mpeg_pkt = Field.new("mp2t")
-- ?定義協(xié)議的字段
local ror_channel = Field.new("ror.channel")-- 激活對(duì)話框時(shí)候的回調(diào)
local function init_payload_dump(file, filter)local tap = Listener.new(nil, filter)-- this function is going to be called once each time our filter matchesfunction tap.packet(pinfo, tvb)-- do some fancy workendretap_packets()tap:remove()
end-- 窗?回調(diào)
local function begin_dialog_menu()new_dialog("Dump MPEG TS Packets", init_payload_dump, "Output file", ilter")
end-- 注冊(cè)窗?
register_menu("Dump MPEG TS Packets", begin_dialog_menu, MENU_TOOLS_UNSORTED)
樣例解析
如下是?些解析樣例.
- VREP Dissector
- RTP Over RTSP Dissector
- MPEG Dumper
- RTP over RTSP Dumper
VREP Dissector 解析樣例
這個(gè)文件比較長(zhǎng), 請(qǐng)參考我的Github Repo
RTP Over RTSP Dissector 解析樣例
-- 1. declare a new type of protocol
local rtpp = Proto("rtpp", "RTP over RTSP(iPanel Flavor)")-- 2. define some field into the rtpp
local pf_rtpp_magic = ProtoField.uint8("rtpp.magic", "Magic", base.HEX)local pf_rtpp_channel = ProtoField.uint8("rtpp.channel", "Interleaved Channel", base.HEX)
local pf_rtpp_length = ProtoField.uint16("rtpp.length", "Length")-- data 就是?法識(shí)別凈荷內(nèi)容的情況下簡(jiǎn)單的將其設(shè)置為?進(jìn)制數(shù)據(jù)的?法
local default_parser = Dissector.get("data")-- 3. 注冊(cè)新協(xié)議擁有的字段, 這些字段可作為以后抽取數(shù)據(jù)之?
rtpp.fields = {pf_rtpp_magic,pf_rtpp_channel,pf_rtpp_length,
}-- 前向聲明
local dissect_rtpp
local rtpp_min_len = 4-- 此處處理TCP 重傳的邏輯
function rtpp.dissector(tvbuf, pktinfo, root)local segment_length = tvbuf:len()local bytes_consumed = 0local reported_len = tvbuf:reported_length_remaining()if segment_length ~= reported_len then-- captured packets are being sliced/cut-off,-- so don't try to desegment/reassemblereturn 0endwhile bytes_consumed < segment_length do-- 此處會(huì)調(diào)?具體的解析函數(shù)local result = dissect_rtpp(tvbuf, pktinfo, root, bytes_consumed)if result == 0 thenreturn 0elseif result > 0 thenbytes_consumed = bytes_consumed + resultelsetinfo.desegment_offset = bytes_consumedresult = -resultpktinfo.desegment_len = resultreturn segment_lengthendendreturn bytes_consumed
end-- RTP over RTSP 有基本的RTSP 協(xié)議信令也有數(shù)據(jù)流,
-- 對(duì)基本的信令?默認(rèn)的RTSP 解析器來解析
-- 對(duì)interleaved-channel 形式的按照其載荷類型來解析
dissect_rtpp = function(tvbuf, pinfo, root, offset)local msglen = tvbuf:len() - offsetdebug("sub_buf len=" .. msglen .. ", offset=" .. offset)if msglen < rtpp_min_len thendebug("sliced packet")return - DESEGMENT_ONE_MORE_SEGMENTend-- 分類解析if tvbuf:range(offset, 1):uint() ~= 0x24 then-- 以普通的rtsp 消息來解析debug("interpret packet as normal rtsp")local rtsp_dissector = Dissector.get("rtsp")-- 此處的返回值尚不清楚, 對(duì)此的處理也?較幼稚rtsp_dissector:call(tvbuf:range(offset, msglen):tvb(), pinfo, root)info("ret=" .. ret)return msglenelse-- interleaved-channel 形式debug("interpret packet as interleaved channel")local len_buf = tvbuf:range(offset + 2, 2)local payload_len = len_buf:uint()local packet_len = payload_len + 4debug("rtsp packet_len=" .. packet_len .. ", payload_len load=" .. pyload_len)-- ?少需要4 個(gè)字節(jié)才可以區(qū)分出該包是否屬于RTP over RTSP 協(xié)議if msglen < packet_len thenreturn -(packet_len - msglen)end-- 添加?些界?顯?信息root:add(pf_rtpp_magic, tvbuf:range(offset + 0, 1))root:add(pf_rtpp_channel, tvbuf:range(offset + 1, 1))root:add(pf_rtpp_length, len_buf)offset = offset + 4-- 取凈荷的第?個(gè)字節(jié)來區(qū)分mpeg 和rtplocal probe_byte = tvbuf:range(offset, 1):uint()debug("probe_byte=" .. string.format( "0x%x ", probe_byte))if probe_byte == 0x47 then-- 0x47 開頭的就?mpeg 的解析器來解析debug("raw mp2t packet, offset=" .. offset .. ", payload_len=" .. payload_len)local mpeg_dissector = Dissector.get("mp2t")while (offset + 188) <= packet_len dolocal mpeg_tvb = tvbuf:range(offset, packet_len - offset):tvb()-- 暫時(shí)不知道該函數(shù)的返回值是什么情況mpeg_dissector:call(mpeg_tvb, pinfo, root)offset = offset + 188endreturn offsetelseif probe_byte == 0x80 then-- 0x80 開頭的嘗試?rtp 來解析debug("RTP packet, offset=" .. offset .. ", payload_len=" .. payload_len)local rtp_dissector = Dissector.get("rtp")local rtp_tvb = tvbuf:range(offset, payload_len):tvb()-- 同樣也是對(duì)返回值的情況不太了解.rtp_dissector:call(rtp_tvb, pinfo, root)if msglen ~= packet_len thendebug("length not match, payload_len + 4=" .. packet_len.. ", msglen=" .. msglen)endreturn packet_lenelsedefault_parser(tvbuf, pinfo, root)return packet_lenendend
end-- 將RTP over RTSP 協(xié)議注冊(cè)到554 端?
-- 需要注意的是因?yàn)檎{(diào)?了原?RTSP 解析器, 所以我們的解析結(jié)果并不影響普通的rtsp 解析
tcp_dissector_table:add(554, rtpp)
tcp_dissector_table:add(2554, rtpp)
info("rtpp (RTP over RTSP) protocol registed at TCP port 554")
MPEG 流抽取器
if not GUI_ENABLED thenprint("mpeg_packets_dump.lua only works in Wireshark")return
end-- 聲明要抽取的字段
local mpeg_pid = Field.new("mp2t.pid")
local mpeg_pkt = Field.new("mp2t")-- 窗口回調(diào)函數(shù)
local function init_payload_dump(file, filter)local packet_count = 0-- 對(duì)任意的udp 包進(jìn)?過濾-- filter 為符合BPF 格式的任意過濾器local tap = Listener.new(nil, filter)local myfile = assert(io.open(file, "w+b"))-- 每次BPF 過濾器過濾出?個(gè)ip 包就會(huì)調(diào)?下?的函數(shù)function tap.packet(pinfo, tvb)-- 檢查當(dāng)前包??是否有mpeg 包if (mpeg_pid()) thenpacket_count = packet_count + 1-- dump 出所有的mpeg 包local contents = {mpeg_pkt()}-- 逐個(gè)包輸出到?件for i, finfo in ipairs(contents) dolocal tvbrange = finfo.rangelocal subtvb = tvbrange:tvb()myfile:write(subtvb:raw())-- myfile:flush()endendend-- re-inspect all the packets that are in the current capture, thereby-- triggering the above tap.packet functionretap_packets()-- cleanupmyfile:flush()myfile:close()tap:remove()debug("Dumped mpeg packets: " .. packet_count)
endlocal function begin_dialog_menu()new_dialog("Dump MPEG TS Packets", init_payload_dump, "Output file", "Packet filter (optional)\n\nExamples:\nip.dst == 225.1.1.4\nmp2t\nmp2t.pid == 0x300")
end-- 注冊(cè)到程序菜單
register_menu("Dump MPEG TS Packets", begin_dialog_menu, MENU_TOOLS_UNSORTED)
RTP over RTSP 負(fù)載抽取
local mpeg_pid = Field.new("mp2t.pid")
local mpeg_pkt = Field.new("mp2t")
local rtp_payload = Field.new("rtp.payload")local function init_payload_dump(file, filter)local packet_count = 0local real_filter = "(rtpp.channel)"if filter ~= nil and filter ~= "" then-- 拼接??輸?的過濾參數(shù)real_filter = real_filter .. " and (" .. filter ..")"endlocal tap = Listener.new(nil, real_filter)local myfile = assert(io.open(file, "w+b"))function tap.packet(pinfo, tvb)-- 檢查是否有mpeg 數(shù)據(jù)包if (mpeg_pid()) thenlocal contents = {mpeg_pkt()}for i, finfo in ipairs(contents) dolocal tvbrange = finfo.rangelocal subtvb = tvbrange:tvb()myfile:write(subtvb:raw())endelse-- 檢查是否是rtp 包local payload = rtp_payload()if payload thenlocal tvbrange = payload.rangelocal subtvb = tvbrange:tvb()myfile:write(subtvb:raw())endendendretap_packets()myfile:flush() myfile:close() tap:remove()
end
調(diào)試腳本
在命令?中啟? Wireshark, 然后可以在當(dāng)前命令?中看到 Lua 腳本的打印輸出. debug
,warn
(), info()
會(huì)輸出到 Lua console
和 stdout
參考鏈接
- Wireshark Lua
- Lua Dissector
- Wireshark Lua Example