摘要
猜测头 脏数据偏移量 固定长度 端口注册
本文代码框主要包含这四个点展开的,因此如果不定长以及类似TCP那种面向连接的解析,没有呢,注意后面这个没有别看错了。
前言
首先说一下相关抓包,tcp是面向连接的,于是如果丢包或者异常等会断开,而且tcp有策略可以保证包的顺序等,因此底层仅对TCP负责,满足TCP要求的数据和TCP要求丢弃的数据。
抓包作为第三方,底层是不对抓包软件负责(这说的普通抓包,假如那种直接实现TCP的你就是TCP),他只是按要求拷贝赏赐一份数据给抓包软件,对的错的都直接拷贝丢给抓包软件,抓包的换冲区满了可能就抓包丢包了,因此抓包软件需要处理的数据量是非常大的。
在stackoverflow看过有个人问为什么抓到的包很多超时重传。有人回答了,抓包的时候会对数据量造成影响,因此存在重传包。试验过有时候抓包也存在大量重传(PS:人太懒了,想到汇编就不想看,因此还没有看linux底层代码)
因此抓包也存在一定程度的丢包。抓包分析只能通过已知的抓到包的数据推断出可能面临的问题。
这些问题强大的wireshark已经有了非常强大的分析。而我们基本需要分析的是他给我们的数据。假设《史记》是抓到的一个包,史记存在某一纪缺了部分内容,但是我们可以由前后知道,这一部分是原本存在的,只是我们抓包的时候丢了,而我们解析的时候只能学习一下句读,猜测丢失的部分哪里可以作为句子的启始继续解析,这里就是我后面代码里面的猜测起始帧 ignum 和起始帧的脏数据丢弃偏移量iglen。 整个抓包文件可能存在多次有脏包。因此可以多次重新载入。
完善后的使用方法
文件命名为xxx.lua,然后放置在wireshark/plugins/ 目录下面再重启wireshark即可。
!完善后,因此这里提供的你需要根据需求进行改造的。
要点
解析主要有bit位,单字节byte,单字节uint8,4字节unit32,字符串,这四类主要作为基础,比如3字节,你用byte和uint8,偏移量弄一下就ok了
了解一下结构,最后面的1111是端口用于注册的,你所要解析的是作为服务端的是什么端口你就写什么代替。
xjymodule_proto.dissector ---这个是解析器入口
dissect_tcp_pdus(数据区,解析树,固定头长,计算整个数据包的长度,解析这个匹配的包的函数)---这个函数能进去解析必须满足数据区提供的大于等于第3个参数的长度。
modulegetlen 包长计算,计算整个数据包的长度,即将会把这个部分用于后面的这个包的解析。
moduledissect_func 解析这个匹配的包的函数包括构建wireshark的解析树。
frameIgnPart 脏数据直接承载解析
代码结构
解析内容和字段注册并挂在-这一部分看wireshark里面的详细介绍,一些格式uint8,uint32,根据解析具体配置大端模式或小短解析。
解析入口
包具体偏移段设置和解析匹配
包长计算
主要采用C语言对比包解析部分,bit的那部分就不对比了。
2020-05-14 22:33:48
C语言粗糙样例 | 匹配lua解析粗糙样例 |
char buf[100]; char xjymodule_age ; char*off=&buf[0]; memcpy(&xjymodule_age ,off,1); off=off+1; | cstree:add(xjymodule_age , tvbuff(offset, 1)) offset=offset+1 |
char buf[100]; char word[2] ; char*off=&buf[0]; memcpy(word,off,2); off=off+2; | cstree:add(word, tvbuff(offset, 2)) offset=offset+2 |
char buf[100]; char by3[3] ; char*off=&buf[0]; memcpy(by3,off,3); off=off+3; | cstree:add(word, tvbuff(offset, 3)) offset=offset+3 |
char buf[100]; char by4[4] ; char*off=&buf[0]; memcpy(by4 ,off,4); off=off+4; | cstree:add(xjymodule_replytxt , tvbuff(offset, 4))
|
char buf[100]="test hahah"; char by4[100] ; char*off=&buf[0]; int ret=strlen(off)+1; memcpy(by4 ,off,ret); off=off+ret; | ret=tvbuff(offset):strsize() if (ret==0) then return total_len end cstree:add(xjymodule_sex , tvbuff(offset, ret)) offset=offset+ret |
--module->
--dissect_tcp_pdus重组TCP段但不是重组任意的TCP和C的tcp_dissect_pdus().不同
--https://www.wireshark.org/docs/wsdg_html_chunked/ChDissectReassemble.html#TcpDissectPdus
--https://osqa-ask.wireshark.org/questions/61447/dissect_tcp_pdus-with-truncated-segments
--[[
by Xu_Jiayu 需设置三个参数
交互数据,包有一侧起始非完整协议(当前仅一侧)
----根据.cap srcip srcport dstip dstport 查询是否有包开抓部分是否需要偏移
----Usage
local ignum frame.number is not head start
local iglen 人工猜测帧头正确偏移数据
local igts 仅一次忽略
----
未猜测设置
local ignum=-1 frame.number not head start
--]]
do
---
local ignum=200--frame.number not head start
local iglen=20--Dirty data 猜测帧头正确偏移数据
local igts=0--仅一次忽略
---
local ask_text={
[0X0]="你要吃米饭么",
[0X1]="回答米饭提问",
[0X2]="你要吃苹果么",
[0X3]="回答苹果提问",
[0X4]="你要吃榴莲么",
[0X5]="回答榴莲提问",
[0X3835]="问的序号可以跳跃只要唯一"
}
local descriptstr={
[0x0]="吃过了",
[0x1]="忌口",
[0x2]="不吃",
[0x3]="饱了",
[0x4]="穷",
[0x5]="收不了那味",
[0x6]="减肥",
[0x1111]="前面序号可以跳跃的只要唯一"
}
--创建一个新的协议结构
local xjymodule_proto= Proto("moduleCaidan", "moduleCaidan Protocol")
--失败其他协议
--local data_dis = Dissector.get("data")
--下面定义字段,其中wp.signature为wireshark中过滤条件项,signature为显示项,
--base.HEX为数值表现形式,base.HEX为十六进制,base.DEC为10进制
--filtername,name,display_type,desc,range
--base.NONE, base.DOT点分, base.DASH短横分隔, base.COLON or base.SPAC
--把前两个作为固定头 这里是8个字节,长度包括体和头
local xjymodule_length =ProtoField.uint32("moduleCaidan.length", "length", base.DEC)
local xjymodule_asktype=ProtoField.uint32("moduleCaidan.asktype", "asktype", base.HEX,ask_text)
--消息体部分
local xjymodule_payload=ProtoField.bytes("moduleCaidan.payload","Payload",base.COLON)
----消息体的解析树字段
local xjymodule_replytxt=ProtoField.uint32("moduleCaidan.replytxt","回答",base.HEX,descriptstr)
local xjymodule_name =ProtoField.string("moduleCaidan.name","名字",base.HEX)
local xjymodule_sex =ProtoField.string("moduleCaidan.sex","性别",base.HEX)
local xjymodule_age =ProtoField.uint8("moduleCaidan.age","年龄",base.DEC)
local xjymodule_symbol =ProtoField.uint8("moduleCaidan.symbol","符号",base.HEX,nil,0x3f)
--将字段解析添加到协议中
xjymodule_proto.fields = {
xjymodule_length,
xjymodule_asktype,
xjymodule_payload,
xjymodule_replytxt,
xjymodule_name,
xjymodule_sex,
xjymodule_age,
xjymodule_symbol
}
--[[
下面定义xjymodule解析器的主函数,这个函数由wireshark调用
第一个参数是Tvb类型,表示的是需要此解析器解析的数据
第二个参数是Pinfo类型,是协议解析数上的信息,包括UI上的显示
第三个参数是TreeItem类型,表示上一级解析树
返回0解析失败=false
返回消耗或解析的数量
--]]
function xjymodule_proto.dissector(tvbuff, pinfo, treeitem)
--进入TCP之前
--因为这里设定的头占8字节所以是八带进去
dissect_tcp_pdus(tvbuff,treeitem, 8, modulegetlen, moduledissect_func)
end
function frameIgnPart(pinfo,Numb,cost,tvbuff,treeitem,cur)
if pinfo.number==Numb
then
local module_tree = treeitem:add(xjymodule_proto, "ignore data")
module_tree:add(xjymodule_payload,tvbuff(cur, cost))
pinfo.cols.info:prepend(cost.." ")
return cost
end
end
--根据编写的长度预测句柄函数截取的该PUD部分的tvbuff
function moduledissect_func(tvbuff, pinfo, treeitem)
local b_offset =pinfo.desegment_offset or 0
local tvbuff_len = tvbuff:len()
pinfo.cols.info:prepend("<".."***" .. b_offset.."|"..tvbuff_len.."|"..igts.."|"..pinfo.desegment_offset..
">")
if (pinfo.number==ignum)
then
if ((b_offset==0)and(igts==1) )
then
igts=2
local retlen=frameIgnPart(pinfo,ignum,iglen,tvbuff,treeitem,b_offset)
if retlen~=0
then
return retlen
end
end
end
offset=b_offset
--开始解析头部,先长度
total_len=tvbuff(offset,4):uint()
pinfo.cols.protocol:set("xjymodule_proto")
cmid=tvbuff(offset+4, 4):uint()
local module_tree = treeitem:add(xjymodule_proto, ask_text[cmid])
module_tree:add(tvbuff(offset, 0), "------moduleCaidan banner Header------")
module_tree:add(xjymodule_length, tvbuff(offset, 4))
module_tree:add(xjymodule_asktype,tvbuff(offset+4, 4))
offset=offset+8
--设置头部打印信息
ainfo=ask_text[cmid]
pinfo.cols.info:prepend(ainfo.." ")
--如果只有头部直接一个包解析结束
if total_len==8
then
return 8
end
--开始解析体部分,先把体整体打印
local cstree=module_tree:add(xjymodule_payload, tvbuff(offset, total_len-8))
--正式解析体的部分这里我们假设只有回答苹果和回答榴莲的要解析其他不解析
if (cmid~=0X3 and cmid~=0X5)
then
return total_len
end
--解析4字节并偏移
cstree:add(xjymodule_replytxt , tvbuff(offset, 4))
offset=offset+4
--解析字符串即用null结尾的,先计算长度
ret=tvbuff(offset):strsize()--include'\0'
if (ret==0)
then
return total_len
end
cstree:add(xjymodule_name , tvbuff(offset, ret))
offset=offset+ret
--解析性别
ret=tvbuff(offset):strsize()--include'\0'
if (ret==0)
then
return total_len
end
cstree:add(xjymodule_sex , tvbuff(offset, ret))
offset=offset+ret
--解析1字节的年龄
cstree:add(xjymodule_age , tvbuff(offset, 1))
offset=offset+1
--1111 1111一个字节,但是要解析的在高到低的第2-8bit位
bitsymbol=tvbuff(offset, 1):bitfield(2,8)
if 0x08==bitsymbol
then
cstree:add( xjymodule_symbol,tvbuff(offset, 1))
else
cstree:add( xjymodule_symbol,tvbuff(offset, 1))
end
return total_len
end
--当前包括上次分片的剩余未解析合成的tvbuff ,offset_1为该tvbuff的偏移
function modulegetlen(tvbuff, pinfo, offset_1)
local tvbuff_len=tvbuff:len()
if (pinfo.number==ignum)
then
local remaining=tvbuff_len-offset_1
if offset_1 ==0
then
igts=1
if iglen>remaining
then
return remaining
end
return iglen
end
end
local pdulen=tvbuff(offset_1,4):uint()
return pdulen
end
--向wireshark注册协议插件被调用的条件
local tcp_port_table = DissectorTable.get("tcp.port")
tcp_port_table:add(1111, xjymodule_proto)
end