使用Scapy发送PCAP数据包时,如何使应用层数据与原始文件一致?
问题描述
我使用Scapy读取PCAP数据包并修改头部后发送至服务器,代码如下:
print(f"sending pcap packets to {self.dst_ip}:{self.dst_port}") packs = scp.rdpcap(self.pcap) new_src_mac = get_mac_address(ip="0.0.0.0") new_dst_mac = self.dstmac for pkt in packs: pkt[scp.Ether].src = new_src_mac pkt[scp.Ether].dst = new_dst_mac pkt[scp.IP].src= self.src_ip pkt[scp.IP].dst= self.dst_ip pkt[scp.TCP].sport = self.src_port pkt[scp.TCP].dport = self.dst_port pkt[scp.TCP].ack = ack_num pkt[scp.TCP].seq = seq_num scp.sendp(pkt, iface=self.iface)
发送后通过Wireshark抓包发现,发送的数据包应用层数据显示为十六进制格式,但原始PCAP文件中的数据包并非如此。请问如何发送出与原始文件格式一致的数据包?
解决方法
问题根源在于Scapy修改TCP/IP头部后,会自动重构数据包结构,导致应用层载荷被处理为原始字节(Wireshark默认显示为十六进制),而非原始PCAP中被识别为特定协议的格式。可以通过以下步骤解决:
- 禁用自动校验和计算,保留原始载荷
Scapy默认会重新计算IP和TCP的校验和,可能干扰数据包结构。修改代码时手动处理校验和,同时固定应用层载荷:
print(f"sending pcap packets to {self.dst_ip}:{self.dst_port}") packs = scp.rdpcap(self.pcap) new_src_mac = get_mac_address(ip="0.0.0.0") new_dst_mac = self.dstmac for pkt in packs: # 保存原始TCP应用层载荷 original_payload = pkt[scp.TCP].payload # 修改链路层头部 pkt[scp.Ether].src = new_src_mac pkt[scp.Ether].dst = new_dst_mac # 修改IP头部,删除原有校验和让Scapy重新计算 pkt[scp.IP].src = self.src_ip pkt[scp.IP].dst = self.dst_ip del pkt[scp.IP].chksum # 修改TCP头部,删除原有校验和,设置序列号和确认号 pkt[scp.TCP].sport = self.src_port pkt[scp.TCP].dport = self.dst_port pkt[scp.TCP].ack = ack_num pkt[scp.TCP].seq = seq_num del pkt[scp.TCP].chksum # 恢复原始应用层载荷 pkt[scp.TCP].payload = original_payload # 发送数据包 scp.sendp(pkt, iface=self.iface)
- 强制用Raw层包裹原始载荷
如果Scapy仍自动解析载荷,可将原始载荷转为Raw类型,避免被重新解析:
for pkt in packs: # 提取原始载荷的字节数据 raw_payload = bytes(pkt[scp.TCP].payload) # 执行所有头部修改操作... # 用Raw层包裹原始载荷 pkt[scp.TCP].payload = scp.Raw(load=raw_payload) scp.sendp(pkt, iface=self.iface)
- 检查Wireshark解码设置
有时并非数据包本身问题,而是Wireshark未正确识别应用层协议。可在Wireshark中右键点击目标数据包,选择「解码为」,手动指定对应应用层协议,验证显示是否恢复正常。
内容的提问来源于stack exchange,提问作者user19726663
相关产品推荐
相关产品推荐

