wireshark protobuf lua插件开发

wireshark protobuf lua插件是指使用wireshark针对lua语言的插件支持,通过lua语言开发针对自定义的protobuf协议的插件,在wireshark中将protobuf格式数据转换为明文数据;

如下文章参考wireshark官方文档,测试数据也均来自官方文档提供,如存在纰漏或对文章存在疑问,欢迎讨论,也可跳转至最后参考文档处,自行参考官方文档,一切请以官方文档为准;

1.配置用户proto文件读取路径

在wireshark中配置用户定义或google官方proto文件读取路径;

1.1. 进入protobuf路径设置菜单
编辑-》首选项-》protocols-》protobuf
protobuf文件读取路径
1.2. 编辑protobuf search paths
如果用户在proto文件中import了官方提供的标准proto文件,则需要配置官方文件的加载目录,官方标准proto文件导入语法如下:

syntax = "proto3";
package tutorial;
import "google/protobuf/timestamp.proto";

官方标准的proto文件一般在下载protoc项目时,include目录下
protobuf官方proto文件
点击Protobuf search paths后的Edit按钮;
wireshark proto文件加载路径设置如下图:
wireshark proto文件加载路径设置
1.3. protobuf 其他相关设置勾选设置

2.在上述配置的目录下准备proto文件

这里以官方给出的为实例:
将如下内容保存为xx.proto文件后,放置如第1步中设置的用户proto文件加载路径中;

syntax = "proto3";
package tutorial;
import "google/protobuf/timestamp.proto";

message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phone = 4;
  google.protobuf.Timestamp last_updated = 5;
  bytes portrait_image = 6;
}

message AddressBook {
  repeated Person people = 1;
}

3.编写lua插件脚本

如果protobuf数据通过UDP传输,则无需写对应的插件,wireshark可默认支持解析,直接跳转到:第5步:数据查看;

由于UDP是无连接的,所以一次数据传输的就是一个完整的protobuf数据;而TCP协议是有连接的,这里可能存在诸如确认包等等数据,所以需要写插件,将对应的非protobuf定义的数据进行过滤掉,然后通过wireshark对protobuf数据的解析功能进行解析;如下脚本重点解决的便是TCP传输过程中,将非protobuf数据去除,然后过滤出完整的protobuf数据,传输给wireshark解析器;

阅读脚本前,先了解下官方文档给出的实验数据是如何工作的(此处仅分析TCP协议):
Wireshark TCP实验数据包下载路径
Wireshark UDP实验数据包下载地址
3.1. 下载并查看TCP实验数据
首先根据握手包追踪完整的流
追踪TCP流
查看数据通信流程
TCP通信流程
通过上述数据可以看出,在握手成功后的数据发送阶段,51151端口发送数据给18127端口,每次发送protobuf数据时中间会间隔发送4字节的非protobuf数据,所以在编写lua插件时,需要将对应的4字节数据进行去除;

3.2. 编写lua插件
详细实现脚本如下:

-- 文件名: create_protobuf_dissector.lua

do
    -- 解析器的一个引用, 用于针对一个数据包或该数据包的一部分调用解析器;
    -- 参数: name 该解析器的名称;
    -- 返回值: 如果通过名称检索到了该解析器,则返回其的一个引用,否则返回nil;
    local protobuf_dissector = Dissector.get("protobuf")

    -- Create protobuf dissector based on UDP or TCP.
    -- The UDP dissector will take the whole tvb as a message.
    -- The TCP dissector will parse tvb as format:
    --         [4bytes length][a message][4bytes length][a message]...
    -- @param name  The name of the new dissector.
    -- @param desc  The description of the new dissector.
    -- @param for_udp  Register the new dissector to UDP table.(Enable 'Decode as')
    -- @param for_tcp  Register the new dissector to TCP table.(Enable 'Decode as')
    -- @param msgtype  Message type. This must be the root message defined in your .proto file.
    local function create_protobuf_dissector(name, desc, for_udp, for_tcp, msgtype)
        -- 创建或定义协议,可以用于定义协议名,协议描述,类型等等
        local proto = Proto(name, desc)
        -- 展示协议长度: ProtoField.uint32(name, desc, [base], [mask], [presence], [epan_field_type])
        -- name: 表示协议字段的名称
        -- desc: 表示协议字段的描述
        -- base: 表示数据进制,默认16进制,DEC: 十进制
        local f_length = ProtoField.uint32(name .. ".length", "Length", base.DEC)
        -- 定义协议字段
        proto.fields = { f_length }
        
        -- 匿名函数写法,用于定义Wireshark Lua协议解析器的主要功能。它指定了一个函数,用于解析数据包并显示其内容。
        -- tvb参数是数据包的缓冲区
        -- pinfo参数是有关数据包的信息(例如时间戳、协议类型等)
        -- tree参数是Wireshark窗口中的树形结构。解析器将使用这些参数来解析数据包。
        proto.dissector = function(tvb, pinfo, tree)
            local subtree = tree:add(proto, tvb())
            if for_udp and pinfo.port_type == 3 then -- UDP
                if msgtype ~= nil then
                    pinfo.private["pb_msg_type"] = "message," .. msgtype
                end
                -- 捕获执行函数的错误,pcall(function, arg[, arg1[, arg2]])
                pcall(Dissector.call, protobuf_dissector, tvb, pinfo, subtree)
            elseif for_tcp and pinfo.port_type == 2 then -- TCP
                local offset = 0
                local remaining_len = tvb:len()
				-- 使用一个循环,将TCP流数据进行切割处理
                while remaining_len > 0 do
                    if remaining_len < 4 then -- head not enough
                        pinfo.desegment_offset = offset
                        pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
                        return -1
                    end

                    local data_len = tvb(offset, 4):uint()

                    if remaining_len - 4 < data_len then -- data not enough
                        pinfo.desegment_offset = offset
                        pinfo.desegment_len = data_len - (remaining_len - 4)
                        return -1
                    end
                    subtree:add(f_length, tvb(offset, 4))

                    if msgtype ~= nil then
                        pinfo.private["pb_msg_type"] = "message," .. msgtype
                    end
                    pcall(Dissector.call, protobuf_dissector, 
                           tvb(offset + 4, data_len):tvb(), pinfo, subtree)

                    offset = offset + 4 + data_len
                    remaining_len = remaining_len - 4 - data_len
                end
            end
            pinfo.columns.protocol:set(name)
        end

        if for_udp then DissectorTable.get("udp.port"):add(0, proto) end
        if for_tcp then DissectorTable.get("tcp.port"):add(0, proto) end
        return proto
    end

    -- default pure protobuf udp and tcp dissector without message type
    create_protobuf_dissector("protobuf_udp", "Protobuf UDP")
    create_protobuf_dissector("protobuf_tcp", "Protobuf TCP")
    -- add more protobuf dissectors with message types
    create_protobuf_dissector("AddrBook", "Tutorial AddressBook", true, true, "tutorial.AddressBook")
end

4.将插件脚本放入wireshark的个人插件目录下

4.1. 插件目录查找
进入菜单:帮助-》关于wireshark-》文件夹
插件目录查找

5.解析捕获网络文件的内容

5.1. 打开对应的抓包文件后,找到对应的protobuf数据,右键点击decodes as
protbuf文件解析操作
5.2. 选择注册的协议名-ADDRBOOK
选择注册的协议名
5.3. 查看解析后的数据
在这里插入图片描述

参考资料

Protobuf - Wireshark

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值