接上篇《C#使用SharpPcap实现监听网卡TCP请求以获取所有HTTP访问的网址》场景,我们监听到的TCP包其实已经包含了HTTP请求的所有内容,但是它们是分段的,也就是说一个网页或文件会被截断成若干个TCP包分别发送。
那么如何拼合它们?这主要用到上篇中我们转换得到TcpPacket对象:
//转换为TCP包 var packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data); var tcpPacket = TcpPacket.GetEncapsulated(packet);
先来看一下这一系列TcpPacket的数据:
tcpPacket {[TCPPacket: SourcePort=9343, DestinationPort=80, Flags={ack[2733350940 (0xa2eba01c)]|psh}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=9343, DestinationPort=80, Flags={ack[2733350940 (0xa2eba01c)]|psh}]} Ack: true AcknowledgmentNumber: 2733350940 AllFlags: 24 Checksum: 1985 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 80 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: true Rst: false SequenceNumber: 1943028315 SourcePort: 9343 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 251 tcpPacket {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} Ack: true AcknowledgmentNumber: 1943029346 AllFlags: 16 Checksum: 40291 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 9343 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: false Rst: false SequenceNumber: 2733350940 SourcePort: 80 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 258 tcpPacket {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} Ack: true AcknowledgmentNumber: 1943029346 AllFlags: 16 Checksum: 47556 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 9343 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: false Rst: false SequenceNumber: 2733352380 SourcePort: 80 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 258 tcpPacket {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} Ack: true AcknowledgmentNumber: 1943029346 AllFlags: 16 Checksum: 4517 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 9343 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: false Rst: false SequenceNumber: 2733353820 SourcePort: 80 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 258 tcpPacket {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} Ack: true AcknowledgmentNumber: 1943029346 AllFlags: 16 Checksum: 19259 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 9343 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: false Rst: false SequenceNumber: 2733355260 SourcePort: 80 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 258 tcpPacket {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} Ack: true AcknowledgmentNumber: 1943029346 AllFlags: 16 Checksum: 10010 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 9343 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: false Rst: false SequenceNumber: 2733356700 SourcePort: 80 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 258 tcpPacket {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} base {PacketDotNet.TransportPacket}: {[TCPPacket: SourcePort=80, DestinationPort=9343, Flags={ack[1943029346 (0x73d04662)]}]} Ack: true AcknowledgmentNumber: 1943029346 AllFlags: 16 Checksum: 1131 Color: "[1;33m" CWR: false DataOffset: 5 DestinationPort: 9343 ECN: false Fin: false Options: {byte[0]} OptionsCollection: null Psh: false Rst: false SequenceNumber: 2733358140 SourcePort: 80 Syn: false Urg: false UrgentPointer: 0 ValidChecksum: true ValidTCPChecksum: true WindowSize: 258
其中具有相同AcknowledgmentNumber属性值的TCP包就是可拼合的,只需要按照你获取的顺序将它们拼接起来就可以了。
而如果一系列AcknowledgmentNumber相同的TCP包能够组成一个完整的HTTP响应报文的话,那么其中第一个包的SequenceNumber值对应的是其HTTP请求报文的AcknowledgmentNumber值。(在HTTP响应报文中你得到的是服务器发回的数据,通常是页面或图片等等;在HTTP请求报文中你能找到你所请求的目标主机网址等信息)
你只需要在每次获取到TcpPacket(TCP包)对象后,执行下面的代码即可将其写入文件:
//创建续写的文件流 FileStream fs = new FileStream(tcpPacket.AcknowledgmentNumber + "_AcknowledgmentNumber.txt", FileMode.Append); ////输出为文本,并加入分段标记,使用这种方法输出的话将可以清晰的看到所有TCP包的分段情况 //StreamWriter sw = new StreamWriter(fs); //sw.WriteLine($"-----------------[{nameof(tcpPacket.SequenceNumber)}{tcpPacket.SequenceNumber}][{nameof(tcpPacket.Checksum)}{tcpPacket.Checksum}]--------------------"); //sw.WriteLine(Encoding.UTF8.GetString(tcpPacket.PayloadData)); //sw.Close(); //将源数据直接写入文件,最终将组成完整的源数据 BinaryWriter bw = new BinaryWriter(fs); bw.Write(tcpPacket.PayloadData); bw.Close(); fs.Close();
这样经过多次获取和续写,即使分段发送过来的HTTP报文,也能完整地保存到文件中了。
完整的HTTP请求看起来是这样的:
(模糊处理了Cookie值)
完整的HTTP响应看起来是这样的:
乱码是因为那部分经过了gzip压缩,需要先解压缩才能正确显示出来。
转载此文章时须注明转载自”SkyD(斯克迪亚)开发者博客“,并保留此文章的Url链接
目前还没有任何评论。