From 3a64207e58c289fc518efb8f59e94dfcf9c23864 Mon Sep 17 00:00:00 2001 From: Sabhya <89577007+5h4rrk@users.noreply.github.com> Date: Sat, 10 May 2025 15:56:39 +0530 Subject: [PATCH] pattern: Added pcapng capture file pattern (#385) add: pcapng hexpat --- README.md | 1 + patterns/pcapng.hexpat | 516 +++++++++++++++++++++ tests/patterns/test_data/pcapng.hexpat.bin | Bin 0 -> 20920 bytes 3 files changed, 517 insertions(+) create mode 100644 patterns/pcapng.hexpat create mode 100644 tests/patterns/test_data/pcapng.hexpat.bin diff --git a/README.md b/README.md index 088239e..0739a7a 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | OGG | `audio/ogg` | [`patterns/ogg.hexpat`](patterns/ogg.hexpat) | OGG Audio format | | PAK | | [`patterns/xgspak.hexpat`](patterns/xgspak.hexpat) | Exient XGS Engine Pak files | | PCAP | `application/vnd.tcpdump.pcap` | [`patterns/pcap.hexpat`](patterns/pcap.hexpat) | pcap header and packets | +| PcapNG | `application/vnd.tcpdump.pcap` | [`patterns/pcapng.hexpat`](patterns/pcapng.hexpat) | pcapng header and packets | | PCK | | [`patterns/pck.hexpat`](patterns/pck.hexpat) | Minecraft Legacy Console Edition .pck file | | PCX | `application/x-pcx` | [`patterns/pcx.hexpat`](patterns/pcx.hexpat) | PCX Image format | | PE | `application/x-dosexec` `application/x-msdownload` | [`patterns/pe.hexpat`](patterns/pe.hexpat) | PE header, COFF header, Standard COFF fields and Windows Specific fields | diff --git a/patterns/pcapng.hexpat b/patterns/pcapng.hexpat new file mode 100644 index 0000000..8664d40 --- /dev/null +++ b/patterns/pcapng.hexpat @@ -0,0 +1,516 @@ +#pragma description PcapNG +#pragma MIME application/vnd.tcpdump.pcapng +#pragma author 5h4rrK + +import std.mem; +import std.core; +import std.math; +import std.io; + +#define MAX_VALUE_U64 0xffffffffffffffff + +fn format_version(auto version){ + return std::format( + "{}.{}", version.major, version.minor + ); +}; + + +fn is_valid_len(auto val){ + if (val == MAX_VALUE_U64){ + return std::format("[Not Specified]"); + } + else{ + return val; + } +}; + +enum PcapOrder : u32{ + Little = 0x1a2b3c4d, + Big = 0x4d3c2b1a, +}; + +struct Version { + u16 major; + u16 minor; +}; + +enum BlockType : u32{ + // Mandatory Blocks + SectionHeader = 0x0A0D0D0A, + InterfaceDesc = 0x00000001, + + // Optional Blocks + SimplePacket = 0x00000003, + NameResolution = 0x00000004, + InterfaceStats = 0x00000005, + EnhancedPacket = 0x00000006, + Custom = 0x00000BAD, + CustomNoCopy = 0x40000BAD, + Systemd = 0x00000009, + Decryption = 0x0000000A, + + // Obsolete Block + Packet = 0x00000002, + + // Reserved & Misc + Reserved = 0x00000000, + IRIGTimestamp = 0x00000007, + AFDXInfo = 0x00000008, + + // Hone Project Specific + HoneMachine = 0x00000101, + HoneConnEvent = 0x00000102, + + // Sysdig Specific + SysdigMachine = 0x00000201, + SysdigProcessV1 = 0x00000202, + SysdigFDList = 0x00000203, + SysdigEvent = 0x00000204, + SysdigIFList = 0x00000205, + SysdigUserList = 0x00000206, + SysdigProcessV2 = 0x00000207, + SysdigEventFL = 0x00000208, + SysdigProcessV3 = 0x00000209, + SysdigProcessV4 = 0x00000210, + SysdigProcessV5 = 0x00000211, + SysdigProcessV6 = 0x00000212, + SysdigProcessV7 = 0x00000213, + +}; + +enum LinkType : u16 { + LINKTYPE_NULL = 0, + LINKTYPE_ETHERNET = 1, + LINKTYPE_AX25 = 3, + LINKTYPE_IEEE802_5 = 6, + LINKTYPE_ARCNET_BSD = 7, + LINKTYPE_SLIP = 8, + LINKTYPE_PPP = 9, + LINKTYPE_FDDI = 10, + LINKTYPE_PPP_HDLC = 50, + LINKTYPE_PPP_ETHER = 51, + LINKTYPE_ATM_RFC1483 = 100, + LINKTYPE_RAW = 101, + LINKTYPE_C_HDLC = 104, + LINKTYPE_IEEE802_11 = 105, + LINKTYPE_FRELAY = 107, + LINKTYPE_LOOP = 108, + LINKTYPE_LINUX_SLL = 113, + LINKTYPE_LTALK = 114, + LINKTYPE_PFLOG = 117, + LINKTYPE_IEEE802_11_PRISM = 119, + LINKTYPE_IP_OVER_FC = 122, + LINKTYPE_SUNATM = 123, + LINKTYPE_IEEE802_11_RADIOTAP = 127, + LINKTYPE_ARCNET_LINUX = 129, + LINKTYPE_APPLE_IP_OVER_IEEE1394 = 138, + LINKTYPE_MTP2_WITH_PHDR = 139, + LINKTYPE_MTP2 = 140, + LINKTYPE_MTP3 = 141, + LINKTYPE_SCCP = 142, + LINKTYPE_DOCSIS = 143, + LINKTYPE_LINUX_IRDA = 144, + LINKTYPE_IEEE802_11_AVS = 163, + LINKTYPE_BACNET_MS_TP = 165, + LINKTYPE_PPP_PPPD = 166, + LINKTYPE_GPRS_LLC = 169, + LINKTYPE_GPF_T = 170, + LINKTYPE_GPF_F = 171, + LINKTYPE_LINUX_LAPD = 177, + LINKTYPE_MFR = 182, + LINKTYPE_BLUETOOTH_HCI_H4 = 187, + LINKTYPE_USB_LINUX = 189, + LINKTYPE_PPI = 192, + LINKTYPE_IEEE802_15_4_WITHFCS = 195, + LINKTYPE_SITA = 196, + LINKTYPE_ERF = 197, + LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR = 201, + LINKTYPE_AX25_KISS = 202, + LINKTYPE_LAPD = 203, + LINKTYPE_PPP_WITH_DIR = 204, + LINKTYPE_C_HDLC_WITH_DIR = 205, + LINKTYPE_FRELAY_WITH_DIR = 206, + LINKTYPE_LAPB_WITH_DIR = 207, + LINKTYPE_IPMB_LINUX = 209, + LINKTYPE_FLEXRAY = 210, + LINKTYPE_IEEE802_15_4_NONASK_PHY = 215, + LINKTYPE_USB_LINUX_MMAPPED = 220, + LINKTYPE_FC_2 = 224, + LINKTYPE_FC_2_WITH_FRAME_DELIMS = 225, + LINKTYPE_IPNET = 226, + LINKTYPE_CAN_SOCKETCAN = 227, + LINKTYPE_IPV4 = 228, + LINKTYPE_IPV6 = 229, + LINKTYPE_IEEE802_15_4_NOFCS = 230, + LINKTYPE_DBUS = 231, + LINKTYPE_DVB_CI = 235, + LINKTYPE_MUX27010 = 236, + LINKTYPE_STANAG_5066_D_PDU = 237, + LINKTYPE_NFLOG = 239, + LINKTYPE_NETANALYZER = 240, + LINKTYPE_NETANALYZER_TRANSPARENT = 241, + LINKTYPE_IPOIB = 242, + LINKTYPE_MPEG_2_TS = 243, + LINKTYPE_NG40 = 244, + LINKTYPE_NFC_LLCP = 245, + LINKTYPE_INFINIBAND = 247, + LINKTYPE_SCTP = 248, + LINKTYPE_USBPCAP = 249, + LINKTYPE_RTAC_SERIAL = 250, + LINKTYPE_BLUETOOTH_LE_LL = 251, + LINKTYPE_NETLINK = 253, + LINKTYPE_BLUETOOTH_LINUX_MONITOR = 254, + LINKTYPE_BLUETOOTH_BREDR_BB = 255, + LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR = 256, + LINKTYPE_PROFIBUS_DL = 257, + LINKTYPE_PKTAP = 258, + LINKTYPE_EPON = 259, + LINKTYPE_IPMI_HPM_2 = 260, + LINKTYPE_ZWAVE_R1_R2 = 261, + LINKTYPE_ZWAVE_R3 = 262, + LINKTYPE_WATTSTOPPER_DLM = 263, + LINKTYPE_ISO_14443 = 264, + LINKTYPE_RDS = 265, + LINKTYPE_USB_DARWIN = 266, + LINKTYPE_SDLC = 268, + LINKTYPE_LORATAP = 270, + LINKTYPE_VSOCK = 271, + LINKTYPE_NORDIC_BLE = 272, + LINKTYPE_DOCSIS31_XRA31 = 273, + LINKTYPE_ETHERNET_MPACKET = 274, + LINKTYPE_DISPLAYPORT_AUX = 275, + LINKTYPE_LINUX_SLL2 = 276, + LINKTYPE_OPENVIZSLA = 278, + LINKTYPE_EBHSCR = 279, + LINKTYPE_VPP_DISPATCH = 280, + LINKTYPE_DSA_TAG_BRCM = 281, + LINKTYPE_DSA_TAG_BRCM_PREPEND = 282, + LINKTYPE_IEEE802_15_4_TAP = 283, + LINKTYPE_DSA_TAG_DSA = 284, + LINKTYPE_DSA_TAG_EDSA = 285, + LINKTYPE_ELEE = 286, + LINKTYPE_Z_WAVE_SERIAL = 287, + LINKTYPE_USB_2_0 = 288, + LINKTYPE_ATSC_ALP = 289, + LINKTYPE_ETW = 290 +}; + +enum SHBType : u16{ + EndOfOpt = 0x0, + Hardware = 0x2, + OS = 0x3, + Application = 0x4, + EndOfOpt = 0x0 +}; + +enum IDHType : u16 { + EndOfOpt = 0, + Name = 2, // UTF-8 device name (e.g., "eth0") + Description = 3, // UTF-8 device description + IPv4Addr = 4, // IPv4 address + netmask (8 bytes) + IPv6Addr = 5, // IPv6 address + prefix len (17 bytes) + MACAddr = 6, // MAC address (6 bytes) + EUIAddr = 7, // EUI-64 address (8 bytes) + Speed = 8, // Interface speed (bps, 8 bytes) + TimestampRes = 9, // Timestamp resolution (1 byte) + TimeZone = 10, // Time zone (4 bytes) + Filter = 11, // Capture filter string + OS = 12, // OS name (UTF-8 string) + FCSLength = 13, // Frame Check Sequence length (1 byte) + TimestampOffset = 14, // Timestamp offset (8 bytes) + Hardware = 15, // Variable length + TxSpeed = 16, // 8bytes + RxSpeed = 17 // 8bytes +}; + +enum NameResolutionType: u16 { + EndOfRecord = 0x00, + IPv4 = 0x01, + IPv6 = 0x02 +}; + +enum InterfaceStatsType : u16 { + EndOfOpt = 0, + Comment = 1, // isb_comment + StartTime = 2, // isb_starttime + EndTime = 3, // isb_endtime + IfRecv = 4, // isb_ifrecv + IfDrop = 5, // isb_ifdrop + FilterAccept = 6, // isb_filteraccept + OSdrop = 7, // isb_osdrop + UserDeliver = 8, // isb_usrdeliv +}; + +enum EnhancedPacketType : u16 { + EndOfOpt = 0x0, + Flags = 0x2, + Hash = 0x3, + DropCount = 0x4, + PacketId = 0x5, + Queue = 0x6, + Verdict = 0x7, +}; + +enum PacketBlockType : u16 { + Flags = 0x2, + Hash = 0x3, + EndOfOpt = 0x0, +}; + + +struct Option { + + if (this.parent.block_type == BlockType::SectionHeader) { + SHBType option_type; + } else if(this.parent.block_type == BlockType::InterfaceDesc) { + IDHType option_type; + } else if (this.parent.block_type == BlockType::NameResolution) { + NameResolutionType record_type[[name("record")]]; + } else if (this.parent.block_type == BlockType::InterfaceStats){ + InterfaceStatsType option_type; + } else if (this.parent.block_type == BlockType::EnhancedPacket) { + EnhancedPacketType option_type; + } else if (this.parent.block_type == BlockType::Packet){ + PacketBlockType option_type; + } + u16 option_len; + + if (option_len > 0){ + char data[option_len]; + } else{ + return; + } + // u8 pad_size = (4 - ( $ % 4 )); + u8 pad_size = (4 - ( $ % 4 )) % 4; + // if(this.parent.block_type == BlockType::InterfaceStats) { + // std::print("Current Pos {:#x} {:#x}",$, pad_size); + // } + + $ = $ + pad_size; +}; + + +struct SectionHeaderBlock { + BlockType block_type; + u32 length; + PcapOrder sectionbyteorder; + Version version [[name("Version"), format("format_version")]]; + u64 section_len [[name("SectionLen"), format("is_valid_len")]]; + u64 prev_pos = $; + Option options [ while( $ < (prev_pos + length - 28))]; + u32 block_length [[name("BlockLen")]]; + +}; + + +struct NameResolutionBlock { + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + u64 prev_pos = $; + Option records [ while($ < (prev_pos + block_len1 - 12)) ]; + u32 block_len2[[name("BlockLen2")]]; +}; + +struct SystemJournalExportBlock{ + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + char data[block_len1]; + $ = $ + (4 - ($ % 4 ) ); // Padding + u32 block_len2[[name("BlockLen2")]]; +}; + +struct CustomBlock{ + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + u32 pen[[name("PrivateEnterpriseNumber")]]; + char data[block_len1]; + u64 prev_pos = $; + $ = $ + (4 - ($ % 4 ) ); // Padding + Option options [while($ < (prev_pos + block_len1 - 16))] [[name("Options")]]; + u32 block_len2[[name("BlockLen2")]]; +}; + +struct InterfaceBlock{ + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + LinkType link_type [[name("LinkType")]]; + u16 reserved [[name("Reserved")]]; + u32 snap_len [[name("SnapLen")]]; + u64 prev_pos = $; + Option options [ while( $ < (prev_pos + block_len1 - 20))]; + u32 block_len2[[name("BlockLen2")]]; +}; + +struct EnhancedPacketBlock{ + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + u32 interface_id[[name("InterfaceID")]]; + u64 timestamp[[name("Timestamp")]]; + u32 captured_len[[name("CapturedLen")]]; + u32 pkt_len[[name("PacketLen")]]; + char data[captured_len][[name("Data")]]; + // 32 (BlockType + BlockLen1 + InterfaceID + Timestamp + CapturedLen + PacketLen + BlockLen2) + $ = $ + (block_len1 - captured_len - 32); + u64 prev_pos = $; + // Current Pos - Prev Pos - 4 (BlockLen2) + // std::print("Option Size :: {:#x}", ($ - prev_pos)); + if (($ - prev_pos ) > 0) { + Option options [ while( $ < ( prev_pos + ($ - prev_pos ) ) ) ]; + } + u32 block_len2[[name("BlockLen2")]]; + +}; + +struct SimplePacketBlock { + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + u32 pkt_len[[name("PacketLen")]]; + char data[[name("Data")]]; + u8 pad_size = (4 - ( $ % 4 )) % 4; + $ = $ + pad_size; + u32 block_len2[[name("BlockLen2")]]; +}; + +// Obsolete! +struct PacketBlock { + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + u16 interface_id[[name("InterfaceID")]]; + u16 drop_count[[name("DropCount")]]; + u64 timestamp[[name("Timestamp")]]; + u32 captured_len[[name("CapturedLen")]]; + u32 pkt_len[[name("PacketLen")]]; + if (block_len1 > 32){ + char data[captured_len]; + } + u32 block_len2[[name("BlockLen2")]]; +}; + +enum CompressionType: u8 { + Uncompressed = 0x0, + LempelZiv = 0x1, + Gzip = 0x2 +}; + +enum EncryptionType : u8 { + // Experimental +}; + +enum FixedLengthType : u8 { + // Experimental +}; + +// Experimental +struct CompressionBlock{ + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + CompressionType comp_type [[name("Compresssion")]]; + char data[block_len1]; + u32 block_len2[[name("BlockLen2")]]; +}; + +// Experimental +struct EncryptionBlock{ + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + EncryptionType comp_type [[name("Encryption")]]; + char data[block_len1]; + u32 block_len2[[name("BlockLen2")]]; +}; + +// Experimental +struct FixedLengthBlock { + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + FixedLengthType comp_type [[name("FixedLength")]]; + char data[block_len1]; + u32 block_len2[[name("BlockLen2")]]; +}; + +struct InterfaceStatsBlock { + BlockType block_type[[name("BlockType")]]; + u32 block_len1[[name("BlockLen1")]]; + u32 interface_id[[name("InterfaceID")]]; + u64 timestamp[[name("Timestamp")]]; + if(block_len1 > 24) { + u64 prev_pos = $; + Option options [ while( $ < (prev_pos + block_len1 - 24))]; + } + u32 block_len2[[name("BlockLen2")]]; +}; + +struct PCAPng{ + if (std::mem::eof()){ + break; + } + if (order == PcapOrder::Little){ + le u32 block_type = std::mem::read_unsigned($, 0x4, std::mem::Endian::Little); + } else { + be u32 block_type = std::mem::read_unsigned($, 0x4, std::mem::Endian::Big); + } + // std::print("{} , {:#x}, {:#x}", "Parsing", $, block_type); + // std::print("Parsing : Offset({:#x}), Order({:#x}), BlockType({:#x})", $, order, block_type); + if (block_type == BlockType::SectionHeader) { + if (order == PcapOrder::Little) { + le SectionHeaderBlock SHB; + } else { + be SectionHeaderBlock SHB; + } + } else if (block_type == BlockType::InterfaceDesc) { + if (order == PcapOrder::Little) { + le InterfaceBlock IDH; + } else { + be InterfaceBlock IDH; + } + } else if (block_type == BlockType::EnhancedPacket) { + if (order == PcapOrder::Little) { + le EnhancedPacketBlock EBP; + } else { + be EnhancedPacketBlock EBP; + } + } else if (block_type == BlockType::NameResolution) { + if (order == PcapOrder::Little) { + le NameResolutionBlock NRB; + } else { + be NameResolutionBlock NRB; + } + } else if (block_type == BlockType::InterfaceStats) { + if (order == PcapOrder::Little) { + le InterfaceStatsBlock ISB; + } else { + be InterfaceStatsBlock ISB; + } + } else if (block_type == BlockType::SimplePacket) { + if (order == PcapOrder::Little) { + le SimplePacketBlock SPB; + } else { + be SimplePacketBlock SPB; + } + } else if (block_type == BlockType::Packet) { + if (order == PcapOrder::Little) { + le PacketBlock PB; + } else { + be PacketBlock PB; + } + } else if (block_type == BlockType::Custom) { + if (order == PcapOrder::Little) { + le CustomBlock CB; + } else { + be CustomBlock CB; + } + } else if (block_type == BlockType::CustomNoCopy) { + if (order == PcapOrder::Little) { + le CustomBlock CBN; + } else { + be CustomBlock CBN; + } + } else { + std::print("Unknown BlockType at offset {:#x}\n", $); + break; + } +} [[inline]]; + + +u32 order = std::mem::read_unsigned(0x8, 0x4); +PCAPng PcapNG [while(!std::mem::eof())] @0x00; diff --git a/tests/patterns/test_data/pcapng.hexpat.bin b/tests/patterns/test_data/pcapng.hexpat.bin new file mode 100644 index 0000000000000000000000000000000000000000..6fa742f47d820602f10f2c1007b5d5d67e75c0b3 GIT binary patch literal 20920 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