使用lua给wireshark编写uTP的Dissector

时间:2022-02-09 17:57:33
 
lonelycastle做uTP的实验,使用wireshark捕包,但是最初没有找到wireshark下的uTP的dissector,每次都需要比对文档,这样做实验理解报文含义,效率非常低。作为程序猿就想写一个uTP的dissector来实现这些工作。说干就干,查了一下发现wireshark可以使用lua来实现dissector,这样就简单过了,不用编写C的dissector了。本身是lua盲,又不了解wireshark的dissector开发,中间遇到了很多问题,还好逻辑比较简单,折腾了一个晚上就搞定了;-)
 
BTW: 后来发现wireshark中已经有了bt-utp这个dissector,但是没有判断PIECE分包。
 
1. 如何定义小于1个字节的field
   >> 查了一下User Guide,发现可以在创建ProtoField的时候,使用mask参数就可以了。
2. 如何取小于1个字节field的值
   >> 这个需要位操作进行处理,具体见参考文献1。主要是bit.band, bit.bor, bit.bxor, bit.rshift, bit.lshift等。注意右移位是bit.rshift,而不是bit.brshift。
3. 如何调用其他Dissector
   >> Dissector.get()获得系统中已经有的dissector;DissectorTable.get()获得系统中已经有的dissector table,再调用get_dissector()获得最终的dissector。
   >> 获得dissector后,就可以直接调用call,call的参数跟dissector function的参数一致。
  1. xx_protocol.dissector = function(buffer,pinfo,tree)
  2. --定义这个协议的解析函数,最后会将这个函数注册到wireshark用来解析数据的表中。这个函数的三个参数很重要,是wireshark引擎在调用该函数是会传入,
  3. --buffer就是我们要分析的数据,
  4. --pinfo记录了前面分析过协议留下的信息,
  5. --tree是用来在详细框中添加我们信息的结构。
4. 如何设置报文信息
   >>直接修改pkt.cols.info,其中pkt是dissector function传入的参数,具体见参考文献4.
5. 如何处理一个应用报文跨多个uTP报文
   >>在BitTorrent中,PIECE报文比较大,会跨多个uTP报文,这个时候需要判断出第一个PIECE报文,进行解析,后面的PIECE报文不需要解析,如果解析就会导致出错。这里是使用一个检查函数,判断每种type下,协议中数据长度是否满足限制来实现的。
 
具体如何运行这里就不多说了,直接在init.lua中最后增加dofile就可以,注意要首先把lua_disable关上,debian用户需要保证root也可以在wireshark中运行lua。调试的时候可以看wireshark的报错信息。
 
示例代码如下,BitTorrent的解析调用了wireshark内部已有的bittorrent.tcp dissector:
  1. do
  2. -- Desc: uTP Protocol lua version
  3. -- Author: WangYao, ipconfigme@gmail.com
  4. -- Date: 2011/10/19
  5. -- protol name
  6. local p_utp = Proto("utp", "Micro Transport Protocol");
  7. -- protocol fields
  8. local f_version = ProtoField.uint8("utp.version", "Version", base.DEC,
  9. {[1]="V1"}, 0x0F)
  10. local f_type = ProtoField.uint8("utp.type", "Type", base.DEC,
  11. {[0]="ST_DATA", [1]="ST_FIN", [2]="ST_STATE", [3]="ST_RESET", [4]="ST_SYN"}, 0xF0)
  12. local f_next_extension_type = ProtoField.uint8("utp.next_extension_type", "Next Extension Type", base.DEC,
  13. {[0]="No Extension", [1]="Selective acks", [2]="Extension bits"})
  14. local f_extension_len = ProtoField.uint8("utp.extension_len", "Extension Length", base.DEC)
  15. local f_extension_bitmask = ProtoField.bytes("utp.extension_bitmask", "Extension Bitmask", base.NONE)
  16. local f_connection_id = ProtoField.uint16("utp.connection_id", "Connection_ID", base.DEC)
  17. local f_timestamp_microseconds = ProtoField.uint32("utp.timestamp_microseconds", "timestamp_microseconds", base.DEC)
  18. local f_timestamp_difference_microseconds = ProtoField.uint32("utp.timestamp_difference_microseconds", "timestamp_difference_microseconds", base.DEC)
  19. local f_wnd_size = ProtoField.uint32("utp.wnd_size", "wnd_size", base.DEC)
  20. local f_seq_nr = ProtoField.uint16("utp.seq_nr", "seq_nr", base.DEC)
  21. local f_ack_nr = ProtoField.uint16("utp.ack_nr", "ack_nr", base.DEC)
  22. p_utp.fields = {f_version, f_type, f_next_extension_type, f_extension_len, f_extension_bitmask, f_connection_id, f_timestamp_microseconds, f_timestamp_difference_microseconds, f_wnd_size, f_seq_nr, f_ack_nr}
  23. -- other dissector
  24. local data_dis = Dissector.get("data")
  25. local bittorrent_dissector = Dissector.get("bittorrent.tcp")
  26. -- utp dissector, return OFFSET
  27. local function utp_dissector(buf,pkt,root)
  28. local buf_len = buf:len()
  29. local offset = 0
  30. -- check pack len
  31. if buf_len < 20 then return 0 end
  32. -- get fields
  33. local v_version = buf(offset, 1)
  34. local v_type = buf(offset, 1)
  35. offset = offset + 1
  36. local v_next_extension_type = buf(offset, 1)
  37. offset = offset + 1
  38. local v_connection_id = buf(offset, 2)
  39. offset = offset + 2
  40. local v_timestamp_microseconds = buf(offset, 4)
  41. offset = offset + 4
  42. local v_timestamp_difference_microseconds = buf(offset, 4)
  43. offset = offset + 4
  44. local v_wnd_size = buf(offset, 4)
  45. offset = offset + 4
  46. local v_seq_nr = buf(offset, 2)
  47. offset = offset + 2
  48. local v_ack_nr = buf(offset, 2)
  49. offset = offset + 2
  50. -- check uTP
  51. local i_version = bit.band(v_version:uint(), 0x0F)
  52. -- local i_type = bit.band(bit.rshift(v_type:uint(), 4), 0x0F)
  53. local i_type = bit.rshift(bit.band(v_type:uint(), 0xF0), 4)
  54. if( (i_version~=1) or (i_type~=0 and i_type~=1 and i_type~=2 and i_type~=3 and i_type~=4))
  55. then return 0 end
  56. local subtree = root:add(p_utp, buf(),"Micro Transport Protocol")
  57. -- just add header
  58. subtree:add(buf(0,0),"uTP Header: ")
  59. subtree:add(f_version, v_version)
  60. subtree:add(f_type, v_type)
  61. subtree:add(f_next_extension_type, v_next_extension_type)
  62. subtree:add(f_connection_id, v_connection_id)
  63. subtree:add(f_timestamp_microseconds, v_timestamp_microseconds)
  64. subtree:add(f_timestamp_difference_microseconds, v_timestamp_difference_microseconds)
  65. subtree:add(f_wnd_size, v_wnd_size)
  66. subtree:add(f_seq_nr, v_seq_nr)
  67. subtree:add(f_ack_nr, v_ack_nr)
  68. -- add pkt info
  69. pkt.cols.protocol = "uTP"
  70. if(i_type==0) then
  71. pkt.cols.info = "uTP ST_DATA"
  72. elseif(i_type==1) then
  73. pkt.cols.info = "uTP ST_FIN"
  74. elseif(i_type==2) then
  75. pkt.cols.info = "uTP ST_STATE"
  76. elseif(i_type==3) then
  77. pkt.cols.info = "uTP ST_RESET"
  78. elseif(i_type==4) then
  79. pkt.cols.info = "uTP ST_SYN"
  80. else
  81. pkt.cols.info = "uTP UNKNOW"
  82. end
  83. while(v_next_extension_type:uint()~=0) do
  84. -- add extension tree
  85. local extendtree = subtree:add(p_utp, buf(offset, buf_len-offset):tvb(),"Extension")
  86. if(v_next_extension_type:uint()==0) then
  87. extendtree:append_text(": NO Extension")
  88. elseif(v_next_extension_type:uint()==1) then
  89. extendtree:append_text(": Selective acks")
  90. elseif(v_next_extension_type:uint()==2) then
  91. extendtree:append_text(": Extension bits")
  92. end
  93. v_next_extension_type = buf(offset, 1)
  94. offset = offset + 1
  95. extendtree:add(f_next_extension_type, v_next_extension_type)
  96. local v_extension_len = buf(offset, 1)
  97. offset = offset + 1
  98. extendtree:add(f_extension_len, v_extension_len)
  99. local i_extension_len = v_extension_len:int()
  100. local v_extension_bitmask = buf(offset, i_extension_len)
  101. offset = offset + i_extension_len
  102. extendtree:add(f_extension_bitmask, v_extension_bitmask)
  103. end
  104. return offset
  105. end
  106. -- check packet is bittorrent? header legal
  107. local function check_bittorrent(buf)
  108. local len = buf:len()
  109. local pack_len = buf(0,4)
  110. local pack_type
  111. if(len<4) then
  112. return false
  113. elseif(buf(0,1):uint()==19 and len==68) then --handshake
  114. return true
  115. elseif(len==4) then --keepalive
  116. if(pack_len:uint()==0) then return true
  117. else return false
  118. end
  119. else
  120. pack_type = buf(4,1)
  121. --choke, unchoke, interested, not interested, have all, have none
  122. if(pack_type:uint()==0 or pack_type:uint()==1 or pack_type:uint()==2 or pack_type:uint()==3 or pack_type:uint()==0x0E or pack_type:uint()==0x0F) then
  123. if(pack_len:uint()==1) then return true
  124. else return false
  125. end
  126. --request, cancel, reject
  127. elseif(pack_type:uint()==6 or pack_type:uint()==8 or pack_type:uint()==0x10) then
  128. if(pack_len:uint()==13) then return true
  129. else return false
  130. end
  131. --port
  132. elseif(pack_type:uint()==9) then
  133. if(pack_len:uint()==3) then return true
  134. else return false
  135. end
  136. --have, suggest, allowed fast
  137. elseif(pack_type:uint()==4 or pack_type:uint()==0x0D or pack_type:uint()==0x11) then
  138. if(pack_len:uint()==5) then return true
  139. else return false
  140. end
  141. --bitfield, extend
  142. elseif(pack_type:uint()==5 or pack_type:uint()==0x14) then
  143. if(pack_len:uint()<1024) then return true
  144. else return false
  145. end
  146. --piece, max than 16K
  147. elseif(pack_type:uint()==7) then
  148. if(pack_len:uint()>=16384) then return true
  149. else return false
  150. end
  151. else
  152. return false
  153. end
  154. end
  155. return false
  156. end
  157. -- protocol dissector, include bittorrent
  158. function p_utp.dissector(buf,pkt,root)
  159. local len = buf:len()
  160. local offset = utp_dissector(buf, pkt, root)
  161. if len>offset and offset>0 then
  162. -- call bittorrent dissector
  163. -- pass split PIECE pack
  164. if check_bittorrent(buf(offset, len-offset)) then
  165. bittorrent_dissector:call(buf(offset, len-offset):tvb(), pkt, root)
  166. else
  167. data_dis:call(buf(offset,len-offset):tvb(), pkt, root)
  168. end
  169. elseif offset==0 then
  170. -- call data dissector
  171. data_dis:call(buf,pkt,root)
  172. end
  173. end
  174. -- add to DissectorTable
  175. local udp_table = DissectorTable.get("udp.port")
  176. -- udp_table:add(4135, p_utp)
  177. udp_table:add(10000, p_utp)
  178. end
 
 
参考
 

使用lua给wireshark编写uTP的Dissector的更多相关文章

  1. Lua 学习 chapter30 编写c函数的技巧 - Jow的博客

    目录 数组操作 字符串操作 在c函数中保存状态 生活总需要一点仪式感,然后慢慢的像那个趋向完美的自己靠近. 数组操作 Lua中的数组就是以特殊的方式使用边.像lua_setttable and lua ...

  2. FCEUX金手指加强版 - 使用Lua脚本语言编写FC&sol;NES金手指脚本

    一直觉得大部分的FC/NES模拟器的作弊码金手指不是那么方便使用, 比如魂斗罗1代, 玩家的武器可以通过修改0xAA的值来改变: 0x11为M弹(重机枪),0x12为F弹(圈圈),0x13为S弹(散弹 ...

  3. Lua编写wireshark插件初探——解析Websocket上的MQTT协议

    一.背景 最近在做物联网流量分析时发现, App在使用MQTT协议时往往通过SSL+WebSocket+MQTT这种方式与服务器通信,在使用SSL中间人截获数据后,Wireshark不能自动解析出MQ ...

  4. Wireshark lua dissector 对TCP消息包合并分析

    应用程序发送的数据报都是流式的,IP不保证同一个一个应用数据包会被抓包后在同一个IP数据包中,因此对于使用自制dissector的时候需要考虑这种情况. Lua Dissector相关资料可以见:ht ...

  5. 【wireshark】插件开发(二):Lua插件开发介绍

    1. Wireshark对Lua的支持 本节相关内容可参考Wireshark开发指南第10章”Lua Support in Wireshark”. Wireshark集成了Lua解释器,以支持Lua脚 ...

  6. Lua语言在Wireshark中使用&lpar;转&rpar;

    1.       检查Wireshark的版本是否支持Lua 打开Wireshark,点击“HelpàAbout Wireshark”菜单,查看弹出的对话框,如果有“with Lua 5.1”表示支持 ...

  7. Wireshark使用drcom&lowbar;2011&period;lua插件协助分析drcom协议

    drcom_2011.lua是来源于Google code上的一个开源项目中的一个插件,感谢网络大神的分享 需要使用drcom_2011.lua分析drcom协议的话,需要把drcom_2011.lu ...

  8. 【wireshark】Wireshark原理分析与二次开发系列

    1.版权声明 本系列文章是本人花了很多心血写成,wireshark本是开源软件,本人也乐于技术知识和经验的分享,更是欣赏和推崇开源精神,因此任何看到本文的人都可以随意转载,但只有一个要求: 在大段甚至 ...

  9. 采访 Lua 发明人的一篇文章

    采访 Lua 发明人的一篇文章 来源 https://blog.codingnow.com/2010/06/masterminds_of_programming_7_lua.html <Mast ...

随机推荐

  1. Identify Memory Leaks in Visual CPP Applications —— VLD内存泄漏检测工具

    原文地址:http://www.codeproject.com/Articles/1045847/Identify-Memory-Leaks-in-Visual-CPP-Applications 基于 ...

  2. PING命令入门详解

    转自:http://www.linkwan.com/gb/tech/htm/928.htm 1.Ping的基础知识 ping命令相信大家已经再熟悉不过了,但是能把ping的功能发挥到最大的人却并不是很 ...

  3. Codeforces Beta Round &num;3

    A题,水题,还是无法1Y. B题,题意是类似背包的问题,在v的容量下,有1重量和2重量的,如果达到价值最大. 贪心,写的很恶心.看着数据过了. 奇数的时候,先选一个1.之后然后1+1 和 2 比较就行 ...

  4. Mysql通信协议

    Mysql四种通信协议(linux下本地连接的都是socket 其他都是tcp) 当连接mysql时,使用-h127.0.0.1时,linux与unix下的连接协议为socket协议,windows下 ...

  5. ED&sol;EP系列7《指令速查表》

    命 令                                                             CLA                  INS             ...

  6. 字符串对比&period;net String&period;EndsWith方法 &lpar;String&rpar;

    string str="web/abc.aspx"; if(str.EndsWith("abc.aspx")) { 此方法将 value 与位于此实例末尾.与 ...

  7. MySql 日期转字符串

    1.date_format 日期转字符串 select date_format(now(),'%Y-%m-%d %H:%i:%s'); 2.str_to_date 字符串转日期 select str_ ...

  8. JTextArea Demo

    在往JTextArea中填充数据时,JTextArea上的滚动条也可以拖动.解决办法:主线程放在EDT中,fill JTextArea的操作放在另外一个线程中,这样fill操作与GUI上的操作就分离了 ...

  9. 51Nod--1006 lcs

    1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

  10. luogu 1471

    题意: 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差. 操作1:1 x y k ,表示将第x到第y项每项加上k,k为一实数. 操作2:2 x y ...