DPKT - python修改数据包

20200914 -

0. 引言

翻出来很久之前的代码, 当时是测试是否可以修改PCAP包中的端口号,通过DPKT直接修改就好,例如下面的代码就是将PCAP中的一条流的端口22编程5022。

#修改端口
if tcp.dport == 22:
    tcp.dport = 5022
if tcp.sport == 22:
    tcp.sport = 5022

其实经过了这个步骤,如果你不需要校验和必须正确的话,在wireshark中是可以解析的(不开TCP校验和)。本篇文章中,记录一下怎么修改TCP内容后,同时保证校验和正确。

1. 校验和计算

IP头部中的校验和,只是校验了IP头部,并不对数据进行校验;但TCP/UDP是校验的头部加数据。校验和的公式都是一样的,都是加起来最后取反码,具体可以参考文章[1]。在TCP/UDP的计算过程中,需要加一个伪头部,然后如果整体数据是奇数的话,还需要最后补0。

2. DPKT的代码

直接上代码。

#! /usr/bin/python3
#coding:utf-8
#Auther:VChao
#2020/09/14

import dpkt
import struct 

def main():
    with open("ssh.pcap","rb") as fin:
        with open("res.pcap","wb") as fout:
            pcapin = dpkt.pcap.Reader(fin)
            pcapout = dpkt.pcap.Writer(fout)
            for ts,buf in pcapin:
                Eth = dpkt.ethernet.Ethernet(buf)
                ip = Eth.data
                tcp = ip.data
                
                #修改端口
                if tcp.dport == 22:
                    tcp.dport = 5022
                if tcp.sport == 22:
                    tcp.sport = 5022
               
                #计算伪头部 -  UDP/TCP都必须增加伪头部,
                #其中'\x00\x06'是TCP协议号,UDP为0x17
                #伪头部结构
                #   0  ------  15  ------  31
                #   |       32位源IP        |  
                #   |      32位目的IP       |
                #   |0 |8位协议 |16位TCP长度|
                #   -------------------------
                pseheader = ip.src + ip.dst + b'\x00' * 2 + b'\x00\x06' + struct.pack('>I', len(tcp))
                #将原始TCP的校验和置零  
                tcp.sum = 0
                #拿到所有的tcp数据
                all_tcp = tcp.pack()
                #如果TCP数据是奇数,要补零,但是测试中发现不加也没事,可能是底层库帮忙做了
                if len(all_tcp) % 2 != 0: all_tcp += b'\x00'
                tcp.sum = dpkt.in_cksum(pseheader + all_tcp)
                #验证校验和是否正确
                assert dpkt.in_cksum(pseheader + tcp.pack()) == 0

                ip.data = tcp
                temp = dpkt.ethernet.Ethernet(src = Eth.src, dst = Eth.dst, type= Eth.type, data = ip)
                pcapout.writepkt(temp, ts = ts)
        
if __name__ == "__main__":
    main()

经过测试,这部分代码在python2和python3都能测试成功,dpkt版本1.9.3;测试的方法就是下载了转换后的数据包,利用wireshark查看(其实代码中已经查看assert部分)。

参考

[1]校验和计算方法

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值