Wireshark解析器(Dissector)插件-Lua


前言

如果直接使用Wireshark查看Http等协议报文,并不会有任何不便,

但是如果查看私有协议报文,无法区分哪些是TCP协议相关报文,哪些是含有消息体的私有协议报文,也只能看到一串Byte和对应ASCII编码的Data值,无法知道数据中的各个字节对应哪个字段代表什么含义,更不能根据这些对应字段值进行过滤


一、解析器(Dissector)是什么?

解析器(Dissector)是Wireshark中的概念,用于解析协议,将报文中对应的Bytes转为相应的字段值

可以简单理解为Wireshark中的解码器。

它不只能解析将相应位置的Bytes转为对应字段,还能将解析出来的字段用于报文过滤,还能自定义信息(Info)列中显示的自定义信息。

能方便开发人员调试诊断协议相关问题,比如断连后不重连,报文不正确,未发心跳。

解析器可以使用C语言编写,也可以使用Lua编写

本篇使用Lua编写,因为该语言是脚本语言,不需要编译后执行,方便开发修改调试

缺点是比C语言编写的解析器慢

二、编写流程

1.添加解析器插件文件

  • 在%APPDATA%\Wireshark 中新建文件夹plugins ,可以使用Win+R 键然后输入%APPDATA%\Wireshark然后回车,快速打开该目录
  • 在plugins 文件夹下新建xxx.lua 文件,其中xxx 一般以协议名为文件名

2.解析器由什么部分组成

  • 协议定义
  • 字段定义
  • 协议和字段关联
  • 解析器主函数
  • 协议注册

3. 解析器代码详解

-- 协议定义,名称为ScoreBoard,在Packet Details窗格显示为ScoreBoard Protocol
local p_ScoreBoard = Proto('ScoreBoard', 'ScoreBoard Protocol')

-- 协议的各个字段定义
local f_identifier = ProtoField.bytes('ScoreBoard.identifier', 'Identifier')
local f_operator =
    ProtoField.uint8(
    'ScoreBoard.operator',
    'Operator',
    base.HEX,
    -- 这个字段的数字值都有相应的含义,可以自动对应成字符串
    {
        [0] = 'get-value',
        [1] = 'set-value',
        [128] = 'resp-value',
        [16] = 'get-color',
        [17] = 'set-color',
        [144] = 'resp-color'
    }
)
-- 所有可能的字段都要定义,到时没有t:add就不会显示
local f_left = ProtoField.uint32('ScoreBoard.left', 'Value Left', base.DEC)
local f_right = ProtoField.uint32('ScoreBoard.right', 'Value Right', base.DEC)
local f_red = ProtoField.uint8('ScoreBoard.red', 'Color Red', base.DEC)
local f_green = ProtoField.uint8('ScoreBoard.green', 'Color Green', base.DEC)
local f_blue = ProtoField.uint8('ScoreBoard.blue', 'Color Blue', base.DEC)

-- 将字段添加到协议中
p_ScoreBoard.fields = {
    f_identifier,
    f_operator,
    f_left,
    f_right,
    f_red,
    f_green,
    f_blue
}

-- 获取Wireshark自带的Data解析器
-- 后续解析发现不是有效报文需要调用该解析器显示报文数据
local data_dis = Dissector.get('data')

local function ScoreBoard_dissector(buf, pkt, root)
    local buf_len = buf:len()
    -- 先检查报文长度,太短的不是我的协议
    if buf_len > 17 then
        return false
    end
    -- 取得前16字节identifier字段的值
    local v_identifier = buf(0, 16)
    -- 验证identifier是否正确
    if
        ((buf(0, 1):uint() ~= 226) or (buf(1, 1):uint() ~= 203) or (buf(2, 1):uint() ~= 181) or
            (buf(3, 1):uint() ~= 128) or
            (buf(4, 1):uint() ~= 203) or
            (buf(5, 1):uint() ~= 9) or
            (buf(6, 1):uint() ~= 78) or
            (buf(7, 1):uint() ~= 186) or
            (buf(8, 1):uint() ~= 163) or
            (buf(9, 1):uint() ~= 107) or
            (buf(10, 1):uint() ~= 246) or
            (buf(11, 1):uint() ~= 7) or
            (buf(12, 1):uint() ~= 206) or
            (buf(13, 1):uint() ~= 149) or
            (buf(14, 1):uint() ~= 63) or
            (buf(15, 1):uint() ~= 43))
     then -- 不正确就不是我的协议
        return false
    end
    -- 取得operator的值
    local v_operator = buf(16, 1)
    local i_operator = v_operator:uint()

    -- 现在知道是我的协议了,放心大胆添加Packet Details
    local t = root:add(p_ScoreBoard, buf)
    -- 在Packet List窗格的Protocol列也可以"做个小广告"
    pkt.cols.protocol = 'ScoreBoard'
    t:add(f_identifier, v_identifier)
    t:add(f_operator, v_operator)

    if ((i_operator == 1) or (i_operator == 128)) and (buf_len >= 25) then
        -- 把存在的字段逐个添加进去
        t:add(f_left, buf(17, 4))
        t:add(f_right, buf(21, 4))
    elseif ((i_operator == 17) or (i_operator == 144)) and (buf_len >= 20) then
        t:add(f_red, buf(17, 1))
        t:add(f_green, buf(18, 1))
        t:add(f_blue, buf(19, 1))
    end
    return true
