wireshark二三事

来源:互联网 发布:都市校园网络高手小说 编辑:程序博客网 时间:2024/06/02 02:06

       wireshark被称为报文分析界的一哥,本文着眼于使用层次的,抛砖引玉,介绍一下wireshark在批量增删改查方面的应用。
       数据库都有用过,那什么是数据库呢?数据库就是数据存储的仓库,当然仅仅存储数据还是不行的。因为.txt也可存储数据,.jpg,.mp4存储的都是数据,他们不叫数据库,他们叫做数据。因此数据库的主要功能是如何将这些数据组织起来。.xls已经有了数据库的雏形,因为其数据是结构化的存储,并且提供了数据的增删改查的功能。开发者常用的数据库是mysql,如果从前面所分析的角度来看(对于数据库,只是个人的理解,可能会由不严谨之处),那么以.pcap形式存储的数据,当我们使用wireshark分析工具进行打开的时候,每一片的报文相当于数据表的每一行,wireshark针对这一片的数据报文提供可在界面显示的以及没有显示的诸多属性。同时与mysql数据表对应的,wireshark针对pcap同样提供了数据(每一片报文)的增删改查功能。那这一次就来聊一聊这方面的事情。
       wireshark查的功能,大家都是耳闻能详的,毕竟wireshark作为报文利器,提供了协议数据各个方面的信息,这里面即包括协议本身字段,还包括wireshark拓展的字段。最被大家所熟知的应该是wireshark的过滤器(expression),因为过滤条件就是协议报文的各种属性的体现。例如tcp.hdr_len 表示的是tcp协议中,tcp头部长度字段;而tcp.len所表示的是tcp上层数据长度,这个是wireshark提供的。
这次我们所讨论的查肯定不是简单的手动的输入过滤条件等,而是批量的处理,因为我知道高效的程序员都讨厌手动方式。
       说道批量的处理,有人可能会想到tshark,在这里,我对tshark的应用基于切流场景写了一个示例。但是tshark的缺点很明显,就是只能在一个pcap数据包的粒度进行操作,既然我们将wireshark比作数据库,那么针对每一片报文(相当于数据表的每一行),那也是具有相应的方法的。那么,在这里我同样通过切流操作这样的一个场景,间接介绍了wireshark在批量查方面的应用。因此本此主要说明的是wireshark在批量修改报文方面的应用,相应的可以拓展只增删改等方面。
       以一个场景为例,就是将http层的报文数据复制一份,这样在承载http那一层就存在两个一模一样的http数据了。如下图:
这里写图片描述

       新鲜出炉的lua脚本如下:

local getTcpStream = Field.new("tcp.stream")local getSrcIp = Field.new("ip.src")local getDstIp = Field.new("ip.dst")local getSrcPort = Field.new("tcp.srcport")local getDstPort = Field.new("tcp.dstport")local getIpVersion = Field.new("ip.version")local getIpLen = Field.new("ip.len")local getArrivalTime = Field.new("frame.time_epoch")local getTcpLen = Field.new("tcp.len")local tcpStreamTable = {}--每一条流的索引哈希表  local dataWriterTable = {}--每一条流的dumper表local getHttpHost = Field.new("http.host") local count = 0do    local function packet_listener()        local tap = Listener.new("frame", "tcp")        --frame是监听器的名称,tcp是wireshark过滤器规则        function tap.reset()            print("tap reset")--        end        function tap.packet(pinfo,tvb)            --回调函数,每收到一个包执行一次。            count = count + 1            local tcpStream = getTcpStream()            local srcIp = getSrcIp()            local dstIp = getDstIp()            local srcPort = getSrcPort()            local dstPort = getDstPort()            local ipVersion = getIpVersion()            local tcpStreamNumber = tonumber(tostring(tcpStream))            local ipLen = tonumber(tostring(getIpLen()))            local tcpLen = tonumber(tostring(getTcpLen()))            local arrivalTime = tonumber(tostring(getArrivalTime()))            local httpHost = getHttpHost()            if(tcpStreamTable[tcpStreamNumber])            then                if(httpHost)                then                    bytearray_fri = tvb:bytes(0,tvb:len())                    httpStartPos = (tvb:len() - tcpLen)                    --print (bytearray_fri:get_index(16))                    --print (bytearray_fri:get_index(17))                                       bytearray_sec = tvb:bytes(httpStartPos,tcpLen)                    --bytearray:__concat(bytearray_fri, bytearray_sec)                    bytearray_fri:append(bytearray_sec)                    newIplen = ipLen + tcpLen                    bytearray_fri:set_index(16,newIplen/256)                    bytearray_fri:set_index(17,newIplen%256)                    dataWriterTable[tcpStreamNumber]:dump(arrivalTime,PseudoHeader.eth(0),bytearray_fri)                else                    dataWriterTable[tcpStreamNumber]:dump_current()                end            else                local packetTuple4 = tostring(tcpStream).."_"..tostring(srcIp).."_"..tostring(srcPort).."_"..tostring(dstIp).."_"..tostring(dstPort).."_"..tostring(ipVersion)..".pcap"                oldPcapName = packetTuple4                tcpStreamTable[tcpStreamNumber] = tcpStream                dataWriterTable[tcpStreamNumber] = Dumper.new(packetTuple4)                dataWriterTable[tcpStreamNumber]:dump_current()                            --print(type(tcpStreamTable[tcpStreamNumber]),type(tcpStreamNumber),type(dataWriterTable[tcpStreamNumber]),type(tcpStreamTable))            end        end        function tap.draw()            --结束执行            print("tap draw")            --os.rename(oldPcapName,newPcapName)           end    end    --监听报文     packet_listener()end

       其中相应的接口API可以在这里查看。其中Dumper是wireshark提供的用于写pcap报文数据类型,也就说这种对象能能够构建pcap格式的文件。 Listener是wireshark提供的监听器,通过调用监听器的packet函数来处理每一片的报文数据,其中的tvb入参表示的是每一片原始报文数据,pinfo入参可以访问报文的部分属性信息。ByteArray对象可以用来对每一片报文的原始数据进行修改等操作。
       当然对于pcap报文和数据表不同的地方在于,每一片的报文都有一个归属,这个归属叫做流,也就是说每一片报文属于固定的一条流,而这条流是由五元组进行唯一确定的(源和目的IP+源和目的端口+传输层协议)。因此对于pcap报文的操作不可避免的要对流进行管理。如果使用C 语言的话,需要建立流表,但是之与lua来说。表这种结构本身就是lua提供的一种数据类型。因此在流表的管理方面非常方便,并且可以动态的增长。其中的tcpStreamTable变量就是简单的流表实现。相应的新报文命名也是流号加上五元组来进行表示的。
       当然你并不能简单的复制和拼接http层的数据,原因在于在IP层由一个字段表示的是IP及其上层数据的总长度,而wireshark会根据这个长度来显示余下的数据部分。因此如果你在该片报文上面增加数据,需要把IP层的数据长度字段要做相应的修改,不然的话,打开wireshark是看不到拼接的数据部分的。
       前面只是介绍了wireshark提供的lua API的一种应用场景,我在像切流场景以及按需切割报文等场景都有使用相关接口,效率还是非常的高。希望在我简单的介绍完为wireshark提供的接口后,你能够在处理报文的时候得心应手。
       本文为CSDN村中少年原创文章,转载记得加上小尾巴偶,博主链接这里。