Wireshark Lua 插件教程
本⽂主要介绍 Lua 脚本在 Wireshark 中的应⽤, Lua 脚本可以在 Wireshark 中完成如下功能:
-
从⽹络包中提取数据, 或者统计⼀些数据包(
Dumper
) -
需要解析⼀种 Wireshark 不提供原⽣⽀持的协议(
Dissector
)
⽰例
协议解析
VREP
协议是 NOGD
框架对于 TRIP
协议的⼀种延伸和扩展. Wireshark 原⽣并不提供对于 VREP
协议的⽀持, 下图展⽰了脚本前后对⽐.
(a) VREP 原始字节流如下
(b) 脚本解析过后的信息
数据流提取
Wireshark 对 RTP
和 RTSP
均提供⽀持, 但是没提供对于 RTP over RTSP
协议的⽀持, 可以利⽤此处脚本提供的协议对此完成解析. 下图展⽰了这种差异.
(a) RTP over RTSP 原始信息
(b) 脚本加强解析后的信息
使⽤⽅法
假定你要使⽤ foo.lua
脚本
- 将脚本拷⻉到 Wireshark home ⽬录, 如
C:\Program\Files\Wireshark\foo.lua
- 修改
init.lua
脚本(C:\Program\Files\Wireshark\init.lua
), 在末尾添加⼀⾏dofile("foo.lua")
- 重启 Wireshark 使脚本⽣效
不同类型的脚本的使⽤⽅法:
Dissector
在选定的数据流中右击->
解码为… -> 选择脚本注册的协议, 如 RTPP.Dumper
在⼯具菜单下⾯选择注册的 dumper.(如Dump MPEG TS Packet
)
解析器(Dissector)
注册新协议
注册新协议的⼀般步骤.
-
注册新协议
- 基于 UDP 相对而⾔⽐较简单, 逐个解析 IP 包即可
- 基于 TCP 解析器⽐较复杂, 需要考虑 TCP 重组(TCP Reassembly)
-
定义协议字段
-
注册协议字段
-
定义解析函数
-
注册到协议端口号
解析器代码框架
local ror = Proto("ror", "RTP over RTSP Protocol")-- 定义协议字段
local pf_ror_magic = ProtoField.uint8("ror.magic", "Magic", base.HEX)
local pf_ror_channel = ProtoField.uint8("ror.channel", "Interleaved Channel", base.HEX)
local pf_ror_length = ProtoField.uint16("ror.length", "Length")-- 注册协议字段
ror.fields = {pf_ror_magic ,pf_ror_channel ,pf_ror_length ,
}-- 在此处定义你精妙绝伦的解析函数function ror.dissector(tvbuf, pinfo, root)-- tvbuf: TCP segment-- pinfo: packet column info-- root: node info in the display zoneend-- 指定协议端⼝, 此处是tcp 端⼝
local tcp_dissector_table = DissectorTable.get("tcp.port")
tcp_dissector_table:add(554, ror)
TCP 包重组问题
作为 tcp 解析器必须要⽤能⼒处理下⾯⼏种情况
- TCP 数据段只含有协议数据包的前⼀部分
- TCP 数据段含有多个协议数据包
- 协议数据包在 TCP 数据段的中间部分, 因为协议包的前⼀部分可能没有被捕获到
- 数据包可能有被截断的情形
- 以上⼏种情形的任意组合
对以上问题的应对策略.
- 针对 4, 简单来说就是不解析切断的包(
return 0
) - 针对 3, 解析函数必须要做⼀定的合法性检查, 如果不是属于该协议的包, 那么就丢弃该包(
return 0
) - 针对 2, 在解析函数⾥⾯做⼀个
while
循环(return 已解析的⻓度
) - 针对 1, 尽最⼤可能去确定协议数据包的⻓度, 如果不能确定, 那么就返回⼀个默认值
DESEGMENT_ONE_MORE_SEGMENT
dissector 函数的返回值如下:
- 如果 TCP 数据段携带的数据不属于当前协议, 那么返回
0
- 如果需要更多的数据才能继续解析, 那么设置
desegment_len
,desegment_offset
, 返回值为nil
或者已解析的⻓度都可以 - 如果不需要更多数据, 那么返回 nil 或者已经解析的⻓度都可以
Dumper
可以导出指定的协议字段到⽂件. 可选的字段:
- 来⾃预定义的字段(
ip.src
,tcp.port
,rtsp.length
) - ⾃定义的字段(
ror.magic
)
Dumper 代码框架
-- 定义感兴趣的字段
-- wireshark 现已⽀持的协议的字段
local mpeg_pid = Field.new("mp2t.pid")
local mpeg_pkt = Field.new("mp2t")
-- ⾃定义协议的字段
local ror_channel = Field.new("ror.channel")-- 激活对话框时候的回调
local function init_payload_dump(file, filter)local tap = Listener.new(nil, filter)-- this function is going to be called once each time our filter matchesfunction tap.packet(pinfo, tvb)-- do some fancy workendretap_packets()tap:remove()
end-- 窗⼝回调
local function begin_dialog_menu()new_dialog("Dump MPEG TS Packets", init_payload_dump, "Output file", ilter")
end-- 注册窗⼝
register_menu("Dump MPEG TS Packets", begin_dialog_menu, MENU_TOOLS_UNSORTED)
样例解析
如下是⼀些解析样例.
- VREP Dissector
- RTP Over RTSP Dissector
- MPEG Dumper
- RTP over RTSP Dumper
VREP Dissector 解析样例
这个文件比较长, 请参考我的Github Repo
RTP Over RTSP Dissector 解析样例
-- 1. declare a new type of protocol
local rtpp = Proto("rtpp", "RTP over RTSP(iPanel Flavor)")-- 2. define some field into the rtpp
local pf_rtpp_magic = ProtoField.uint8("rtpp.magic", "Magic", base.HEX)local pf_rtpp_channel = ProtoField.uint8("rtpp.channel", "Interleaved Channel", base.HEX)
local pf_rtpp_length = ProtoField.uint16("rtpp.length", "Length")-- data 就是⽆法识别净荷内容的情况下简单的将其设置为⼆进制数据的⽅法
local default_parser = Dissector.get("data")-- 3. 注册新协议拥有的字段, 这些字段可作为以后抽取数据之⽤
rtpp.fields = {pf_rtpp_magic,pf_rtpp_channel,pf_rtpp_length,
}-- 前向声明
local dissect_rtpp
local rtpp_min_len = 4-- 此处处理TCP 重传的逻辑
function rtpp.dissector(tvbuf, pktinfo, root)local segment_length = tvbuf:len()local bytes_consumed = 0local reported_len = tvbuf:reported_length_remaining()if segment_length ~= reported_len then-- captured packets are being sliced/cut-off,-- so don't try to desegment/reassemblereturn 0endwhile bytes_consumed < segment_length do-- 此处会调⽤具体的解析函数local result = dissect_rtpp(tvbuf, pktinfo, root, bytes_consumed)if result == 0 thenreturn 0elseif result > 0 thenbytes_consumed = bytes_consumed + resultelsetinfo.desegment_offset = bytes_consumedresult = -resultpktinfo.desegment_len = resultreturn segment_lengthendendreturn bytes_consumed
end-- RTP over RTSP 有基本的RTSP 协议信令也有数据流,
-- 对基本的信令⽤默认的RTSP 解析器来解析
-- 对interleaved-channel 形式的按照其载荷类型来解析
dissect_rtpp = function(tvbuf, pinfo, root, offset)local msglen = tvbuf:len() - offsetdebug("sub_buf len=" .. msglen .. ", offset=" .. offset)if msglen < rtpp_min_len thendebug("sliced packet")return - DESEGMENT_ONE_MORE_SEGMENTend-- 分类解析if tvbuf:range(offset, 1):uint() ~= 0x24 then-- 以普通的rtsp 消息来解析debug("interpret packet as normal rtsp")local rtsp_dissector = Dissector.get("rtsp")-- 此处的返回值尚不清楚, 对此的处理也⽐较幼稚rtsp_dissector:call(tvbuf:range(offset, msglen):tvb(), pinfo, root)info("ret=" .. ret)return msglenelse-- interleaved-channel 形式debug("interpret packet as interleaved channel")local len_buf = tvbuf:range(offset + 2, 2)local payload_len = len_buf:uint()local packet_len = payload_len + 4debug("rtsp packet_len=" .. packet_len .. ", payload_len load=" .. pyload_len)-- ⾄少需要4 个字节才可以区分出该包是否属于RTP over RTSP 协议if msglen < packet_len thenreturn -(packet_len - msglen)end-- 添加⼀些界⾯显⽰信息root:add(pf_rtpp_magic, tvbuf:range(offset + 0, 1))root:add(pf_rtpp_channel, tvbuf:range(offset + 1, 1))root:add(pf_rtpp_length, len_buf)offset = offset + 4-- 取净荷的第⼀个字节来区分mpeg 和rtplocal probe_byte = tvbuf:range(offset, 1):uint()debug("probe_byte=" .. string.format( "0x%x ", probe_byte))if probe_byte == 0x47 then-- 0x47 开头的就⽤mpeg 的解析器来解析debug("raw mp2t packet, offset=" .. offset .. ", payload_len=" .. payload_len)local mpeg_dissector = Dissector.get("mp2t")while (offset + 188) <= packet_len dolocal mpeg_tvb = tvbuf:range(offset, packet_len - offset):tvb()-- 暂时不知道该函数的返回值是什么情况mpeg_dissector:call(mpeg_tvb, pinfo, root)offset = offset + 188endreturn offsetelseif probe_byte == 0x80 then-- 0x80 开头的尝试⽤rtp 来解析debug("RTP packet, offset=" .. offset .. ", payload_len=" .. payload_len)local rtp_dissector = Dissector.get("rtp")local rtp_tvb = tvbuf:range(offset, payload_len):tvb()-- 同样也是对返回值的情况不太了解.rtp_dissector:call(rtp_tvb, pinfo, root)if msglen ~= packet_len thendebug("length not match, payload_len + 4=" .. packet_len.. ", msglen=" .. msglen)endreturn packet_lenelsedefault_parser(tvbuf, pinfo, root)return packet_lenendend
end-- 将RTP over RTSP 协议注册到554 端⼝
-- 需要注意的是因为调⽤了原⽣RTSP 解析器, 所以我们的解析结果并不影响普通的rtsp 解析
tcp_dissector_table:add(554, rtpp)
tcp_dissector_table:add(2554, rtpp)
info("rtpp (RTP over RTSP) protocol registed at TCP port 554")
MPEG 流抽取器
if not GUI_ENABLED thenprint("mpeg_packets_dump.lua only works in Wireshark")return
end-- 声明要抽取的字段
local mpeg_pid = Field.new("mp2t.pid")
local mpeg_pkt = Field.new("mp2t")-- 窗口回调函数
local function init_payload_dump(file, filter)local packet_count = 0-- 对任意的udp 包进⾏过滤-- filter 为符合BPF 格式的任意过滤器local tap = Listener.new(nil, filter)local myfile = assert(io.open(file, "w+b"))-- 每次BPF 过滤器过滤出⼀个ip 包就会调⽤下⾯的函数function tap.packet(pinfo, tvb)-- 检查当前包⾥⾯是否有mpeg 包if (mpeg_pid()) thenpacket_count = packet_count + 1-- dump 出所有的mpeg 包local contents = {mpeg_pkt()}-- 逐个包输出到⽂件for i, finfo in ipairs(contents) dolocal tvbrange = finfo.rangelocal subtvb = tvbrange:tvb()myfile:write(subtvb:raw())-- myfile:flush()endendend-- re-inspect all the packets that are in the current capture, thereby-- triggering the above tap.packet functionretap_packets()-- cleanupmyfile:flush()myfile:close()tap:remove()debug("Dumped mpeg packets: " .. packet_count)
endlocal function begin_dialog_menu()new_dialog("Dump MPEG TS Packets", init_payload_dump, "Output file", "Packet filter (optional)\n\nExamples:\nip.dst == 225.1.1.4\nmp2t\nmp2t.pid == 0x300")
end-- 注册到程序菜单
register_menu("Dump MPEG TS Packets", begin_dialog_menu, MENU_TOOLS_UNSORTED)
RTP over RTSP 负载抽取
local mpeg_pid = Field.new("mp2t.pid")
local mpeg_pkt = Field.new("mp2t")
local rtp_payload = Field.new("rtp.payload")local function init_payload_dump(file, filter)local packet_count = 0local real_filter = "(rtpp.channel)"if filter ~= nil and filter ~= "" then-- 拼接⽤⼾输⼊的过滤参数real_filter = real_filter .. " and (" .. filter ..")"endlocal tap = Listener.new(nil, real_filter)local myfile = assert(io.open(file, "w+b"))function tap.packet(pinfo, tvb)-- 检查是否有mpeg 数据包if (mpeg_pid()) thenlocal contents = {mpeg_pkt()}for i, finfo in ipairs(contents) dolocal tvbrange = finfo.rangelocal subtvb = tvbrange:tvb()myfile:write(subtvb:raw())endelse-- 检查是否是rtp 包local payload = rtp_payload()if payload thenlocal tvbrange = payload.rangelocal subtvb = tvbrange:tvb()myfile:write(subtvb:raw())endendendretap_packets()myfile:flush() myfile:close() tap:remove()
end
调试脚本
在命令⾏中启⽤ Wireshark, 然后可以在当前命令⾏中看到 Lua 脚本的打印输出. debug
,warn
(), info()
会输出到 Lua console
和 stdout
参考链接
- Wireshark Lua
- Lua Dissector
- Wireshark Lua Example
相关文章:

Wireshark Lua 插件教程
本⽂主要介绍 Lua 脚本在 Wireshark 中的应⽤, Lua 脚本可以在 Wireshark 中完成如下功能: 从⽹络包中提取数据, 或者统计⼀些数据包(Dumper) 需要解析⼀种 Wireshark 不提供原⽣⽀持的协议(Dissector) ⽰例 协议解析 VREP 协议是 NOGD 框架对于 TRIP 协议的⼀种延伸和扩展…...
mysql怎样优化where like ‘%字符串%‘这种模糊匹配的慢sql
一 问题描述 工作中经常遇到这种模糊匹配的慢sql: select * from 表名 where 字段 like %字符串%; 由于前面有%,导致无法走该字段上的索引。 二 解决办法 ① 给该字段创建一个全文索引 CREATE FULLTEXT INDEX 索引名 ON 表名 (字段名); ② 改写sq…...
Python代码片段-断点任务
使用Python处理一堆长耗时任务的时候,为了防止异常退出程序或者手动退出程序后丢失任务进度,可用使用断点的方式记录任务进度,下次重载任务后,继续运行上次未完成的任务即可。 这里用json文件作为数据持久化的方式,免…...

mapbox基础,使用geojson加载heatmap热力图层
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️heatmap热力图层样式二、🍀使用geojs…...

03.检测 Zabbix agent
TOC 利用 zabbix_get 工具测试 Zabbix Agent 是否正常 # 安装 zabbix-get [rootUbuntu2204 ~]#apt install -y zabbix-get# 使用zabbix_get 工具查看验证 agent 是否正常 返回1表示正常 [rootUbuntu2204 ~]#zabbix_get -s 10.0.0.110 -p 10050 -k "agent.ping"故障…...
Vue 3 + Vite 项目配置访问地址到服务器某个文件夹的解决方案
前言 在开发 Vue 3 Vite 项目时,我们经常需要将项目部署到服务器的某个特定文件夹下。例如,将项目部署到 /my-folder/ 目录下,而不是服务器的根目录。这时,我们需要对 Vite 和 Vue Router 进行一些配置,以确保项目能…...

JavaScript将:;隔开的字符串转换为json格式。使用正则表达式匹配键值对,并构建对象。多用于解析cssText为style Object对象
// 使用正则表达式匹配键值对,并构建对象 let string2Json(s)>{const r {};s.replace(/;/g, ;).replace(/\;/g, \n).replace(/:/g, :).replace(/\n/g, \n)//合并多个换行符.split(\n).forEach(item > {const [k, v] item.split(:);(k…...
MT-Metrics
MT-Metrics 是一类用于评估生成文本质量的指标,最初用于机器翻译任务,后来扩展到生成任务(如对话生成、文本摘要等)。它的核心思想是通过比较生成文本与参考文本之间的相似性(如词汇重叠、句法结构、语义相似性&#x…...

【数据结构第十六节】实现链式结构二叉树(详细递归图解—呕心沥血版!)
必须有为成功付出代价的决心,然后想办法付出这个代价。云边有个稻草人-CSDN博客 这节课挺抽象(苦笑),没事,我会帮你!干就完了! (目录在路上) 正文开始—— 引言 用链表…...
【Python爬虫(100)】从当下到未来:Python爬虫技术的进阶之路
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发…...

Vue-Flow绘制流程图(Vue3+ElementPlus+TS)简单案例
本文是vue3Elementplusts框架编写的简单可拖拽绘制案例。 1.效果图: 2.Index.vue主代码: <script lang"ts" setup> import { ref, markRaw } from "vue"; import {VueFlow,useVueFlow,MarkerType,type Node,type Edge } fro…...

CNN:卷积网络中设计1×1夹在主要卷积核如3×3前后的作用
话不多说直接上图举例: 像在 ResNet 的 Bottleneck 结构 中,1x1 卷积 被放置在 3x3 卷积 的前后,这种设计有以下几个关键作用和优势: 1. 降低计算复杂度 问题:直接使用 3x3 卷积计算量较大,尤其是当输入和…...

esp8266 rtos sdk开发环境搭建
1. 安装必要的工具 1.1 安装 Git Git 用于从远程仓库克隆代码,你可以从Git 官方网站下载 Windows 版本的安装程序。安装过程中可保持默认设置,安装完成后,在命令提示符(CMD)或 PowerShell 中输入git --version&#…...
【深度学习】矩阵的核心问题解析
一、基础问题 1. 如何实现两个矩阵的乘法? 问题描述:给定两个矩阵 A A A和 B B B,编写代码实现矩阵乘法。 解法: 使用三重循环实现标准矩阵乘法。 或者使用 NumPy 的 dot 方法进行高效计算。 def matrix_multiply(A, B):m, n …...

DeepSeek模型昇腾部署优秀实践
2024年12月26日,DeepSeek-V3横空出世,以其卓越性能备受瞩目。该模型发布即支持昇腾,用户可在昇腾硬件和MindIE推理引擎上实现高效推理,但在实际操作中,部署流程与常见问题困扰着不少开发者。本文将为你详细阐述昇腾 De…...
从 Spring Boot 2 升级到 Spring Boot 3 的终极指南
一、升级前的核心准备 1. JDK 版本升级 Spring Boot 3 强制要求 Java 17 及以上版本。若当前项目使用 Java 8 或 11,需按以下步骤操作: 安装 JDK 17:从 Oracle 或 OpenJDK 官网下载,配置环境变量(如 JAVA_HOME&…...

mysql架构查询执行流程(图解+描述)
目录 mysql架构查询执行流程 图解 描述 mysql架构查询执行流程 图解 描述 用户连接到数据库后,由连接器处理 连接器负责跟客户端建立连接、获取权限、维持和管理连接 客户端发送一条查询给服务器 服务器先检查查询缓存,如果命中缓存,则立…...

20分钟 Bash 上手指南
文章目录 bash 概念与学习目的第一个 bash 脚本bash 语法变量的使用位置参数管道符号(过滤条件)重定向符号条件测试命令条件语句case 条件分支Arrayfor 循环函数exit 关键字 bash 脚本记录历史命令查询文件分发内容 bash 概念与学习目的 bash࿰…...

事故02分析报告:慢查询+逻辑耦合导致订单无法生成
一、事故背景与现象 时间范围 2022年2月3日 18:11~18:43(历时32分钟) 受影响系统 系统名称角色影响范围dc3订单数据库主库订单生成、事务回滚dc4订单数据库从库数据同步、容灾切换 业务影响 核心业务:手机点餐、C扫B支付订单无法推送至…...
vant2 vue2 两个输入框联动验证遇到的问题
需求是两个输入框,一个输上限A,一个输下限B <van-fieldv-model"formData.upperLimit"name"upperLimit"type"number"label"上限"required:formatter"formatter"/><van-fieldv-model"for…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...