接上篇《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请求看起来是这样的:

image

(模糊处理了Cookie值)

完整的HTTP响应看起来是这样的:

image

乱码是因为那部分经过了gzip压缩,需要先解压缩才能正确显示出来。

转载此文章时须注明转载自”SkyD(斯克迪亚)开发者博客“,并保留此文章的Url链接

作者信息

昵称
斯克迪亚

查看其所发布的所有文章

总积分
2420
注册时间
(2018年5月4日 19:06)

评论

目前还没有任何评论。

[切换到移动版页面]