[译]用lua创建一个Wireshark解剖器系列1(基础)

原文
这篇文章将向你讲解如何用Lua语言简单地创建协议解剖器。当你使用Wireshark尚未拥有解剖器的自定义协议时,此功能非常有用。例如Wireshark长这样

wireshark查看报文

很难说出数据部分中的各个字节代表什么。
Wireshark是用C语言编写的,Wireshark的解剖器通常也用C语言编写。然而,Wireshark有一个Lua实现,使不熟悉C的人可以轻松编写解剖器。对于那些不熟悉Lua的人来说,它是一种非常轻量级的编程语言,旨在作为应用程序中的脚本语言实现,以扩展其功能。
使用Lua的缺点是这样编写出来的解剖器将比用C编写的解剖器慢。
在我们开始编写解剖器之前,让我们来看看Lua的速成课程。详细了解语言并不必要,但我们必须了解基础知识。

Lua速成班

  • Lua是多范式的,在某种程度上支持面向过程风格,函数式编程,并且它还具有一些面向对象的编程特性。它没有开箱即用的类,原型或继承,但它们可以由程序员定制。
  • 它是动态输入的
  • 范围分为localglobal,未声明的情况下默认为全局可见。
  • 不需要分号结尾。空格并不像Python中那样重要
  • --开头的行为注释
  • 不要使用+++=。使用i = i +1替代
  • 不等于用~=表示而非!=
  • 数据类型:string、number、boolean、nil、function、userdata、thread、table。数字型代表所有的数字,包括浮点型和整数。布尔型包含两个值:false和true。字符串由一对双引号或单引号来表示。你可以忘掉thread和userdata。
  • nil表示一个无效值,变量在被明确赋值前为nil。
  • 在条件表达式中:nil和false为假,其他为真
  • Lua有一个名为table的类型,它也是Lua里唯一的数据结构。表实现了关联数组。关联数组可以由数字和其他类型(如字符串)索引。它们没有固定的大小,可以动态添加元素。表通常称为对象。它们是这样创建的:
new_table = {}

赋值:

new_table[20] = 10
new_table["x"] = "test"
a.x = 10                    -- same as a["x"] = 10

它们可以具有函数,并且通常与JavaScript中的对象非常相似。

  • 条件分支看起来像这样:
if i == 0 then variable = 200
elseif i == 1 then variable = 300
else variable = 400 end
  • 循环看起来像这样:
while i < 10 do
  i = i + 1
end
for i = 0, 10, 1 do
  print(i)
end

for后面跟的内容分别为 i = first, last, delta. break可以使用,但是continue不被允许

  • 函数声明:
function add(arg1, arg2)
    return arg1 + arg2
end

函数调用:

local added_number = add(2, 3)

如果你看到这样的函数调用:

a:func1()
a.func2()

然后函数func1func2属于表(对象)a。使用冒号是语法糖,用于将对象本身作为参数传递给函数。这意味着a:func1()类似于a.func1(a)
那是重要的事情。如果您关心细节,可以阅读 Lua 5.3参考手册

Setup

Lua脚本放在plugins文件夹的子文件夹中,该文件夹位于Wireshark根文件夹中。子文件夹以Wireshark版本命名。例如。 Windows上的C:\ Program Files \ Wireshark \ plugins \ 2.4.2。启动Wireshark时,该脚本将处于活动状态。在对脚本进行更改后,必须重新启动Wireshark,或者使用Ctrl + Shift + L重新加载所有Lua脚本。
我正在使用当前的最新版本。我在这里做的可能不适用于早期版本。

协议

在这篇文章中探讨的最有趣的协议可能是Wireshark当前不知道的自定义协议,但我使用过的所有自定义协议都与工作有关,我不能在这里发布有关它们的信息。所以我们将看看MongoDB wire protocol
Wrieshark已经有一个 Mongo dissector ,但是我不会使用那个
根据上面链接的规范,MongoDB有线协议是使用端口号27017的TCP / IP协议。字节排序是小端,意味着最低有效字节首先出现。大多数协议都是大端。唯一的区别是字节的排序。例如,如果我们有一个int32,这些字节为:00 4F 23 11 大端,那么小端版本将是11 23 4F 00.这是编写解剖器时必须考虑的事项
在这篇文章中,我将只看一下协议的头。看起来像这样

Mongo协议头

我们可以看到它有四个int32,每个包含4个字节,因为4 * 8 = 32。

设置样板代码

让我们首先设置一些所有解剖器都需要的样板代码:

mongodb_protocol = Proto("MongoDB",  "MongoDB Protocol")

mongodb_protocol.fields = {}

function mongodb_protocol.dissector(buffer, pinfo, tree)
  length = buffer:len()
  if length == 0 then return end

  pinfo.cols.protocol = mongodb_protocol.name

  local subtree = tree:add(mongodb_protocol, buffer(), "MongoDB Protocol Data")
end

local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(59274, mongodb_protocol)

我们开始创建一个Proto(protocol)对象并将其命名为mongodb_protocol。表构造函数有两个参数:namedescription。该协议需要fields表和解剖器函数。我们还没有添加任何字段,因此fields表为空。对于我们指定类型的每个数据包,都会调用一次解剖器函数。
解剖器函数有三个参数:buffer,pinfo,treebuffer包含数据包的缓冲区,是一个Tvb对象
。它包含我们想要剖析的数据。pinfo包含数据包列表的列,是一个Pinfo对象。最后,tree是树根,是TreeItem对象

数据包列表列对象

Tree

在解剖器函数内部,我们首先检查缓冲区的长度,然后返回它是否为空。
如前所述,pinfo对象包含数据包列表中的列。当我们收到MongoDB类型的数据包时,我们可以使用它来设置协议名称。在脚本的第一行,我们将协议的名称设置为“MongoDB”(通过将名称传递给构造函数)。我们在此处设置协议列名称

