Wireshark解析器(Dissector)插件-Lua

现有问题

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

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

什么是解析器(Dissector)

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

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

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

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

编写流程

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

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

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

编写解析器需要使用lua 语言 所以建议先学一点基础,或者碰到看不懂的再查也行

Lua基础知识请参考

添加解析器插件文件#

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

解析器由什么部分组成#

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

解析器代码详解#

-- 协议定义,名称为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(016)
    -- 验证identifier是否正确
    if
        ((buf(01):uint() ~= 226or (buf(11):uint() ~= 203or (buf(21):uint() ~= 181or
            (buf(31):uint() ~= 128or
            (buf(41):uint() ~= 203or
            (buf(51):uint() ~= 9or
            (buf(61):uint() ~= 78or
            (buf(71):uint() ~= 186or
            (buf(81):uint() ~= 163or
            (buf(91):uint() ~= 107or
            (buf(101):uint() ~= 246or
            (buf(111):uint() ~= 7or
            (buf(121):uint() ~= 206or
            (buf(131):uint() ~= 149or
            (buf(141):uint() ~= 63or
            (buf(151):uint() ~= 43))
     then -- 不正确就不是我的协议
        return false
    end
    -- 取得operator的值
    local v_operator = buf(161)
    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 == 1or (i_operator == 128)) and (buf_len >= 25then
        -- 把存在的字段逐个添加进去
        t:add(f_left, buf(174))
        t:add(f_right, buf(214))
    elseif ((i_operator == 17or (i_operator == 144)) and (buf_len >= 20then
        t:add(f_red, buf(171))
        t:add(f_green, buf(181))
        t:add(f_blue, buf(191))
    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)

如何调试

重新加载脚本#

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

查看控制台输出#

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

如何使用

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

高级

  • 不绑定端口怎么办?

启发式解析器

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

wireshark/README.heuristic at master - wireshark/wireshark (github.com)

  • 粘包,分包问题

粘包使用while 循环处理

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

使用 lua 编写 wireshark 协议解析插件_mb5fe55a9dbe9dd的技术博客_51CTO博客

11.6. Functions For New Protocols And Dissectors (wireshark.org)

  • 大端(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)


原文链接:https://www.cnblogs.com/KSPT/p/16688475.html

作者:KSPT

出处:https://www.cnblogs.com/KSPT/p/wireshark-dissector.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   知科行技  阅读(3943)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu