使用python计算校验和

在对数据包内容进行修改后,需要重新计算校验和。

定义源文件位置、目标文件位置

SourceFile = "E:/temp2/1.cap" NewFile = "E:/temp2/New.cap"

定义函数,用于将小端序转换为大端序

def xD(value):
    BigEndian = int.from_bytes(value[::-1], byteorder='big')
    HexAdecimal = hex(BigEndian)
    return HexAdecimal

定义函数,用于将字节数组转换为十进制整数

def BytearrayToDecimal(ByteArray):
    result = int.from_bytes(ByteArray, byteorder='big')
    return result

定义函数,用于将整数转换为字节数组

指定长度为2字节

def DecimalToBytearray(Decimal):
    result = Decimal.to_bytes(2, 'big')
    return result

定义函数用于计算校验和

之前有大哥问我TCP校验和到底都包含哪些内容,借此机会我也做了验证,TCP的校验和计算在下面,慢慢看下去。

def CalculateChecksum(Data):
    
    # 如果数据长度为奇数,补零使其为偶数
    if len(Data) % 2 != 0:
        Data += b'\x00'

    # 计算
    Checksum = 0
    for i in range(0, len(Data), 2):
        Word = (Data[i] << 8) + Data[i+1]
        Checksum += Word
        if Checksum > 0xffff:
            Checksum = (Checksum & 0xffff) + 1
            
    # 取反
    Checksum = ~Checksum & 0xffff
    
    # 转换为大端字节序
    Checksum = Checksum.to_bytes(2, byteorder='big')
    
    return Checksum

读取源.cap文件

SourceFile = open(SourceFile,'rb')

以字节数组的形式实例化源内容(字节数组可以直接修改)

BtArray = bytearray(SourceFile.read())

关闭源文件,节省内存空间

SourceFile.close()

定义第一个报文头位置索引

Index = 24

定义循环终止条件

DataLength = len(BtArray)

无限循环直至索引位置超出数组长度

while Index < DataLength:
    ## 修改报文头的时间戳高位,这里的高位数值根据实际需要修改,实现时间脱敏
    BtArray[Index+1:Index+4] = b'\x00\x00\x0F'
    # 实例化报文头
    DataDramHeader = BtArray[Index:Index+16]
    
    # 读取报文的捕获长度
    DataDramLength = int(xD(DataDramHeader[8:12]),16)

    # 报文头索引
    DataDramStart = Index + 16

    # 修改MAC地址自定义部分的前两个字节
    BtArray[DataDramStart+3:DataDramStart+6-1] = b'\x00\x00'
    BtArray[DataDramStart+6+3:DataDramStart+6+6-1] = b'\x00\x00'
    
    # 实例化以太类型
    EthType = BtArray[DataDramStart+12:DataDramStart+14]
    
    # 二层负载索引,同时也是三层头索引
    PktL2PayStart = DataDramStart + 14
    
    # 如果是ARP报文,将报文内的MAC地址和IP地址脱敏
    if EthType == b'\x08\x06':
        BtArray[PktL2PayStart+8+3:PktL2PayStart+8+6-1] = b'\x00\x00'
        BtArray[PktL2PayStart+8+6+1:PktL2PayStart+8+6+4-1] = b'\x00\x00'
        BtArray[PktL2PayStart+8+6+4+3:PktL2PayStart+8+6+4+6-1] = b'\x00\x00'
        BtArray[PktL2PayStart+8+6+4+6+1:PktL2PayStart+8+6+4+6+4-1] = b'\x00\x00'
    
    # 如果是IP报文
    elif EthType == b'\x08\x00':
        L3Start = PktL2PayStart
        Protocol = BtArray[L3Start+9:L3Start+10]
        
        # IP地址脱敏
        BtArray[L3Start+12+1:L3Start+12+4-1] = b'\x00\x00'
        BtArray[L3Start+16+1:L3Start+20-1] = b'\x00\x00'
        
        # 实例化IP首部长度
        IPHeaderLength = (BtArray[L3Start+0] & 0x0f)*4
        
        # 实例化IP总长度
        IPTotalLength = BytearrayToDecimal(BtArray[L3Start+2:L3Start+4])
        
        # 实例化IP首部
        IPHeader = BtArray[L3Start:L3Start+IPHeaderLength]
        
        # 将校验和字段设置为0
        IPHeader[10:12] = b'\x00\x00'
        
        # 重新计算IP校验和
        NewChecksum = CalculateChecksum(IPHeader)
        
        # 修改IP校验和
        BtArray[L3Start+10:L3Start+12] = NewChecksum
        
        # 实例化IP地址,用于构建伪首部
        SrcIP = BtArray[L3Start+12:L3Start+16]
        DstIP = BtArray[L3Start+16:L3Start+20]
        
        # 如果是TCP报文
        if Protocol == b'\x06':
            # 定义七层数据索引
            TcpDataOffset = (BtArray[L3Start + IPHeaderLength +12] & 0xf0)>>2
            L7Start = L3Start + IPHeaderLength + TcpDataOffset

            # 修改七层数据


            # 构建伪首部,用于计算TCP校验和
# 经过实践验证,之前昂哥问的TCP校验和计算覆盖这些内容:
# 首先是伪首部:源IP + 目的IP + 一字节0 + IP协议号 + 二字节TCP分段长度(包含TCP头和TCP负载)
            TcpLengthBtArray = DecimalToBytearray(IPTotalLength - IPHeaderLength)
            TcpPseudoHeader = SrcIP + DstIP + b'\x00' + Protocol + TcpLengthBtArray
            # 实例化分段
            Segment = BtArray[L3Start+IPHeaderLength:L3Start+IPTotalLength]
            # 分段校验和字段置0
            Segment[16:18] = b'\x00\x00'
            
            # 重新计算TCP校验和
## 然后是将伪首部与TCP分段拼接在一起,不要忘记先把原来的校验和置0
            PseudoSegment = TcpPseudoHeader + Segment
            NewChecksum = CalculateChecksum(PseudoSegment)
            # 修改TCP校验和 
            BtArray[L3Start+IPHeaderLength+16:L3Start+IPHeaderLength+18] = NewChecksum

        # 如果是UDP报文
        elif Protocol == b'\x11':
            # 定义七层数据索引
            L7Start = L3Start + IPHeaderLength + 8
            SrcPort = BtArray[L3Start+IPHeaderLength+0:L3Start+IPHeaderLength+2]
            DstPort = BtArray[L3Start+IPHeaderLength+2:L3Start+IPHeaderLength+4]
                        
            # 修改七层数据
            
                # 如果是DHCP 【TLV字段的脱敏办法容我慢慢思考】
            if SrcPort == b'\x00\x44' or SrcPort == b'\x00\x43':
                BtArray[L7Start+12+1:L7Start+16-1] = b'\x00\x00'
                BtArray[L7Start+16+1:L7Start+20-1] = b'\x00\x00'
                BtArray[L7Start+20+1:L7Start+24-1] = b'\x00\x00'
                BtArray[L7Start+24+1:L7Start+28-1] = b'\x00\x00'
                BtArray[L7Start+28+3:L7Start+34-1] = b'\x00\x00'
            else:
                pass

            # 实例化UDP数据
            UdpPart = BtArray[L3Start+IPHeaderLength:L3Start+IPTotalLength]
            # 分段校验和字段置0
            UdpPart[6:8] = b'\x00\x00'

            # 构建伪首部,并重新计算UDP校验和
            UdpPseudoHeader = SrcIP + DstIP + b'\x00' + Protocol + BtArray[L3Start+IPHeaderLength+4:L3Start+IPHeaderLength+6]
            PseudoUdpPart = UdpPseudoHeader + UdpPart
            NewChecksum = CalculateChecksum(PseudoUdpPart)
            # 修改UDP校验和 
            BtArray[L3Start+IPHeaderLength+6:L3Start+IPHeaderLength+8] = NewChecksum

    else:
        pass
    # 定义下一个报文头位置索引
    Index = Index+DataDramLength+16

修改后的数据写入目标.cap文件

with open(NewFile,'wb') as f:
    f.write(BtArray)

我就学习一下,望点赞收藏关注,谢谢。 感谢阅读!