PCAP文件格式分析(做抓包軟件之必備)


轉載源:http://blog.csdn.net/anzijin/article/details/2008333

    http://www.ebnd.cn/2009/09/07/file-format-analysis-of-wireshark-pcap/

    

 

前段時間因工作要求,需要對各種數據包進行分析和操作,內容涉及網路協議分析,socket,文件操作等。在此分享下學習和實踐的經驗。

首先介紹下網絡抓包、協議分析的必備軟件Ethereal,新版(Wireshark)以下還以 Ethereal代之,目前最新版本已經支持在無線局域網抓包了。Linux和Windows均有對應安裝包,它們分別是gcc和VC++編譯的。不過 Windows下是基於Winpcap而Linux下則是Libcap。Ethereal作為網路協議分析、學習、開發的敲門軟件,其使用技巧及其原理機 制(BPF)網上都有比較詳盡的介紹,當初我收集的相關資料隨后也會上傳,不再多說。下面主要介紹下Ethereal默認的*.pcap文件保存格式。

Pcap文件頭24B各字段說明:

Magic:4B:0x1A 2B 3C 4D:用來標示文件的開始
Major:2B,0x02 00:當前文件主要的版本號
Minor:2B,0x04 00當前文件次要的版本號
ThisZone:4B當地的標准時間;全零
SigFigs:4B時間戳的精度;全零
SnapLen:4B最大的存儲長度
LinkType:4B鏈路類型
常用類型:
0 BSD loopback devices, except for later OpenBSD
1            Ethernet, and Linux loopback devices
6            802.5 Token Ring
7            ARCnet
8            SLIP
9            PPP
10           FDDI
100         LLC/SNAP-encapsulated ATM
101         “raw IP”, with no link
102         BSD/OS SLIP
103         BSD/OS PPP
104         Cisco HDLC
105         802.11
108         later OpenBSD loopback devices (with the AF_value in network byte order)
113         special Linux “cooked” capture
114         LocalTalk
 
Packet  包頭和Packet 數據組成
字段說明:
Timestamp:時間戳高位,精確到seconds
Timestamp:時間戳低位,精確到microseconds
Caplen:當前數據區的長度,即抓取到的數據幀長度,由此可以得到下一個數據幀的位置。
Len:離線數據長度 網絡中實際數據幀的長度,一般不大於caplen,多數情況下和Caplen數值相等。
Packet  數據:即 Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的后面,就是當前PCAP文件中存放的下一個Packet數據包,也就 是說:PCAP文件里面並沒有規定捕獲的Packet數據包之間有什么間隔字符串,下一組數據在文件中的起始位置。我們需要靠第一個Packet包確定。 最后,Packet數據部分的格式其實就是標准的網路協議格式了可以任何網絡教材上找得到。
 

 

 

========================================================

這里再把pcap文件頭的結構定義添上:

typedef unsigned long  DWORD;
typedef unsigned short  WORD;
typedef unsigned char  BYTE;

typedef struct PCAP_FILE_HEADER
{
 DWORD magic;
 WORD versionMajor;
 WORD versionMinor;
 DWORD thisZone;
 DWORD sigfigs;
 DWORD snapLen;
 DWORD linkType;
}PcapFileHeader, *PPcapFileHeader;

##################################################
pcap文件格式是常用的數據報存儲格式,包括wireshark在內的主流抓包軟件都可以生成這種格式的數據包
下面對這種格式的文件簡單分析一下: 
 
pcap文件的格式為:
  文件頭    24字節
  數據報頭 + 數據報  數據包頭為16字節,后面緊跟數據報
  數據報頭 + 數據報  ......
 
pcap.h里定義了文件頭的格式
struct pcap_file_header {
        bpf_u_int32 magic;
        u_short version_major;
        u_short version_minor;
        bpf_int32 thiszone;    
        bpf_u_int32 sigfigs;   
        bpf_u_int32 snaplen;   
        bpf_u_int32 linktype;  
};
看一下各字段的含義:
 magic:   4字節 pcap文件標識 目前為“d4 c3 b2 a1”
 major:   2字節主版本號     #define PCAP_VERSION_MAJOR 2
 minor:   2字節次版本號     #define PCAP_VERSION_MINOR 4
 thiszone:4字節時區修正     並未使用,目前全為0
 sigfigs: 4字節精確時間戳   並未使用,目前全為0
 snaplen: 4字節抓包最大長度如果要抓全,設為0x0000ffff(65535),
          tcpdump -s 0就是設置這個參數,缺省為68字節
 linktype:4字節鏈路類型    一般都是1:ethernet
 
 
 
