如何用C#代码创建仅含源/目的MAC、IP及数据的pcap文件?
手动用C#构造PCAP文件的简便方法
其实完全不需要依赖第三方库就能实现——PCAP文件格式是公开的,咱们手动构造各个部分就行,非常直接。下面是一个完整的实现,只需要传入你需要的源MAC、源IP、目的MAC、目的IP和数据,就能生成可以用Wireshark等工具打开的PCAP文件。
核心思路
PCAP文件由两部分组成:
- 全局头:描述文件的基本信息(版本、数据链路类型等)
- 数据包序列:每个数据包包含包头(时间戳、长度)和实际的帧数据(以太网帧 + IP包 + 传输层数据 + 你的自定义数据)
咱们直接构造这些字节流,写入文件即可。
完整代码实现
using System; using System.IO; using System.Runtime.InteropServices; public class PcapCreator { [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct PcapGlobalHeader { public uint MagicNumber; public ushort VersionMajor; public ushort VersionMinor; public int TimeZoneOffset; public uint SigFigs; public uint SnapLength; public uint NetworkType; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct PcapPacketHeader { public uint TimestampSeconds; public uint TimestampMicroseconds; public uint CapturedLength; public uint OriginalLength; } public static void CreatePcapFile(string filePath, byte[] srcMac, byte[] srcIp, byte[] destMac, byte[] destIp, byte[] data) { // 构造PCAP全局头(标准小端格式) var globalHeader = new PcapGlobalHeader { MagicNumber = 0xA1B2C3D4, // PCAP标准魔数 VersionMajor = 2, VersionMinor = 4, TimeZoneOffset = 0, // UTC时间 SigFigs = 0, SnapLength = 65535, // 最大捕获长度 NetworkType = 1 // 数据链路类型:以太网 }; // 获取当前UTC时间戳(PCAP使用Unix时间) var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); var timeSpan = DateTime.UtcNow - epoch; uint timestampSeconds = (uint)timeSpan.TotalSeconds; uint timestampMicroseconds = (uint)(timeSpan.TotalMilliseconds * 1000); // 构造以太网帧头部(14字节) byte[] ethernetFrame = new byte[14]; Array.Copy(destMac, 0, ethernetFrame, 0, 6); // 目的MAC Array.Copy(srcMac, 0, ethernetFrame, 6, 6); // 源MAC ethernetFrame[12] = 0x08; ethernetFrame[13] = 0x00; // 帧类型:IPv4 // 构造IPv4头部(20字节,无扩展选项) byte[] ipHeader = new byte[20]; ipHeader[0] = 0x45; // 版本(4) + 头部长度(5*4=20字节) ipHeader[1] = 0x00; // 服务类型 ushort ipTotalLength = (ushort)(20 + 8 + data.Length); // IP头+UDP头+数据总长度 WriteBigEndian(ipTotalLength, ipHeader, 2); ipHeader[4] = 0x00; ipHeader[5] = 0x00; // 标识 ipHeader[6] = 0x00; ipHeader[7] = 0x00; // 标志+片偏移 ipHeader[8] = 0x40; // TTL=64 ipHeader[9] = 0x11; // 协议类型:UDP ipHeader[10] = 0x00; ipHeader[11] = 0x00; // 校验和(先设0,后面计算) Array.Copy(srcIp, 0, ipHeader, 12, 4); // 源IP Array.Copy(destIp, 0, ipHeader, 16, 4); // 目的IP // 计算IPv4头部校验和 ushort ipChecksum = CalculateChecksum(ipHeader); WriteBigEndian(ipChecksum, ipHeader, 10); // 构造UDP头部(8字节) byte[] udpHeader = new byte[8]; WriteBigEndian((ushort)1234, udpHeader, 0); // 源端口(可自定义) WriteBigEndian((ushort)5678, udpHeader, 2); // 目的端口(可自定义) ushort udpLength = (ushort)(8 + data.Length); // UDP头+数据长度 WriteBigEndian(udpLength, udpHeader, 4); udpHeader[6] = 0x00; udpHeader[7] = 0x00; // UDP校验和(可选设0) // 拼接完整的数据包 byte[] packetData = new byte[ethernetFrame.Length + ipHeader.Length + udpHeader.Length + data.Length]; int offset = 0; Array.Copy(ethernetFrame, 0, packetData, offset, ethernetFrame.Length); offset += ethernetFrame.Length; Array.Copy(ipHeader, 0, packetData, offset, ipHeader.Length); offset += ipHeader.Length; Array.Copy(udpHeader, 0, packetData, offset, udpHeader.Length); offset += udpHeader.Length; Array.Copy(data, 0, packetData, offset, data.Length); // 构造数据包头部 var packetHeader = new PcapPacketHeader { TimestampSeconds = timestampSeconds, TimestampMicroseconds = timestampMicroseconds, CapturedLength = (uint)packetData.Length, OriginalLength = (uint)packetData.Length }; // 写入PCAP文件 using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) using (var bw = new BinaryWriter(fs)) { // 写入全局头(注意字节序:PCAP使用小端,直接用BitConverter即可) bw.Write(BitConverter.GetBytes(globalHeader.MagicNumber)); bw.Write(BitConverter.GetBytes(globalHeader.VersionMajor)); bw.Write(BitConverter.GetBytes(globalHeader.VersionMinor)); bw.Write(BitConverter.GetBytes(globalHeader.TimeZoneOffset)); bw.Write(BitConverter.GetBytes(globalHeader.SigFigs)); bw.Write(BitConverter.GetBytes(globalHeader.SnapLength)); bw.Write(BitConverter.GetBytes(globalHeader.NetworkType)); // 写入数据包头部 bw.Write(BitConverter.GetBytes(packetHeader.TimestampSeconds)); bw.Write(BitConverter.GetBytes(packetHeader.TimestampMicroseconds)); bw.Write(BitConverter.GetBytes(packetHeader.CapturedLength)); bw.Write(BitConverter.GetBytes(packetHeader.OriginalLength)); // 写入数据包内容 bw.Write(packetData); } } // 辅助方法:将ushort以大端序写入字节数组 private static void WriteBigEndian(ushort value, byte[] buffer, int offset) { byte[] bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); Array.Copy(bytes, 0, buffer, offset, 2); } // 计算校验和(用于IP头部) private static ushort CalculateChecksum(byte[] data) { uint sum = 0; int i = 0; while (i < data.Length) { sum += (ushort)((data[i] << 8) | data[i + 1]); i += 2; } // 处理奇数长度(这里IP头是20字节,偶数,所以实际不会触发) if (data.Length % 2 != 0) { sum += (ushort)(data[data.Length - 1] << 8); } // 折叠求和并取反 sum = (sum >> 16) + (sum & 0xFFFF); sum += sum >> 16; return (ushort)~sum; } // 示例调用 public static void Main() { // 替换成你需要的参数 byte[] srcMac = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; byte[] srcIp = new byte[] { 192, 168, 1, 100 }; byte[] destMac = new byte[] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; byte[] destIp = new byte[] { 8, 8, 8, 8 }; byte[] data = System.Text.Encoding.ASCII.GetBytes("Hello from custom PCAP!"); CreatePcapFile("output.pcap", srcMac, srcIp, destMac, destIp, data); Console.WriteLine("PCAP文件已生成!"); } }
关键说明
- 不需要任何第三方库:所有逻辑都是原生C#实现,直接编译运行即可。
- 参数灵活:你只需要传入源MAC、源IP、目的MAC、目的IP和自定义数据,其他部分(如端口、TTL)可以根据需要修改。
- 兼容性:生成的PCAP文件可以被Wireshark、tcpdump等工具正常打开解析,因为完全遵循PCAP标准格式。
- 可扩展:如果不需要UDP层,你可以直接把数据作为IP包的payload,只需要修改IP头的协议字段(比如设为
0xFF表示私有协议),并调整IP总长度为20 + data.Length,去掉UDP头的代码即可。
内容的提问来源于stack exchange,提问作者ARMisKing
相关产品推荐
相关产品推荐

