攔截網路卡封包並且對封包內容進行分析 Part 2

Hold up packages from network adepter and analyze it. Part 2

在上一篇

我們已經成功的攔截到網路卡的封包

在這一篇我們將開始進行解析

封包的資料格式有一定的資料結構

首先我們將對IP的表頭進行拆解

然後再以TCP的資料結構為範例

進行解析

 

關於IP表頭的資料格式

可以參考以下連結

http://freesoft.org/CIE/Course/Section3/7.htm

 

在下面的程式碼中

我們首先跟據表頭的格式進行拆解

拆解完畢之後

判斷協定是否為TCP

如果是的話

才繼續往下進行分析

	namespace WindowsFormsApplication1
{
    public class AnalyzePackage
    {

        private eProtocol _Protocol;
        public eProtocol Protocol { get { return _Protocol; } }

        private int _HeaderLength;
        private int _Version;

        private int _DesPort;
        public int DesPort { get { return _DesPort; } }


        private int _SrcPort;
        public int SrcPort { get {return _SrcPort;} }


        private IPAddress _DesIP;
        public IPAddress DesIP { get { return _DesIP; } }


        private IPAddress _SrcIP;
        public IPAddress SrcIP { get { return _SrcIP; } }


        private TcpPackage _mTcpPackage;
        public TcpPackage Tcp { get { return _mTcpPackage; } }



        public AnalyzePackage(byte[] byData, int iLength)
        {
            byte[] byData_ = new byte[iLength];

            Array.Copy(byData, 0, byData_, 0, iLength);

            //  get Header length
            _Version = (byData_[0] & 0xF0) >> 4;
            _HeaderLength = (byData_[0] & 0x0F) * 4 /* sizeof(int) */;


            // get protocol
            if (Enum.IsDefined(typeof(eProtocol), (int)byData_[9]))
                _Protocol = (eProtocol)byData_[9];
            else
                _Protocol = eProtocol.Other;


            // get ip
            byte[] byIP_ = new byte[4];

            Array.Copy(byData_, 12, byIP_, 0, 4);
            _SrcIP = new IPAddress(byIP_);

            Array.Copy(byData_, 16, byIP_, 0, 4);
            _DesIP = new IPAddress(byIP_);



            // get port
            _SrcPort = byData_[_HeaderLength] * 256 + byData_[_HeaderLength + 1];
            _DesPort = byData_[_HeaderLength + 2] * 256 + byData_[_HeaderLength + 3];



            if (_Protocol == eProtocol.Tcp)
            {
                byte[] byTcp_ = new byte[byData_.Length - _HeaderLength];
                Array.Copy(byData_, _HeaderLength, byTcp_, 0, byTcp_.Length);
                _mTcpPackage = new TcpPackage(byTcp_);
            }
            else
            {
                _mTcpPackage = null;
            }
        }
    }



    public enum eProtocol
    {
        Ggp = 3,
        Icmp = 1,
        Idp = 22,
        Igmp = 2,
        IP = 4,
        ND = 77,
        Pup = 12,
        Tcp = 6,
        Udp = 17,
        Other = -1
    }
}

 

上面程式碼中的列舉eProtocol中的定義

可以參考這邊

http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml

 

 

 

接下來則是對TCP的格是進行解析

TCP格式的內容可以參考這邊

http://tools.ietf.org/html/rfc793

下面程式碼中的類別

其中有一個欄位 ApplicationData

便是儲存解析完後應用層的資料

	namespace WindowsFormsApplication1
{
    public class TcpPackage
    {
        private UInt16 _SrcPort;
        public int SourcePort { get { return (int)_SrcPort; } }

        private UInt16 _DesPort;
        public int DesPort { get { return (int)_DesPort; } }

        private UInt32 _SeqNum;
        public int SeqNum { get { return (int)_SeqNum; } }

        private UInt32 _AckNum;
        public int AckNum { get { return (int)_AckNum; } }

        private UInt16 _Windows;
        public int Windows { get { return (int)_Windows; } }

        private UInt16 _Shecksum;
        public int Shecksum { get { return (int)_Shecksum; } }

        private UInt16 _UrgentPoint;
        public int UrgentPoint { get { return (int)_UrgentPoint; } }

        private byte[] _ApplicationData;
        public byte[] ApplicationData { get { return _ApplicationData; } }

        public TcpPackage(byte[] byData)
        {
            byte[] byPort_ = new byte[4];
            Array.Copy(byData, 0, byPort_, 0, 4);
            Array.Reverse(byPort_);

            _SrcPort     = BitConverter.ToUInt16(byPort_, 2);
            _DesPort     = BitConverter.ToUInt16(byPort_, 0);
            _SeqNum      = BitConverter.ToUInt32(byData, 12);
            _AckNum      = BitConverter.ToUInt32(byData, 8);
            _Windows      = BitConverter.ToUInt16(byData, 4);
            _Shecksum     = BitConverter.ToUInt16(byData, 2);
            _UrgentPoint= BitConverter.ToUInt16(byData, 0);
            
            _ApplicationData = new byte[byData.Length - 20];
            Array.Copy(byData, 20, _ApplicationData, 0, byData.Length - 20);
        }
    }
}