.cap file format of Microsoft Network Monitor, v2.x: C# parsing library

Microsoft Network Monitor (AKA Netmon) is a proprietary Microsoft's network packet sniffing and analysis tool. It can save captured traffic as .cap files, which usually contain the packets and may contain some additional info - enhanced network info, calculated statistics, etc.

There are at least 2 different versions of the format: v1 and v2. Netmon v3 seems to use the same file format as v1.

Application

Microsoft Network Monitor, v2.x

File extension

cap

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.7

References

This page hosts a formal specification of .cap file format of Microsoft Network Monitor, v2.x using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C# generated by Kaitai Struct depends on the C# runtime library. You have to install it before you can parse data.

The C# runtime library is available in the NuGet Gallery. Installation instructions can also be found there.

Code

Parse a local file and get structure in memory:

var data = MicrosoftNetworkMonitorV2.FromFile("path/to/local/file.cap");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
var data = new MicrosoftNetworkMonitorV2(new KaitaiStream(someArray));

After that, one can get various attributes from the structure by accessing properties like:

data.VersionMinor // => Format version (minor), BCD
data.FrameTable // => Index that is used to access individual captured frames

C# source code to parse .cap file format of Microsoft Network Monitor, v2.x

MicrosoftNetworkMonitorV2.cs

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

using System.Collections.Generic;

namespace Kaitai
{

    /// <summary>
    /// Microsoft Network Monitor (AKA Netmon) is a proprietary Microsoft's
    /// network packet sniffing and analysis tool. It can save captured
    /// traffic as .cap files, which usually contain the packets and may
    /// contain some additional info - enhanced network info, calculated
    /// statistics, etc.
    /// 
    /// There are at least 2 different versions of the format: v1 and
    /// v2. Netmon v3 seems to use the same file format as v1.
    /// </summary>
    /// <remarks>
    /// Reference: <a href="https://learn.microsoft.com/en-us/windows/win32/netmon2/capturefile-header-values">Source</a>
    /// </remarks>
    public partial class MicrosoftNetworkMonitorV2 : KaitaiStruct
    {
        public static MicrosoftNetworkMonitorV2 FromFile(string fileName)
        {
            return new MicrosoftNetworkMonitorV2(new KaitaiStream(fileName));
        }


        public enum Linktype
        {
            NullLinktype = 0,
            Ethernet = 1,
            Ax25 = 3,
            Ieee8025 = 6,
            ArcnetBsd = 7,
            Slip = 8,
            Ppp = 9,
            Fddi = 10,
            PppHdlc = 50,
            PppEther = 51,
            AtmRfc1483 = 100,
            Raw = 101,
            CHdlc = 104,
            Ieee80211 = 105,
            Frelay = 107,
            Loop = 108,
            LinuxSll = 113,
            Ltalk = 114,
            Pflog = 117,
            Ieee80211Prism = 119,
            IpOverFc = 122,
            Sunatm = 123,
            Ieee80211Radiotap = 127,
            ArcnetLinux = 129,
            AppleIpOverIeee1394 = 138,
            Mtp2WithPhdr = 139,
            Mtp2 = 140,
            Mtp3 = 141,
            Sccp = 142,
            Docsis = 143,
            LinuxIrda = 144,
            User0 = 147,
            User1 = 148,
            User2 = 149,
            User3 = 150,
            User4 = 151,
            User5 = 152,
            User6 = 153,
            User7 = 154,
            User8 = 155,
            User9 = 156,
            User10 = 157,
            User11 = 158,
            User12 = 159,
            User13 = 160,
            User14 = 161,
            User15 = 162,
            Ieee80211Avs = 163,
            BacnetMsTp = 165,
            PppPppd = 166,
            GprsLlc = 169,
            GpfT = 170,
            GpfF = 171,
            LinuxLapd = 177,
            BluetoothHciH4 = 187,
            UsbLinux = 189,
            Ppi = 192,
            Ieee802154 = 195,
            Sita = 196,
            Erf = 197,
            BluetoothHciH4WithPhdr = 201,
            Ax25Kiss = 202,
            Lapd = 203,
            PppWithDir = 204,
            CHdlcWithDir = 205,
            FrelayWithDir = 206,
            IpmbLinux = 209,
            Ieee802154NonaskPhy = 215,
            UsbLinuxMmapped = 220,
            Fc2 = 224,
            Fc2WithFrameDelims = 225,
            Ipnet = 226,
            CanSocketcan = 227,
            Ipv4 = 228,
            Ipv6 = 229,
            Ieee802154Nofcs = 230,
            Dbus = 231,
            DvbCi = 235,
            Mux27010 = 236,
            Stanag5066DPdu = 237,
            Nflog = 239,
            Netanalyzer = 240,
            NetanalyzerTransparent = 241,
            Ipoib = 242,
            Mpeg2Ts = 243,
            Ng40 = 244,
            NfcLlcp = 245,
            Infiniband = 247,
            Sctp = 248,
            Usbpcap = 249,
            RtacSerial = 250,
            BluetoothLeLl = 251,
            Netlink = 253,
            BluetoothLinuxMonitor = 254,
            BluetoothBredrBb = 255,
            BluetoothLeLlWithPhdr = 256,
            ProfibusDl = 257,
            Pktap = 258,
            Epon = 259,
            IpmiHpm2 = 260,
            ZwaveR1R2 = 261,
            ZwaveR3 = 262,
            WattstopperDlm = 263,
            Iso14443 = 264,
        }
        public MicrosoftNetworkMonitorV2(KaitaiStream p__io, KaitaiStruct p__parent = null, MicrosoftNetworkMonitorV2 p__root = null) : base(p__io)
        {
            m_parent = p__parent;
            m_root = p__root ?? this;
            f_frameTable = false;
            _read();
        }
        private void _read()
        {
            _signature = m_io.ReadBytes(4);
            if (!((KaitaiStream.ByteArrayCompare(Signature, new byte[] { 71, 77, 66, 85 }) == 0)))
            {
                throw new ValidationNotEqualError(new byte[] { 71, 77, 66, 85 }, Signature, M_Io, "/seq/0");
            }
            _versionMinor = m_io.ReadU1();
            _versionMajor = m_io.ReadU1();
            _macType = ((Linktype) m_io.ReadU2le());
            _timeCaptureStart = new WindowsSystemtime(m_io);
            _frameTableOfs = m_io.ReadU4le();
            _frameTableLen = m_io.ReadU4le();
            _userDataOfs = m_io.ReadU4le();
            _userDataLen = m_io.ReadU4le();
            _commentOfs = m_io.ReadU4le();
            _commentLen = m_io.ReadU4le();
            _statisticsOfs = m_io.ReadU4le();
            _statisticsLen = m_io.ReadU4le();
            _networkInfoOfs = m_io.ReadU4le();
            _networkInfoLen = m_io.ReadU4le();
            _conversationStatsOfs = m_io.ReadU4le();
            _conversationStatsLen = m_io.ReadU4le();
        }
        public partial class FrameIndex : KaitaiStruct
        {
            public static FrameIndex FromFile(string fileName)
            {
                return new FrameIndex(new KaitaiStream(fileName));
            }

            public FrameIndex(KaitaiStream p__io, MicrosoftNetworkMonitorV2 p__parent = null, MicrosoftNetworkMonitorV2 p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                _read();
            }
            private void _read()
            {
                _entries = new List<FrameIndexEntry>();
                {
                    var i = 0;
                    while (!m_io.IsEof) {
                        _entries.Add(new FrameIndexEntry(m_io, this, m_root));
                        i++;
                    }
                }
            }
            private List<FrameIndexEntry> _entries;
            private MicrosoftNetworkMonitorV2 m_root;
            private MicrosoftNetworkMonitorV2 m_parent;
            public List<FrameIndexEntry> Entries { get { return _entries; } }
            public MicrosoftNetworkMonitorV2 M_Root { get { return m_root; } }
            public MicrosoftNetworkMonitorV2 M_Parent { get { return m_parent; } }
        }

        /// <summary>
        /// Each index entry is just a pointer to where the frame data is
        /// stored in the file.
        /// </summary>
        public partial class FrameIndexEntry : KaitaiStruct
        {
            public static FrameIndexEntry FromFile(string fileName)
            {
                return new FrameIndexEntry(new KaitaiStream(fileName));
            }

            public FrameIndexEntry(KaitaiStream p__io, MicrosoftNetworkMonitorV2.FrameIndex p__parent = null, MicrosoftNetworkMonitorV2 p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                f_body = false;
                _read();
            }
            private void _read()
            {
                _ofs = m_io.ReadU4le();
            }
            private bool f_body;
            private Frame _body;

            /// <summary>
            /// Frame body itself
            /// </summary>
            public Frame Body
            {
                get
                {
                    if (f_body)
                        return _body;
                    KaitaiStream io = M_Root.M_Io;
                    long _pos = io.Pos;
                    io.Seek(Ofs);
                    _body = new Frame(io, this, m_root);
                    io.Seek(_pos);
                    f_body = true;
                    return _body;
                }
            }
            private uint _ofs;
            private MicrosoftNetworkMonitorV2 m_root;
            private MicrosoftNetworkMonitorV2.FrameIndex m_parent;

            /// <summary>
            /// Absolute pointer to frame data in the file
            /// </summary>
            public uint Ofs { get { return _ofs; } }
            public MicrosoftNetworkMonitorV2 M_Root { get { return m_root; } }
            public MicrosoftNetworkMonitorV2.FrameIndex M_Parent { get { return m_parent; } }
        }

        /// <summary>
        /// A container for actually captured network data. Allow to
        /// timestamp individual frames and designates how much data from
        /// the original packet was actually written into the file.
        /// </summary>
        /// <remarks>
        /// Reference: <a href="https://learn.microsoft.com/en-us/windows/win32/netmon2/frame">Source</a>
        /// </remarks>
        public partial class Frame : KaitaiStruct
        {
            public static Frame FromFile(string fileName)
            {
                return new Frame(new KaitaiStream(fileName));
            }

            public Frame(KaitaiStream p__io, MicrosoftNetworkMonitorV2.FrameIndexEntry p__parent = null, MicrosoftNetworkMonitorV2 p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                _read();
            }
            private void _read()
            {
                _tsDelta = m_io.ReadU8le();
                _origLen = m_io.ReadU4le();
                _incLen = m_io.ReadU4le();
                switch (M_Root.MacType) {
                case MicrosoftNetworkMonitorV2.Linktype.Ethernet: {
                    __raw_body = m_io.ReadBytes(IncLen);
                    var io___raw_body = new KaitaiStream(__raw_body);
                    _body = new EthernetFrame(io___raw_body);
                    break;
                }
                default: {
                    _body = m_io.ReadBytes(IncLen);
                    break;
                }
                }
            }
            private ulong _tsDelta;
            private uint _origLen;
            private uint _incLen;
            private object _body;
            private MicrosoftNetworkMonitorV2 m_root;
            private MicrosoftNetworkMonitorV2.FrameIndexEntry m_parent;
            private byte[] __raw_body;

            /// <summary>
            /// Time stamp - usecs since start of capture
            /// </summary>
            public ulong TsDelta { get { return _tsDelta; } }

            /// <summary>
            /// Actual length of packet
            /// </summary>
            public uint OrigLen { get { return _origLen; } }

            /// <summary>
            /// Number of octets captured in file
            /// </summary>
            public uint IncLen { get { return _incLen; } }

            /// <summary>
            /// Actual packet captured from the network
            /// </summary>
            public object Body { get { return _body; } }
            public MicrosoftNetworkMonitorV2 M_Root { get { return m_root; } }
            public MicrosoftNetworkMonitorV2.FrameIndexEntry M_Parent { get { return m_parent; } }
            public byte[] M_RawBody { get { return __raw_body; } }
        }
        private bool f_frameTable;
        private FrameIndex _frameTable;

        /// <summary>
        /// Index that is used to access individual captured frames
        /// </summary>
        public FrameIndex FrameTable
        {
            get
            {
                if (f_frameTable)
                    return _frameTable;
                long _pos = m_io.Pos;
                m_io.Seek(FrameTableOfs);
                __raw_frameTable = m_io.ReadBytes(FrameTableLen);
                var io___raw_frameTable = new KaitaiStream(__raw_frameTable);
                _frameTable = new FrameIndex(io___raw_frameTable, this, m_root);
                m_io.Seek(_pos);
                f_frameTable = true;
                return _frameTable;
            }
        }
        private byte[] _signature;
        private byte _versionMinor;
        private byte _versionMajor;
        private Linktype _macType;
        private WindowsSystemtime _timeCaptureStart;
        private uint _frameTableOfs;
        private uint _frameTableLen;
        private uint _userDataOfs;
        private uint _userDataLen;
        private uint _commentOfs;
        private uint _commentLen;
        private uint _statisticsOfs;
        private uint _statisticsLen;
        private uint _networkInfoOfs;
        private uint _networkInfoLen;
        private uint _conversationStatsOfs;
        private uint _conversationStatsLen;
        private MicrosoftNetworkMonitorV2 m_root;
        private KaitaiStruct m_parent;
        private byte[] __raw_frameTable;
        public byte[] Signature { get { return _signature; } }

        /// <summary>
        /// Format version (minor), BCD
        /// </summary>
        public byte VersionMinor { get { return _versionMinor; } }

        /// <summary>
        /// Format version (major), BCD
        /// </summary>
        public byte VersionMajor { get { return _versionMajor; } }

        /// <summary>
        /// Network topology type of captured data
        /// </summary>
        public Linktype MacType { get { return _macType; } }

        /// <summary>
        /// Timestamp of capture start
        /// </summary>
        public WindowsSystemtime TimeCaptureStart { get { return _timeCaptureStart; } }
        public uint FrameTableOfs { get { return _frameTableOfs; } }
        public uint FrameTableLen { get { return _frameTableLen; } }
        public uint UserDataOfs { get { return _userDataOfs; } }
        public uint UserDataLen { get { return _userDataLen; } }
        public uint CommentOfs { get { return _commentOfs; } }
        public uint CommentLen { get { return _commentLen; } }
        public uint StatisticsOfs { get { return _statisticsOfs; } }
        public uint StatisticsLen { get { return _statisticsLen; } }
        public uint NetworkInfoOfs { get { return _networkInfoOfs; } }
        public uint NetworkInfoLen { get { return _networkInfoLen; } }
        public uint ConversationStatsOfs { get { return _conversationStatsOfs; } }
        public uint ConversationStatsLen { get { return _conversationStatsLen; } }
        public MicrosoftNetworkMonitorV2 M_Root { get { return m_root; } }
        public KaitaiStruct M_Parent { get { return m_parent; } }
        public byte[] M_RawFrameTable { get { return __raw_frameTable; } }
    }
}