1.操作步骤:
1.1 服务器端安装rpcapd程序
1.2 本地Wireshark安装和配置
1.3 自定义应用层协议解析
1.1 服务器端安装rpcapd程序
①安装glibc程序,C运行库
redhat/centos系列安装
sudo yum install glibc-static
debian/ubuntu系列安装
sudo apt-get install libc6-dev
② 下载rpcapd安装包,也可以官网下载
wget http://www.winpcap.org/install/bin/WpcapSrc_4_1_2.zip
unzip WpcapSrc_4_1_2.zip
③ 编译rpcapd
cd winpcap/wpcap/libpcap
chmod +x configure runlex.sh
CFLAGS=-static ./configure
make
cd rpcapd && make
④ 运行rpcapd
./rpcapd -n -d
⑤ 检查rpcapd运行状态
netstat -nltp|grep rpcapd
查看端口和进程是否正常,默认端口2002
1.2 本地Wireshark安装和配置
①安装wireshark程序
②配置远程捕获接口(可以此时设置捕获过滤器条件)
③查看效果
1.3 自定义应用层协议解析
①Wireshark上配置Lua脚本插件地址
②Lua脚本文件如下packet-dt.lua(解析器表部分根据自己需要监听的UDP端口更改):
do
local proto = Proto("SRUDP","Stream Rapid UDP")
--协议的各个字段
local f_protocol = ProtoField.uint32("SRUDP.protocol","Protocol", base.DEC)
local f_version = ProtoField.uint32("SRUDP.version","Version", base.DEC)
local f_msgCode = ProtoField.uint32("SRUDP.msgCode","MsgCode", base.DEC)
local f_msgType = ProtoField.string("SRUDP.msgType","MsgType", base.UTF8)
local f_connectId = ProtoField.uint64("SRUDP.connectId","ConnectId", base.DEC)
local f_msgSeq = ProtoField.uint32("SRUDP.msgSeq","MsgSeq", base.DEC)
local f_streamHash = ProtoField.uint64("SRUDP.streamHash","StreamHash", base.DEC)
local f_tsIdx = ProtoField.uint32("SRUDP.tsIdx","TsIdx", base.DEC)
local f_piecesCount = ProtoField.uint32("SRUDP.piecesCount","PiecesCount", base.DEC)
local f_pieceSeq = ProtoField.uint32("SRUDP.pieceSeq","PieceSeq", base.DEC)
local f_timestamp = ProtoField.uint64("SRUDP.timestamp","Timestamp", base.DEC)
local f_payloadEncrypt = ProtoField.uint16("SRUDP.payloadEncrypt","PayloadEncrypt", base.DEC)
local f_payloadType = ProtoField.uint16("SRUDP.payloadType","PayloadType", base.DEC)
local f_payloadLength = ProtoField.uint32("SRUDP.payloadLength","PayloadLength", base.DEC)
local f_requestParams = ProtoField.string("SRUDP.requestParams","RequestParams", base.UTF8)
local f_body = ProtoField.bytes("SRUDP.body","Body")
--这里把DT协议的全部字段都加到proto这个变量的fields字段里
proto.fields = {
f_protocol,
f_version,
f_msgCode,
f_msgType,
f_connectId,
f_msgSeq,
f_streamHash,
f_tsIdx,
f_piecesCount,
f_pieceSeq,
f_timestamp,
f_payloadEncrypt,
f_payloadType,
f_payloadLength,
f_requestParams,
f_body
}
local function SRUDP_dissector(buf,pkt,root)
local buf_len = buf:len();
--先检查报文长度,太短的不是我的协议
if buf_len > 1388 then return false end
--验证一下identifier这个字段是不是0x12,如果不是的话,认为不是我要解析的packet
local v_protocol = buf(0, 4)
local v_version = buf(4, 4)
local v_msgCode = buf(8, 4)
local v_msgType
local v_code = v_msgCode:uint()
if(v_code == 1000)
then
v_msgType = 'SUBSCRIBE_AND_LOGIN'
elseif(v_code == 1001)
then
v_msgType = 'SUBSCRIBE_ACK'
elseif(v_code == 1002)
then
v_msgType = 'UNSUBSCRIBE'
elseif(v_code == 1100)
then
v_msgType = 'NOTIFY_INDEX'
elseif(v_code == 1101)
then
v_msgType = 'INDEX_REQUEST'
elseif(v_code == 1200)
then
v_msgType = 'BLOCK_PUSH_RESPONSE'
elseif(v_code == 1201)
then
v_msgType = 'BLOCK_REQUEST'
elseif(v_code == 1300)
then
v_msgType = 'HEARTBEAT_REQUEST'
elseif(v_code == 1301)
then
v_msgType = 'HEARTBEAT_RESPONSE'
else
v_msgType = 'UNKNOWN_MSG'
end
local v_connectId = buf(12, 8)
local v_msgSeq = buf(20, 4)
local v_streamHash = buf(24, 8)
local v_tsIdx = buf(32, 4)
local v_piecesCount = buf(36, 4)
local v_pieceSeq = buf(40, 4)
local v_timestamp = buf(44, 8)
local v_payloadEncrypt = buf(52, 2)
local v_payloadType = buf(54, 2)
local v_payloadLength = buf(56, 4)
local v_requestParams;
local v_body;
if(buf_len<1000)
then
v_requestParams = buf(60, buf_len-60)
else
v_body = buf(60, buf_len-60)
end
--现在知道是我的协议了,放心大胆添加Packet Details
local t = root:add(proto,buf)
--在Packet List窗格的Protocol列可以展示出协议的名称
pkt.cols.protocol = "SRUDP"
--这里是把对应的字段的值填写正确,只有t:add过的才会显示在Packet Details信息里. 所以在之前定义fields的时候要把所有可能出现的都写上,但是实际解析的时候,如果某些字段没出现,就不要在这里add
t:add(f_protocol,v_protocol)
t:add(f_version,v_version)
t:add(f_msgCode,v_msgCode)
t:add(f_msgType,v_msgType)
t:add(f_connectId,v_connectId)
t:add(f_msgSeq,v_msgSeq)
t:add(f_streamHash,v_streamHash)
t:add(f_tsIdx,v_tsIdx)
t:add(f_piecesCount,v_piecesCount)
t:add(f_pieceSeq,v_pieceSeq)
t:add(f_timestamp,v_timestamp)
t:add(f_payloadEncrypt,v_payloadEncrypt)
t:add(f_payloadType,v_payloadType)
t:add(f_payloadLength,v_payloadLength)
if(buf_len<1000)
then
t:add(f_requestParams,v_requestParams)
else
t:add(f_body,v_body)
end
return true
end
--这里是获取data这个解析器
local data_dis = Dissector.get("data")
--这段代码是目的Packet符合条件时,被Wireshark自动调用的,是proto的成员方法
function proto.dissector(buf,pkt,root)
if SRUDP_dissector(buf,pkt,root) then
else
--data这个dissector几乎是必不可少的;当发现不是我的协议时,就应该调用data
data_dis:call(buf,pkt,root)
end
end
local udp_encap_table = DissectorTable.get("udp.port")
--因为我们的DT协议的接受端口肯定是50002,所以这里只需要添加到"udp.port"这个DissectorTable里,并且指定值为50002即可。
udp_encap_table:add(33188, proto)
udp_encap_table:add(8891, proto)
end
③Lua脚本文件每次更新需要重新载入Lua插件
④效果查看
⑤现在可以实时解析远程服务器的发包收包情况了,同时可以自行解析应用层协议。优化点如下:
1)监听接口时,精细化捕获过滤器条件,这样会减少解析包的数量。
2)精细化显示过滤器条件,更专注于自定义协议解析。如只展示srudp协议
3)优化lua脚本,当前使用udp.port解析器表来匹配自定义解析器,需要手动配置关联监听的UDP端口号,每次都需要手动关联并重新加载Lua插件。寻找一种更方便的匹配方式。
4)Wireshark包解析界面,展示应用层消息类型和消息序号至主界面,对发包收包分别着色展示。