end

--[[
    下面定义 foo 解析器的主函数,这个函数由 wireshark调用
    第一个参数是 Tvb 类型,表示的是需要此解析器解析的数据
    第二个参数是 Pinfo 类型,是协议解析树上的信息,包括 UI 上的显示
    第三个参数是 TreeItem 类型,表示上一级解析树
--]]
function foo_proto.dissector(tvb, pinfo, treeitem)
    -- 设置一些UI中报文列表中Proto列和Info列显示的信息
    pinfo.cols.protocol:set('FOO')
    pinfo.cols.info:set('Foo Protocol')

    if ScoreBoard_dissector(buf, pkt, root) then
        -- 如果是有效的报文
    else
        -- 当发现不是我的协议时,就使用Wiresahrk自带的Data解析器显示
        data_dis:call(buf, pkt, root)
    end
end

-- 向 wireshark 注册协议插件被调用的条件为TCP协议且端口为12345的报文
-- 符合条件就会调用上面的foo_proto.dissector函数
-- local udp_port_table = DissectorTable.get("udp.port")
local tcp_port_table = DissectorTable.get('tcp.port')
tcp_port_table:add(12345, foo_proto)


三、调试

1. 重新加载脚本

  • 修改Lua 脚本
  • 在Wireshark 中使用Ctrl+Shift+L 快捷键重新加载修改后的Lua 脚本

2. 查看控制台输出

  • Lua 脚本中print(VariableName) 在控制台输出对应变量值
  • Edit 编辑 -> Preferences… 首选项(Ctrl+Shif+P ) -> Advanced 高级
  • 搜索gui.console_open 并将对应值修改为 ALWAYS

3. 如何使用

  • 在%APPDATA%\Wireshark 中新建文件夹plugins ,可以使用Win+R 键然后输入%APPDATA%\Wireshark然后回车,快速打开该目录
  • 复制编写好的脚本到该文件夹%APPDATA%\Wireshark\plugins
  • 重新打开抓包文件或者Ctrl+Shift+L 快捷键重新加载插件脚本

四、进阶

1. 不绑定端口怎么办?

启发式解析器
在 Lua 中创建独立于端口(启发式)的 Wireshark 解调器|米卡的技术博客 (mika-s.github.io)
wireshark/README.heuristic at master - wireshark/wireshark (github.com)

2. 粘包,分包问题

粘包使用while 循环处理

分包设置pinfo.desegment_len 的值或者使用dissect_tcp_pdus 函数

使用 lua 编写 wireshark 协议解析插件
Functions For New Protocols And Dissectors

3. 大端(Big End)小端(Little End)问题

Wireshark中默认是大端,如果需要处理小端协议,可以将add 函数替换为add_le 的函数


参考

Lua语法

Lua 5.2 Reference Manual - contents

教程

用Lua语言编写Wireshark dissector插件 (archive.org)

Creating a Wireshark dissector in Lua - part 1 (the basics) | Mika’s tech blog (mika-s.github.io)

强烈推荐:Mika’s tech blog (mika-s.github.io)

Wireshark Dissector文档

Dissectors (wireshark.org)

10.3. Example: Dissector written in Lua (wireshark.org)

Chapter 11. Wireshark’s Lua API Reference Manual

11.7. Adding Information To The Dissection Tree (wireshark.org)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Wireshark支持使用Lua脚本进行协议解析。要添加Lua解析器,请按照以下步骤操作: 1. 安装Lua环境。Wireshark需要使用Lua 5.1或更高版本。可以从Lua的官方网站下载安装程序并按照说明进行安装。 2. 找到Wireshark插件目录。在Wireshark的菜单中,选择“帮助”->“关于Wireshark”,然后单击“文件夹”按钮,即可打开插件目录。 3. 创建一个新的Lua插件。在插件目录中创建一个新的目录,例如“my_lua_plugin”。 4. 创建一个Lua脚本。在新创建的目录中创建一个名为“my_protocol.lua”的文件,并将以下代码复制到该文件中: ``` -- my_protocol.lua -- declare our protocol my_protocol = Proto("my_protocol", "My Protocol") -- create a function to dissect it function my_protocol.dissector(buffer, pinfo, tree) -- add protocol name to protocol column pinfo.cols.protocol = "MY_PROTO" -- create a subtree for our protocol subtree = tree:add(my_protocol, buffer(), "My Protocol Data") -- add fields to the subtree subtree:add(buffer(0,1), "Field 1") subtree:add(buffer(1,1), "Field 2") end -- register our protocol tcp_table = DissectorTable.get("tcp.port") tcp_table:add(1234, my_protocol) ``` 这个脚本定义了一个名为“my_protocol”的协议,并使用“tcp.port”表将其注册到TCP端口1234上。在协议分析器中,它将显示为“My Protocol”。 5. 启用Lua插件。在Wireshark的菜单中,选择“编辑”->“首选项”,然后选择“协议”->“Lua”。单击“+”按钮,然后选择新创建的插件目录。确保选中“启用”复选框,然后单击“应用”和“确定”。 6. 使用Lua解析器。现在,当Wireshark捕获到使用TCP端口1234发送的数据包时,它将调用my_protocol.dissector()函数来解析该协议,并显示解析结果。 这只是一个简单的示例,可以根据需要进行修改和扩展。更多信息,请参阅WiresharkLua API文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值