本文讲述如何用wireshark支持的lua脚本语言编写解析器(dissector)来解析HTTP Body部分的内容。Wireshark本身提供的HTTP Body(MIME)媒体内容的解析有限,多为直接显示文本内容,但有时我们在查看抓包时希望能看到进一步的协议解析结果。本文介绍的内容可以帮助有这方面需要的朋友直接编写解析器,进一步解析HTTP Body部分(无论是GET/POST的HTTP Body,还是应答消息的Body)。另外,用lua的好处是不需要用C编译器来写解析器,只要用户文本编辑器写一个lua脚本就可以用了。
我尝试了几种方法,最后在看了wireshark http相关源代码后才找到了比较理想的解析方法。中间走了一些弯路:
1. 刚开始可能认为用postdissectors可以,但是post-dissector解析器本身只能得到一个个独立的当前包的数据,而在HTTP Body媒体内容跨多个TCP包时post-dissector方式就不行了(所谓的reassemble PDU问题)。
2. 直接写dissector来替换http协议的dissector,在自己写的dissector里调用http后再解析http body的方式也不合适。
最后看到wireshark http解析代码里创建了一个media_type的dissector table,专门用于解析媒体内容的,我们只用编写dissector注册到media_type表里,而不是tcp.port表里。
具体dissector代码样例如下:
-- Test your own dissector for known HTTP body -- Author: Huang Qiangxiong ([email protected]) -- change log: -- 2010-04-25 -- Just for test. ------------------------------------------------------------------------------------------------ do local test_dissect_mime = Proto("test_dissect_mime", "MIME Encapsulation [HQX's plugins]") ---- save old dissectors local media_type_table = DissectorTable.get("media_type") local old_dissectors = { ["application/x-www-form-urlencoded"] = media_type_table:get_dissector("application/x-www-form-urlencoded"), ["text/html"] = media_type_table:get_dissector("text/html"), ["image/jpeg"] = media_type_table:get_dissector("image/jpeg"), } -- prepare to get Content-Type field in http headers local f_content_type = Field.new("http.content_type") ---- my dissector function test_dissect_mime.dissector(tvb, pinfo, tree) local content_type = f_content_type() if content_type then -- get type name from Content-Type local type_label = tostring(content_type) local type_name local idx = type_label:find(";") if idx then type_name = type_label:sub(1, idx-1) else type_name = type_label end ---- now, if the type_name is what you want, then begin your own dissection ---- -- following is example code: -- that will add a treeitem, and then show old dissector result under it. local subtree = tree:add(test_dissect_mime, tvb()) subtree:append_text(": " .. type_label) subtree:add("[Body Length: " .. tvb:len() .. "]") subtree:add("[Type name: " .. type_name .. "]") old_dis = old_dissectors[type_name] if old_dis then -- call old dissector and append the result under subtree old_dis:call(tvb, pinfo, subtree) else subtree:add("!Not found old dissector!") end end end -- register this dissector to replace all old dissectors for type_name in pairs(old_dissectors) do media_type_table:add(type_name, test_dissect_mime) end end
从以上代码可以看出,当我们希望解析那种HTTP Body媒体类型时,就在media_type里注册这种类型。以上代码的含义是自己编写的dissector替换原来的HTTP Body媒体类型Content-Type为"application/x-www-form-urlencoded"、"text/html"和"image/jpeg"的解析器(实际上例子只是自己加了一个节点,然后再在这个节点下用原来的解析器再解析了一下)。
在实践中建议大家还是针对每种媒体类型编写一个dissector,然后用类似以下代码注册到media_type:
local media_type_table = DissectorTable.get("media_type")
media_type_table:add("application/x-www-form-urlencoded", your_dissector)
一个实际的例子请参考《用Wireshark lua编写的协议解析器查看Content-Type为application/x-www-form-urlencoded的HTTP抓包》(http://blog.csdn.net/jasonhwang/archive/2010/04/25/5525700.aspx),该例子是在wireshark抓包界面树里进一步解析Content-Type为"application/x-www-form-urlencoded"的form提交的HTTP请求包。
注:wireshark版本为1.2.7