轉載源: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各字段說明:
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

========================================================
這里再把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;
##################################################
文件頭 24字節
數據報頭 + 數據報 數據包頭為16字節,后面緊跟數據報
數據報頭 + 數據報 ......
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大
下面主要介紹下Ethereal默認的*.pcap文件保存格式。
Pcap文件頭24B各字段說明:
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

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(×tamp1,buff,4);
memcpy(×tamp2,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" 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 OpenBSD1 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

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還是很容易轉換的)