數據報頭的格式
struct pcap_pkthdr {
        struct timeval ts;     
        bpf_u_int32 caplen;    
        bpf_u_int32 len;       
};
struct timeval {
        long            tv_sec;        
        suseconds_t     tv_usec;       
};
 ts:    8字節 抓包時間 4字節表示秒數,4字節表示微秒數
 caplen:4字節 保存下來的包長度(最多是snaplen,比如68字節)
 len:   4字節數據報的真實長度,如果文件中保存的不是完整數據包,可能比caplen大
 
下圖僅供參考
pcap文件格式分析
 
 
 
########################################

下面主要介紹下Ethereal默認的*.pcap文件保存格式。 

Pcap文件頭24B各字段說明:

Magic:4B:0x1A 2B 3C 4D:用來標示文件的開始
Major:2B,0x02 00:當前文件主要的版本號     
Minor:2B,0x04 00當前文件次要的版本號
ThisZone:4B當地的標准時間;全零
SigFigs:4B時間戳的精度;全零
SnapLen:4B最大的存儲長度    
LinkType:4B鏈路類型
常用類型:
 0            BSD loopback devices, except for later OpenBSD
       1            Ethernet, and Linux loopback devices
       6            802.5 Token Ring
       7            ARCnet
       8            SLIP
       9            PPP
       10           FDDI
       100         LLC/SNAP-encapsulated ATM
       101         "raw IP", with no link
       102         BSD/OS SLIP
       103         BSD/OS PPP
       104         Cisco HDLC
       105         802.11
       108         later OpenBSD loopback devices (with the AF_value in network byte order)
       113         special Linux "cooked" capture
       114         LocalTalk
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Packet 包頭和Packet數據組成
字段說明:
Timestamp:時間戳高位,精確到seconds     
Timestamp:時間戳低位,精確到microseconds
Caplen:當前數據區的長度,即抓取到的數據幀長度,由此可以得到下一個數據幀的位置。
Len:離線數據長度 網絡中實際數據幀的長度,一般不大於caplen,多數情況下和Caplen數值相等。
Packet 數據: 即 Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的后面,就是當前PCAP文件中存放的下一個Packet數據包,也就 是說:PCAP文件里面並沒有規定捕獲的Packet數據包之間有什么間隔字符串,下一組數據在文件中的起始位置。我們需要靠第一個Packet包確定。 最后,Packet數據部分的格式其實就是標准的網路協議格式了可以任何網絡教材上找得到。



以下是我的實現,針對自定義的UDP的抓包文件進行解析
typedef struct tagIpHead
{
    int version;//版本
    int headLength; //頭長度
    int  diffsever; 
    int  totallength; //總長度
    int  identification; 
    int  flag;
    int  fragment;
    int  ttl;
    int  protocoltype; //協議類型
    int  checksum;
    unsigned long  srcip;//源ip
    unsigned long  dstip;//目的ip
}IP_HEAD;
typedef struct tagUdpHead

    unsigned short  srcport; //源端口
    unsigned short  dstport; //目的端口
    int   length; //udp包長度
}UDP_HEAD;

