lua入门及wireshark自定义协议lua解码
文章目錄
- 介紹
- Lua 特性
- lua環(huán)境搭建
- Window 系統(tǒng)上安裝 Lua
- Lua 基本語(yǔ)法
- 第一個(gè) Lua 程序
- 交互式編程
- 腳本式編程
- 實(shí)例
- 注釋
- 單行注釋
- 多行注釋
- 標(biāo)示符
- 關(guān)鍵詞
- 全局變量
- 運(yùn)算符
- 函數(shù)
- 實(shí)例
- wireshark與lua
- wireshark的lua API —— Proto
- ProtoField
- 參數(shù)
- Tvb
- Pinfo
- TreeItem
- wireshark文檔分享:
- 對(duì)于TCP分包的合并分析
介紹
Lua 是一種輕量小巧的腳本語(yǔ)言,用標(biāo)準(zhǔn)C語(yǔ)言編寫并以源代碼形式開放, 其設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能。
Lua 是巴西里約熱內(nèi)盧天主教大學(xué)(Pontifical Catholic University of Rio de Janeiro)里的一個(gè)研究小組于 1993 年開發(fā)的,該小組成員有:Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo。
其設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能。
Lua 特性
-
輕量級(jí): 它用標(biāo)準(zhǔn)C語(yǔ)言編寫并以源代碼形式開放,編譯后僅僅一百余K,可以很方便的嵌入別的程序里。
-
可擴(kuò)展: Lua提供了非常易于使用的擴(kuò)展接口和機(jī)制:由宿主語(yǔ)言(通常是C或C++)提供這些功能,Lua可以使用它們,就像是本來(lái)就內(nèi)置的功能一樣。
-
其它特性:
- 支持面向過程(procedure-oriented)編程和函數(shù)式編程(functional programming);
- 自動(dòng)內(nèi)存管理;只提供了一種通用類型的表(table),用它可以實(shí)現(xiàn)數(shù)組,哈希表,集合,對(duì)象;
- 語(yǔ)言內(nèi)置模式匹配;閉包(closure);函數(shù)也可以看做一個(gè)值;提供多線程(協(xié)同進(jìn)程,并非操作系統(tǒng)所支持的線程)支持;
- 通過閉包和table可以很方便地支持面向?qū)ο缶幊趟枰囊恍╆P(guān)鍵機(jī)制,比如數(shù)據(jù)抽象,虛函數(shù),繼承和重載等。
lua環(huán)境搭建
Window 系統(tǒng)上安裝 Lua
window下你可以使用一個(gè)叫"SciTE"的IDE環(huán)境來(lái)執(zhí)行l(wèi)ua程序,下載地址為:
-
Github 下載地址:https://github.com/rjpcomputing/luaforwindows/releases
-
Google Code下載地址 : https://code.google.com/p/luaforwindows/downloads/list
雙擊安裝后即可在該環(huán)境下編寫 Lua 程序并運(yùn)行。
你也可以使用 Lua 官方推薦的方法使用 LuaDist:http://luadist.org/
Lua 基本語(yǔ)法
第一個(gè) Lua 程序
交互式編程
Lua 提供了交互式編程模式。我們可以在命令行中輸入程序并立即查看效果。
Lua 交互式編程模式可以通過命令 lua -i 或 lua 來(lái)啟用:
$ lua -i $ Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio >在命令行中,輸入以下命令:
> print("Hello World!")接著我們按下回車鍵,輸出結(jié)果如下:
\> print("Hello World!") Hello World! \>腳本式編程
我們可以將 Lua 程序代碼保存到一個(gè)以 lua 結(jié)尾的文件,并執(zhí)行,該模式稱為腳本式編程,如我們將如下代碼存儲(chǔ)在名為 hello.lua 的腳本文件中:
print("Hello World!") print("I'm orange")使用 lua 名執(zhí)行以上腳本,輸出結(jié)果為:
$ lua hello.lua Hello World! I'm orange我們也可以將代碼修改為如下形式來(lái)執(zhí)行腳本(在開頭添加:#!/usr/local/bin/lua):
實(shí)例
#!/usr/local/bin/lua print("Hello World!") print("I'm orange")以上代碼中,我們指定了 Lua 的解釋器/usr/local/bin directory。加上 # 號(hào)標(biāo)記解釋器會(huì)忽略它。接下來(lái)我們?yōu)槟_本添加可執(zhí)行權(quán)限,并執(zhí)行:
.\hello.lua Hello World! I'm orange注釋
單行注釋
兩個(gè)減號(hào)是單行注釋:
--多行注釋
--[[多行注釋多行注釋--]]標(biāo)示符
Lua 標(biāo)示符用于定義一個(gè)變量,函數(shù)獲取其他用戶定義的項(xiàng)。標(biāo)示符以一個(gè)字母 A 到 Z 或 a 到 z 或下劃線 _ 開頭后加上 0 個(gè)或多個(gè)字母,下劃線,數(shù)字(0 到 9)。
最好不要使用下劃線加大寫字母的標(biāo)示符,因?yàn)長(zhǎng)ua的保留字也是這樣的。
Lua 不允許使用特殊字符如 @, $, 和 % 來(lái)定義標(biāo)示符。 Lua 是一個(gè)區(qū)分大小寫的編程語(yǔ)言。因此在 Lua 中 Runoob 與 runoob 是兩個(gè)不同的標(biāo)示符。
關(guān)鍵詞
以下列出了 Lua 的保留關(guān)鍵詞。保留關(guān)鍵字不能作為常量或變量或其他用戶自定義標(biāo)示符:
| elseif | end | false | for |
| function | if | in | local |
| nil | not | or | repeat |
| return | then | true | until |
| while | goto |
一般約定,以下劃線開頭連接一串大寫字母的名字(比如 _VERSION)被保留用于 Lua 內(nèi)部全局變量。
全局變量
在默認(rèn)情況下,變量總是認(rèn)為是全局的。
全局變量不需要聲明,給一個(gè)變量賦值后即創(chuàng)建了這個(gè)全局變量,訪問一個(gè)沒有初始化的全局變量也不會(huì)出錯(cuò),只不過得到的結(jié)果是:nil。
\> print(b) nil \> b=10 \> print(b) 10 \>如果你想刪除一個(gè)全局變量,只需要將變量賦值為nil。
b = nil print(b) --> nil這樣變量b就好像從沒被使用過一樣。換句話說, 當(dāng)且僅當(dāng)一個(gè)變量不等于nil時(shí),這個(gè)變量即存在。
運(yùn)算符
常用算數(shù)運(yùn)算符:設(shè)A的值為10,B的值為21:
| + | 加法 | A + B 輸出結(jié)果 31 |
| - | 減法 | A - B 輸出結(jié)果 -11 |
| * | 乘法 | A * B 輸出結(jié)果 210 |
| / | 除法 | B / A 輸出結(jié)果 2.1 |
| % | 取余 | B % A 輸出結(jié)果 1 |
| ^ | 乘冪 | A^2 輸出結(jié)果 100 |
| - | 負(fù)號(hào) | -A 輸出結(jié)果 -10 |
關(guān)系運(yùn)算符,設(shè)A的值為10,B的值為21:
| == | 等于,檢測(cè)兩個(gè)值是否相等,相等返回 true,否則返回 false | (A == B) 為 false。 |
| ~= | 不等于,檢測(cè)兩個(gè)值是否相等,不相等返回 true,否則返回 false | (A ~= B) 為 true。 |
| > | 大于,如果左邊的值大于右邊的值,返回 true,否則返回 false | (A > B) 為 false。 |
| < | 小于,如果左邊的值大于右邊的值,返回 false,否則返回 true | (A < B) 為 true。 |
| >= | 大于等于,如果左邊的值大于等于右邊的值,返回 true,否則返回 false | (A >= B) 返回 false。 |
| <= | 小于等于, 如果左邊的值小于等于右邊的值,返回 true,否則返回 false | (A <= B) 返回 true。 |
邏輯運(yùn)算符,設(shè)A 的值為 true,B 的值為 false
| and | 邏輯與操作符。 若 A 為 false,則返回 A,否則返回 B。 | (A and B) 為 false。 |
| or | 邏輯或操作符。 若 A 為 true,則返回 A,否則返回 B。 | (A or B) 為 true。 |
| not | 邏輯非操作符。與邏輯運(yùn)算結(jié)果相反,如果條件為 true,邏輯非為 false。 | not(A and B) 為 true。 |
其他運(yùn)算符:
| … | 連接兩個(gè)字符串 | a…b ,其中 a 為 "Hello " , b 為 “World”, 輸出結(jié)果為 “Hello World”。 |
| # | 一元運(yùn)算符,返回字符串或表的長(zhǎng)度。 | #“Hello” 返回 5 |
函數(shù)
Lua 編程語(yǔ)言函數(shù)定義格式如下:
optional_function_scope function function_name( argument1, argument2,......argumentn)function_bodyreturn result_params_comma_separated end- optional_function_scope: 該參數(shù)是可選的制定函數(shù)是全局函數(shù)還是局部函數(shù),未設(shè)置該參數(shù)默認(rèn)為全局函數(shù),如果你需要設(shè)置函數(shù)為局部函數(shù)需要使用關(guān)鍵字 local。
- function_name: 指定函數(shù)名稱。
- argument1, argument2, argument3…, argumentn: 函數(shù)參數(shù),多個(gè)參數(shù)以逗號(hào)隔開,函數(shù)也可以不帶參數(shù)。
- function_body: 函數(shù)體,函數(shù)中需要執(zhí)行的代碼語(yǔ)句塊。
- result_params_comma_separated: 函數(shù)返回值,Lua語(yǔ)言函數(shù)可以返回多個(gè)值,每個(gè)值以逗號(hào)隔開。
實(shí)例
以下實(shí)例定義了函數(shù) max(),參數(shù)為 num1, num2,用于比較兩值的大小,并返回最大值:
--[[ 函數(shù)返回兩個(gè)值的最大值 --]] function max(num1, num2)if (num1 > num2) thenresult = num1;elseresult = num2;endreturn result; end -- 調(diào)用函數(shù) print("兩值比較最大值為 ",max(10,4)) print("兩值比較最大值為 ",max(5,6))以上代碼執(zhí)行結(jié)果為:
兩值比較最大值為 10兩值比較最大值為 6wireshark與lua
wireshark的lua API —— Proto
表示一個(gè)新的Protocol,在Wireshark中Protocol對(duì)象有很多用處,解析器是其中主要的一個(gè)。主要接口有:
| proto:__call (name,desc) | 創(chuàng)建Proto對(duì)象。name和desc分別是對(duì)象的名稱和描述,前者可用于過濾器等 |
| proto.name | get名稱 |
| proto.fields | get/set字段 |
| proto.prefs | get配置項(xiàng) |
| proto.init | 初始化,無(wú)參數(shù) |
| proto.dissector | 解析函數(shù),3個(gè)參數(shù)tvb,pinfo,tree,分別是報(bào)文內(nèi)容,報(bào)文信息和解析樹結(jié)構(gòu) |
| proto:register_heuristic (listname, func) | 為Proto注冊(cè)一個(gè)啟發(fā)式解析器,被調(diào)用時(shí),參數(shù)func將被傳入與dissector方法相同的3個(gè)參數(shù) |
Proto舉例:
-- create a new protocol local proto_name = "PNASKCP" local proto_desc = "Private NAS Protocol (KCP)" local proto_obj = Proto(proto_name, proto_desc) local proto_port = 5067--register this dissector add Packet Details DissectorTable.get("udp.port"):add(proto_port, proto_obj)ProtoField
表示協(xié)議字段,一般用于解析字段后往解析樹上添加節(jié)點(diǎn)。根據(jù)字段類型不同,其接口可以分為兩大類。
這些接口都會(huì)返回一個(gè)新的字段對(duì)象。方括號(hào)內(nèi)是可選字段,花括號(hào)內(nèi)是可替換的類型字段。
ProtoField.{type}(abbr, [name], [base], [valuestring], [mask], [desc])·type包括:uint8, uint16, uint24, uint32, uint64, framenum, float, double, string, stringz, bytes, bool, ipv4, ipv6, ether,oid, guid參數(shù)
-
abbr
字段的縮寫名稱(過濾器中使用的字符串)。
-
name (optional)
字段的實(shí)際名稱(出現(xiàn)在樹中的字符串)。
-
base (optional)
base.DEC,base.HEX或base.OCT,base.DEC_HEX,base.HEX_DEC,base.UNIT_STRING或base.RANGE_STRING。
-
valuestring (optional)
包含與值對(duì)應(yīng)的文本的表,或包含與值 ({min, max, “string”}) 對(duì)應(yīng)的范圍字符串值表的表(如果基數(shù)為 )base.RANGE_STRING,或包含單位名稱的表如果 base 是base.UNIT_STRING.
-
mask (optional)
此字段的整數(shù)掩碼。
-
desc (optional)
字段說明。
舉例:
fields.tlv_value_int16 = ProtoField.uint16(proto_name .. ".tlv_value_int", "PNAS TLV VALUE", base.HEX)fields.uri_ipv4 = ProtoField.ipv4(proto_name .. ".uri_ipv4", "IP ADDRESS")[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-2Zg7qC6t-1644300257537)(C:\Users\210744417\AppData\Roaming\Typora\typora-user-images\image-20211201094858126.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-rx3VEfm7-1644300257538)(C:\Users\210744417\AppData\Roaming\Typora\typora-user-images\image-20211201094827857.png)]
Tvb
Tvb(Testy Virtual Buffer)表示報(bào)文緩存,也就是實(shí)際的報(bào)文數(shù)據(jù),可以通過下面介紹的TvbRange從報(bào)文數(shù)據(jù)中解出信息。主要接口有:
| tvb:__tostring() | 將報(bào)文數(shù)據(jù)轉(zhuǎn)化為字符串,可用于調(diào)試 |
| tvb:reported_len() | get tvb的(not captured)長(zhǎng)度 |
| tvb:len() | get tvb的(captured)長(zhǎng)度 |
| tvb:reported_length_remaining() | 獲取當(dāng)前tvb的剩余長(zhǎng)度,如果偏移值大于報(bào)文長(zhǎng)度,則返回-1 |
| tvb:offset() | 返回原始偏移 |
Pinfo
報(bào)文信息(packet information)。主要接口有:
| pinfo.len pinfo.caplen | get報(bào)文長(zhǎng)度 |
| pinfo.abs_ts | get報(bào)文捕獲時(shí)間 |
| pinfo.number | get報(bào)文編號(hào) |
| pinfo.src pinfo.dst | get/set報(bào)文的源地址、目的地址 |
| pinfo.columns pinfo.cols | get報(bào)文列表列(界面) |
? [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-teVeGuBU-1644300257539)(C:\Users\210744417\AppData\Roaming\Typora\typora-user-images\image-20211201100432245.png)]
TreeItem
表示報(bào)文解析樹中的一個(gè)樹節(jié)點(diǎn)。主要接口有:
| treeitem:add([protofield], [tvbrange], [value], [label]) | 向當(dāng)前樹節(jié)點(diǎn)添加一個(gè)子節(jié)點(diǎn) |
| treeitem:set_text(text) | 設(shè)置當(dāng)前樹節(jié)點(diǎn)的文本 |
| treeitem:prepend_text(text) | 在當(dāng)前樹節(jié)點(diǎn)文本的前面加上text |
| treeitem:append_text(text) | 在當(dāng)前樹節(jié)點(diǎn)文本的后面加上text |
還有注意一下網(wǎng)絡(luò)字節(jié)序的問題,如果是網(wǎng)絡(luò)字節(jié)序需要用add_le添加節(jié)點(diǎn)~
添加節(jié)點(diǎn)舉例
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-fg6xLCrJ-1644300257539)(C:\Users\210744417\AppData\Roaming\Typora\typora-user-images\image-20211201101225673.png)]
wireshark文檔分享:
wireshark官方文檔:https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html
對(duì)于TCP分包的合并分析
應(yīng)用程序發(fā)送的數(shù)據(jù)報(bào)都是流式的,當(dāng)一次發(fā)送的數(shù)據(jù)量很大時(shí),數(shù)據(jù)包會(huì)進(jìn)行截?cái)喾职l(fā)送,因此對(duì)于使用自制dissector的時(shí)候需要考慮這種情況,對(duì)分包的TCP進(jìn)行合并解析。
Lua Dissector相關(guān)資料可以見:http://wiki.wireshark.org/Lua/Dissectors
使用Lua合并tcp數(shù)據(jù)報(bào)進(jìn)行分析的樣例如下
local Agreement = Proto("Agreement", "Agreement") function Agreement.dissector(tvb, pinfo, tree)--設(shè)置指針起始位置local offset = pinfo.desegment_offset or 0local massagelen = get_len() while true dolocal nxtpdu = offset + massagelenif nxtpdu > tvb:len() then--如果協(xié)議數(shù)據(jù)長(zhǎng)度大于該包的長(zhǎng)度,說明被分包了,記錄被截?cái)喟臄?shù)據(jù)當(dāng)前的位置指針pinfo.desegment_len = nxtpdu - tvb:len()pinfo.desegment_offset = offsetreturnendtree:add(Agreement, tvb(offset, massagelen))offset = nxtpduif nxtpdu == tvb:len() thenreturnendend end local tcp_table = DissectorTable.get("tcp.port") tcp_table:add(5060, Agreement)總結(jié)
以上是生活随笔為你收集整理的lua入门及wireshark自定义协议lua解码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nexus 5x安装xposed
- 下一篇: 论文要点总结:Gradient-Base