pinfo.cols.protocol = mongodb_protocol.name

并且协议列名称从TCP更改为MONGODB:



然后,我们必须在“数据包详细信息”窗格中的树结构中创建一个子树。它通过向树对象添加一个额外的树项来完成,该树对象作为参数传递给解剖器函数。

local subtree = tree:add(mongodb_protocol, buffer(), "MongoDB Protocol Data")

字符串是子树的名称。没有添加任何字段,它将如下所示:



最后,我们必须将协议分配给端口。就我而言,我将使用端口59274,因为这是我用来连接Mongo数据库的端口。

local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(59274, mongodb_protocol)

如果协议使用UDP而不是TCP,也可以使用“udp.port”。

添加字段(fields)

这个阶段该脚本已经可以运行,但它没有做任何有用的事情。为了使脚本能够执行有用的操作,我们必须添加要解析的字段。通过创建ProtoField对象来创建字段。我们可以通过仅添加第一个字段来开始。 MongoDB有线协议规范中的第一个字段是消息长度,它是一个int32。

mongodb_protocol = Proto("MongoDB",  "MongoDB Protocol")

message_length = ProtoField.int32("mongodb.message_length", "messageLength", base.DEC)

mongodb_protocol.fields = { message_length }

function mongodb_protocol.dissector(buffer, pinfo, tree)
  length = buffer:len()
  if length == 0 then return end

  pinfo.cols.protocol = mongodb_protocol.name

  local subtree = tree:add(mongodb_protocol, buffer(), "MongoDB Protocol Data")

  subtree:add_le(message_length, buffer(0,4))
end

local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(59274, mongodb_protocol)

我们在上面的解剖器函数中添加以下内容:

message_length = ProtoField.int32("mongodb.message_length", "messageLength", base.DEC)

第一个参数在过滤器设置中用作标签,第二个用作子树中的标签,最后一个用于决定变量值的显示方式。在这种情况下,我想以十进制显示值,但我也可以使用base.HEX以十六进制格式显示它。但十六进制格式不适用于int32。
ProtoField有几种我们可以使用的函数:uint8(),uint16(),string()等。我们必须使用符合规范的那个。可以在here找到所有功能的列表。
然后,我们将该字段添加到协议的fields表中:

mongodb_protocol.fields = { message_length }

最后将字段添加到子树:

subtree:add_le(message_length, buffer(0,4))

我使用add_le而不是add,因为我们正在使用little-endian协议。如果协议是大端,我们将不得不使用add。该函数有两个参数:我们进一步增加的字段和缓冲区范围。我们可以通过使用作为缓冲区对象一部分的range函数来获取一系列缓冲区。 buffer(offset,length)是范围函数的缩写形式。 buffer(0,4)表示我们要从第一个字节开始,然后取4个字节。我们想要从0开始的原因是因为我们正在处理标头中的第一个字段。我们占用4个字节,因为这是int32的大小。
使用Ctrl + Shift + L重新加载Lua脚本后,Wireshark应如下所示:


我们可以看到它正确解析了messageLength。我们还可以看到,我们不必解析所有字段以使其工作。我们可以逐步扩展插件。
标头中的其他三个字段也是int32s。我们可以像添加消息长度字段一样添加它们。因此,这部分的最终脚本如下所示:

mongodb_protocol = Proto("MongoDB",  "MongoDB Protocol")

message_length = ProtoField.int32("mongodb.message_length", "messageLength", base.DEC)
request_id     = ProtoField.int32("mongodb.requestid"     , "requestID"    , base.DEC)
response_to    = ProtoField.int32("mongodb.responseto"    , "responseTo"   , base.DEC)
opcode         = ProtoField.int32("mongodb.opcode"        , "opCode"       , base.DEC)

mongodb_protocol.fields = { message_length, request_id, response_to, opcode }

function mongodb_protocol.dissector(buffer, pinfo, tree)
  length = buffer:len()
  if length == 0 then return end

  pinfo.cols.protocol = mongodb_protocol.name

  local subtree = tree:add(mongodb_protocol, buffer(), "MongoDB Protocol Data")

  subtree:add_le(message_length, buffer(0,4))
  subtree:add_le(request_id,     buffer(4,4))
  subtree:add_le(response_to,    buffer(8,4))
  subtree:add_le(opcode,         buffer(12,4))
end

local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(59274, mongodb_protocol)

我们必须在调用范围函数(buffer(offset,length))时将偏移量增加4,以便为每个字段读取4个新字节。如果我们处理的不是int32s,我们当然必须增加其他东西。
数据包详细信息窗格最终如下所示:


我们现在很高兴。在下一部分中,我将介绍调试和更高级的解析方法。现在,我们只看到操作码的数值,但操作码名称会更有趣。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,766评论 0 38
  • 标签(空格分隔): Wireshark Lua 参考:http://yoursunny.com/t/2008/Wi...
    natsumi阅读 24,417评论 1 15
  • 3.1. 介绍 现在,您已经安装了Wireshark并有可能热衷于开始捕捉您的第一个数据包。在接下来的章节中,我们...
    wwyyzz阅读 1,379评论 0 1
  • 音乐若与云水相衬,每个音符也会飘逸湿润起来,那样的音乐,在流淌中将洗净沾染了灰尘的灵魂。白云在徘徊,碧水在...
    冰夫阅读 124评论 0 0
  • 一、今日工作 1.9栋承接查验,针对要求,执行检查标准对症下药,不拖拉,向行业内厉害的人学习,和有能力的人交往。 ...
    Gasin阅读 202评论 0 0