unsigned long FileParse::Parse( const char* FileName,bool& bThreadRun)//,HWND hwnd )
{
    if (_wass_session)
    {
        delete _wass_session;
        _wass_session = NULL;
    }
    _wass_session = new WassSessions();
    //////////////////////////////////////////////////////////////////////////
    unsigned long lRes =0;
    FILE* pFile=NULL;
    int nReadSize = 0;
    char buff[FILE_READ_LEN];
    char acip[30];
    char portalip[30];
    char radiusip[30];
    unsigned long timestamp1;
    unsigned long timestamp2;
    CConfigure* config=new CConfigure();

    if (config)
    {
        //讀取ip地址,添加到iplist中
        unsigned long ipTmp=0; 
        unsigned short portTmp=0;
        config->getIPConfig(acip,portalip,radiusip);
        cut_ip(acip,ipTmp,portTmp);
        acport_list.push_back(portTmp);
        acip_list.push_back(ipTmp);
        cut_ip(portalip,ipTmp,portTmp);
        portalip_list.push_back(ipTmp);
        portalport_list.push_back(portTmp);
        delete config;
        config = NULL;
    }
    //////////////////////////////////////////////////////////////////////////
    memset(buff,0,FILE_READ_LEN);
    do 
    {


        pFile =fopen(FileName,"rb"); 
        //pFile =_open( FileName, _O_RDONLY | _O_BINARY ); 
        if (!pFile)
        {
            //failed for the file opened
            fprintf(stderr, "Open the file failed:%s ", strerror(errno));

            lRes = 2;
            break;
        }
        nReadSize = fread(buff,sizeof(char),24,pFile);
        if (nReadSize == 24)
        {
            while (!feof(pFile) && bThreadRun) 
            {
                memset(buff,0,FILE_READ_LEN);
                nReadSize = fread(buff,sizeof(char),16,pFile);
                unsigned long nPacketLen=0;
                memcpy(&timestamp1,buff,4);
                memcpy(&timestamp2,buff+4,4);
                memcpy(&nPacketLen,buff+8,4);
                //nPacketLen = ntohl(nPacketLen);
                char* buf = new char[nPacketLen];
                memset(buf,0,nPacketLen);

                int nReadCount=0;
                //讀取包
                while (nReadCount < nPacketLen)
                {
                    nReadSize = fread(buff,sizeof(char),nPacketLen-nReadCount,pFile);
                    memcpy(buf+nReadCount,buff,nReadSize);
                    nReadCount += nReadSize;
                }
                //在此處處理ip/udp包部分
                int nOffset=14;//數據偏移位置
                _ip->Parse(buf+nOffset);//ip解析
                if(_ip->wass_ip_head.protocoltype==17)//只處理UDP
                {
                    nOffset += 20;
                    _udp->Parse(buf+nOffset);//udp解析
                    nOffset +=8;
                    std::list<unsigned long>::iterator acit= acip_list.begin();
                    std::list<unsigned long>::iterator portalit = portalip_list.begin();
                    bool bFoundIP = false;
                    //暫時不考慮算法,遍歷ip地址
                    //while (acit++ != acip_list.end())
                    for (;acit != acip_list.end();acit++)
                    {
                        unsigned long aIP = *acit;
                        char aTmp[20];

                        IPULongToString(aIP,aTmp);
                        IPULongToString(_ip->wass_ip_head.dstip,aTmp);
                        if (_ip->wass_ip_head.dstip== *acit  || _ip->wass_ip_head.srcip == *acit)
                        {
                        for (;portalit !=portalip_list.end();portalit++)
                        {
                            if (_ip->wass_ip_head.dstip== *portalit  || _ip->wass_ip_head.srcip == *portalit)
                            {
                                bFoundIP = true;
                                break;
                            }
                        }
                        break;
                        }
                    }
                    if (bFoundIP)
                    {
                        //此處是表示可以進行數據的解析
                        _portalPacket = new CPortalPacket();
                        _portalPacket->parse(buf + nOffset,nPacketLen - nOffset);
                    //設置包的源IP和目的IP,源端口,目的端口
                        _portalPacket->setIpAndPort(_ip->wass_ip_head.srcip,
                            _ip->wass_ip_head.dstip,_udp->wass_udp_head.srcport,_udp->wass_udp_head.dstport);
                        _portalPacket->setPacketTime(timestamp1,timestamp2); 
                        _wass_session->AddPacket(_portalPacket,_sessions);
                    }
                    else
                    {
                        
                    }
                }
                if (buf)
                {
                    delete [] buf;

                }

            }
        }
    } while (false);
    if (pFile)
    {
        fclose(pFile);
    }

    //////////////////////////////////////////////////////////////////////////
    //::PostMessage(_hwnd,WM_FINISHED,0,0);
    return lRes;
}
 
 
 
 
 
------------------------------------------------------------------------------------------------------------
一、基本格式:

文件頭 數據包頭 數據報 數據包頭 數據報......

pcap文件格式 結構

 

 

文件頭

格式如結構體pcap_file_header

數據包頭1

格式如pcap_pkthdr

數據包

數據包

數據包頭n-1

格式如pcap_pkthdr

數據包

數據包

數據包頭n

格式如pcap_pkthdr

數據包

數據包


二、文件頭結構體:
sturct pcap_file_header
{
DWORD              magic;
      WORD                 version_major;
      WORD                 version_minor;
DWORD              thiszone;
DWORD              sigfigs;
DWORD              snaplen;
DWORD              linktype;
}

說明:

1、標識位:32位的,這個標識位的值是16進制的 0xa1b2c3d4。
a 32-bit        magic number ,The magic number has the value hex a1b2c3d4.
2、主版本號:16位, 默認值為0x2。
a 16-bit          major version number,The major version number should have the value 2.
3、副版本號:16位,默認值為0x04。
a 16-bit          minor version number,The minor version number should have the value 4.
4、區域時間:32位,實際上該值並未使用,因此可以將該位設置為0。
a 32-bit          time zone offset field that actually not used, so you can (and probably should) just make it 0;
5、精確時間戳:32位,實際上該值並未使用,因此可以將該值設置為0。
a 32-bit          time stamp accuracy field tha not actually used,so you can (and probably should) just make it 0;
6、數據包最大長度:32位,該值設置所抓獲的數據包的最大長度,如果所有數據包都要抓獲,將該值設置為65535; 例如:想獲取數據包的前64字節,可將該值設置為64。
a 32-bit          snapshot length&quot; field;The snapshot length field should be the maximum number of bytes perpacket that will be captured. If the entire packet is captured, make it 65535; if you only capture, for example, the first 64 bytes of the packet, make it 64.
7、鏈路層類型:32位, 數據包的鏈路層包頭決定了鏈路層的類型。
a 32-bit link layer type field.The link-layer type depends on the type of link-layer header that the
packets in the capture file have:

以下是數據值與鏈路層類型的對應表
0            BSD       loopback devices, except for later OpenBSD
1            Ethernet, and Linux loopback devices   以太網類型,大多數的數據包為這種類型。
6            802.5 Token Ring
7            ARCnet
8            SLIP
9            PPP
10          FDDI
100        LLC/SNAP-encapsulated ATM
101        raw IP, with no link
102        BSD/OS SLIP
103        BSD/OS PPP
104        Cisco HDLC
105        802.11
108        later OpenBSD loopback devices (with the AF_value in network byte order)
113               special Linux cooked capture
114               LocalTalk




三、數據包頭結構體:
struct pcap_pkthdr
{
struct timeval         ts;
      DWORD              caplen;
      DWORD              len;
}

struct timeval
{
DWORD       GMTtime;
DWORD       microTime

說明:

1、時間戳,包括:
秒計時:32位,一個UNIX格式的精確到秒時間值,用來記錄數據包抓獲的時間,記錄方式是記錄從格林尼治時間的1970年1月1日 00:00:00 到抓包時經過的秒數;
毫秒計時:32位, 抓取數據包時的毫秒值。
a time stamp, consisting of:
a UNIX-format time-in-seconds when the packet was captured, i.e. the number of seconds since January 1,1970, 00:00:00 GMT (that GMT, *NOT* local time!);   
the number of microseconds since that second when the packet was captured;

2、數據包長度:32位 ,標識所抓獲的數據包保存在pcap文件中的實際長度,以字節為單位。
a 32-bit value giving the number of bytes of packet data that were captured;

3、數據包實際長度: 所抓獲的數據包的真實長度,如果文件中保存不是完整的數據包,那么這個值可能要比前面的數據包長度的值大。
a 32-bit value giving the actual length of the packet, in bytes (which may be greater than the previous number, if you are not saving the entire packet).

 

 

Wireshark的Pcap文件格式分析

前段時間因工作要求,需要對各種數據包進行分析和操作,內容涉及網路協議分析,socket,文件操作等。在此分享下學習和實踐的經驗。  

  首先介紹下網絡抓包、協議分析的必備軟件Ethereal,新版(Wireshark)以下還以 Ethereal代之,目前最新版本已經支持在無線局域網抓包了。Linux和Windows均有對應安裝包,它們分別是gcc和VC++編譯的。不過 Windows下是基於Winpcap而Linux下則是Libcap。Ethereal作為網路協議分析、學習、開發的敲門軟件,其使用技巧及其原理機制(BPF)網上都有比較詳盡的介紹,當初我收集的相關資料隨后也會上傳,不再多說。下面主要介紹下Ethereal默認的*.pcap文件保存格式。 

Pcap文件頭24B各字段說明:

Magic:4B:0x1A 2B 3C 4D:用來標示文件的開始Major:2B,0x02 00:當前文件主要的版本號      Minor:2B,0x04 00當前文件次要的版本號ThisZone:4B當地的標准時間;全零SigFigs:4B時間戳的精度;全零SnapLen:4B最大的存儲長度    LinkType:4B鏈路類型常用類型: 0            BSD loopback devices, except for later OpenBSD
       1            Ethernet, and Linux loopback devices
       6            802.5 Token Ring
       7            ARCnet
       8            SLIP
       9            PPP
       10           FDDI
       100         LLC/SNAP-encapsulated ATM
       101         "raw IP", with no link
       102         BSD/OS SLIP
       103         BSD/OS PPP
       104         Cisco HDLC
       105         802.11
       108         later OpenBSD loopback devices (with the AF_value in network byte order)
       113         special Linux "cooked" capture
       114         LocalTalk   Packet 包頭和Packet數據組成字段說明:Timestamp:時間戳高位,精確到seconds      Timestamp:時間戳低位,精確到microsecondsCaplen:當前數據區的長度,即抓取到的數據幀長度,由此可以得到下一個數據幀的位置。Len:離線數據長度:網絡中實際數據幀的長度,一般不大於caplen,多數情況下和Caplen數值相等。Packet 數據:即 Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的后面,就是當前PCAP文件中存放的下一個Packet數據包,也就是說:PCAP文件里面並沒有規定捕獲的Packet數據包之間有什么間隔字符串,下一組數據在文件中的起始位置。我們需要靠第一個Packet包確定。最后,Packet數據部分的格式其實就是標准的網路協議格式了可以任何網絡教材上找得到。
 
-------------------------------------------------------------------

Python讀取pcap文件

 

From:http://blog.sina.com.cn/s/blog_4b5039210100gnlu.html

 

    想試一試讀取pcap文件的內容,並且分析出pcap文件頭,每一包數據的pcap頭,每一包的數據內容(暫時不包括數據包的協議解析),關於pcap文件的格式,可以參看:http://blog.sina.com.cn/s/blog_4b5039210100fzrt.html

    搞了一下午,寫了一個py文件,rdpcap.py,想把里面的二進制文件全部弄成十六進制的,然后作為字符串寫入到一個txt文件,轉化成字符串是為了顯示看起來方便。

    程序如下:

 

#!/usr/bin/env python
#coding=utf-8
#讀取pcap文件,解析相應的信息,為了在記事本中顯示的方便,把二進制的信息

import struct

fpcap = open('test.pcap','rb')
ftxt = open('result.txt','w')

string_data = fpcap.read()

#pcap文件包頭解析
pcap_header = {}
pcap_header['magic_number'] = string_data[0:4]
pcap_header['version_major'] = string_data[4:6]
pcap_header['version_minor'] = string_data[6:8]
pcap_header['thiszone'] = string_data[8:12]
pcap_header['sigfigs'] = string_data[12:16]
pcap_header['snaplen'] = string_data[16:20]
pcap_header['linktype'] = string_data[20:24]
#把pacp文件頭信息寫入result.txt
ftxt.write("Pcap文件的包頭內容如下: \n")
for key in ['magic_number','version_major','version_minor','thiszone',
            'sigfigs','snaplen','linktype']:
    ftxt.write(key+ " : " + repr(pcap_header[key])+'\n')
          

#pcap文件的數據包解析
step = 0
packet_num = 0
packet_data = []

pcap_packet_header = {}
i =24

while(i<len(string_data)):
     
      #數據包頭各個字段
      pcap_packet_header['GMTtime'] = string_data[i:i+4]
      pcap_packet_header['MicroTime'] = string_data[i+4:i+8]
      pcap_packet_header['caplen'] = string_data[i+8:i+12]
      pcap_packet_header['len'] = string_data[i+12:i+16]
      #求出此包的包長len
      packet_len = struct.unpack('I',pcap_packet_header['len'])[0]
      #寫入此包數據
      packet_data.append(string_data[i+16:i+16+packet_len])
      i = i+ packet_len+16
      packet_num+=1
   
   
   
   
#把pacp文件里的數據包信息寫入result.txt
for i in range(packet_num):
    #先寫每一包的包頭
    ftxt.write("這是第"+str(i)+"包數據的包頭和數據:"+'\n')
    for key in ['GMTtime','MicroTime','caplen','len']:
        ftxt.write(key+' : '+repr(pcap_packet_header[key])+'\n')
    #再寫數據部分
    ftxt.write('此包的數據內容'+repr(packet_data[i])+'\n')
ftxt.write('一共有'+str(packet_num)+"包數據"+'\n')
      
ftxt.close()
fpcap.close()

 

最終得到的result文件如下所示:字段顯示的都是十六進制,其中的數據部分和wireshark打開,顯示的十六進制窗口一樣。

(其實如果程序想到得到某一個或某幾個字節的十進制數,用struct還是很容易轉換的)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM