第一部分:PCAP包文件格式
一?基本格式:
???文件頭?數據包頭數據報數據包頭數據報......
二、文件頭:
???
???文件頭結構體
?sturct?pcap_file_header
?{
??????DWORD???????????magic;
??????DWORD???????????version_major;
??????DWORD???????????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
三?packet數據包頭:
?
struct?pcap_pkthdr
{
struct?tim?????????ts;
??????DWORD??????????????caplen;
??????DWORD??????????????len;
}
?
struct?tim
{
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).
四:packet數據:
??即Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的后面,就是當前PCAP文件中存放的下一個Packet數據包,也就是說:PCAP文件里面并沒有規定捕獲的Packet數據包之間有什么間隔字符串,下一組數據在文件中的起始位置。我們需要靠第一個Packet包確定。最后,Packet數據部分的格式其實就是標準的網路協議格式了可以任何網絡教材上找得到。
?
?
五:舉例分析
?
圖中最開始的綠色部分就是24?Bytes的Pcap?Header,接下來紅色的16?Bytes是第一個消息的Pcap?Header。后面的紅色的16?Bytes是第二個消息的Pcap?Header。兩塊藍色的部分分別是兩個消息從鏈路層開始的完整內容。在網絡上實際傳輸的數據包在數據鏈路層上每一個Packet開始都會有7個用于同步的字節和一個用于標識該Packet開始的字節,最后還會有四個CRC校驗字節;而PCAP文件中會把前8個字節和最后4個校驗自己去掉,因為這些信息對于協議分析是沒有用的。
用Wireshark打開一個PCAP數據包,每條消息的所有field會被解析出來并會按照協議層次折疊起來。第一層顯示的是FrameXXX,這一級別沒有對應某層具體的協議,而是對本條消息的一個概括性總結,描述了一些有用的概括性信息,比如從里面我們可以看到本條消息各種協議的層次關系,展開其它協議層之后對應的是該協議的各個域,如下圖所示:
?
第二部分:PCAP文件解析
1、? pcap解析工具?Xplico
Xplico?是一個從?pcap?文件中解析出IP流量數據的工具,可解析每個郵箱?(POP,?IMAP,?和?SMTP?協議),?所有?HTTP?內容,?VoIP?calls?(SIP)?等等
?
2、?C語言實現PCAP文件分析
實現步驟:
1
)用
Wireshark
軟件抓包得到
test.pcap
文件
2
)程序:分析
pcap
文件頭?
->?
分析
pcap_pkt
頭?
->?
分析幀頭?
->?
分析
ip
頭?
->?
分析
tcp
頭?
->?
分析
http
信息
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<time.h>
#define?BUFSIZE?10240
#define?STRSIZE?1024
typedef?long?bpf_int32;
typedef?unsigned?long?bpf_u_int32;
typedef?unsigned?short??u_short;
typedef?unsigned?long?u_int32;
typedef?unsigned?short?u_int16;
typedef?unsigned?char?u_int8;
//pacp 文件頭結構體
struct?pcap_file_header
{
bpf_u_int32?magic;???????/*?0xa1b2c3d4?*/
u_short?version_major;???/*?magjor?Version?2?*/
u_short?version_minor;???/*?magjor?Version?4?*/
bpf_int32?thiszone;??????/*?gmt?to?local?correction?*/
bpf_u_int32?sigfigs;?????/*?accuracy?of?timestamps?*/
bpf_u_int32?snaplen;?????/*?max?length?saved?portion?of?each?pkt?*/
bpf_u_int32?linktype;????/*?data?link?type?(LINKTYPE_*)?*/
};
// 時間戳
struct?time_val
{
long?tv_sec;?????????/*?seconds? 含義同? time_t? 對象的值? */
long?tv_usec;????????/*?and?microseconds?*/
};
//pcap 數據包頭結構體
struct?pcap_pkthdr
{
struct?time_val?ts;??/*?time?stamp?*/
bpf_u_int32?caplen;?/*?length?of?portion?present?*/
bpf_u_int32?len;????/*?length?this?packet?(off?wire)?*/
};
// 數據幀頭
typedef?struct?FramHeader_t
{?//Pcap 捕獲的數據幀頭
u_int8?DstMAC[6];?// 目的 MAC 地址
u_int8?SrcMAC[6];?// 源 MAC 地址
u_short?FrameType;????// 幀類型
}?FramHeader_t;
//IP 數據報頭
typedef?struct?IPHeader_t
{?//IP 數據報頭
u_int8?Ver_HLen;???????// 版本 + 報頭長度
u_int8?TOS;????????????// 服務類型
u_int16?TotalLen;???????// 總長度
u_int16?ID;?// 標識
u_int16?Flag_Segment;???// 標志 + 片偏移
u_int8?TTL;????????????// 生存周期
u_int8?Protocol;???????// 協議類型
u_int16?Checksum;???????// 頭部校驗和
u_int32?SrcIP;?// 源 IP 地址
u_int32?DstIP;?// 目的 IP 地址
}?IPHeader_t;
//TCP 數據報頭
typedef?struct?TCPHeader_t
{?//TCP 數據報頭
u_int16?SrcPort;?// 源端口
u_int16?DstPort;?// 目的端口
u_int32?SeqNO;?// 序號
u_int32?AckNO;?// 確認號
u_int8?HeaderLen;?// 數據報頭的長度 (4?bit)?+? 保留 (4?bit)
u_int8?Flags;?// 標識 TCP 不同的控制消息
u_int16?Window;?// 窗口大小
u_int16?Checksum;?// 校驗和
u_int16?UrgentPointer;??// 緊急指針
}TCPHeader_t;
//
void?match_http(FILE?*fp,?char?*head_str,?char?*tail_str,?char?*buf,?int?total_len);?// 查找? http? 信息函數
//
int?main()
{
struct?pcap_file_header?*file_header;
struct?pcap_pkthdr?*ptk_header;
IPHeader_t?*ip_header;
TCPHeader_t?*tcp_header;
FILE?*fp,?*output;
int???pkt_offset,?i=0;
int?ip_len,?http_len,?ip_proto;
int?src_port,?dst_port,?tcp_flags;
char?buf[BUFSIZE],?my_time[STRSIZE];
char?src_ip[STRSIZE],?dst_ip[STRSIZE];
char??host[STRSIZE],?uri[BUFSIZE];
// 初始化
file_header?=?(struct?pcap_file_header?*)malloc(sizeof(struct?pcap_file_header));
ptk_header??=?(struct?pcap_pkthdr?*)malloc(sizeof(struct?pcap_pkthdr));
ip_header?=?(IPHeader_t?*)malloc(sizeof(IPHeader_t));
tcp_header?=?(TCPHeader_t?*)malloc(sizeof(TCPHeader_t));
memset(buf,?0,?sizeof(buf));
//
if((fp?=?fopen(“test.pcap”,”r”))?==?NULL)
{
printf(“error:?can?not?open?pcap?file\n”);
exit(0);
}
if((output?=?fopen(“output.txt”,”w+”))?==?NULL)
{
printf(“error:?can?not?open?output?file\n”);
exit(0);
}
// 開始讀數據包
pkt_offset?=?24;?//pcap 文件頭結構? 24 個字節
while(fseek(fp,?pkt_offset,?SEEK_SET)?==?0)?// 遍歷數據包
{
i++;
//pcap_pkt_header?16?byte
if(fread(ptk_header,?16,?1,?fp)?!=?1)?// 讀 pcap 數據包頭結構
{
printf(“\nread?end?of?pcap?file\n”);
break;
}
pkt_offset?+=?16?+?ptk_header->caplen;???// 下一個數據包的偏移值
strftime(my_time,?sizeof(my_time),?“%Y-%m-%d?%T”,?localtime(&(ptk_header->ts.tv_sec)));?// 獲取時間
//?printf(“%d:?%s\n”,?i,?my_time);
// 數據幀頭? 14 字節
fseek(fp,?14,?SEEK_CUR);?// 忽略數據幀頭
//IP 數據報頭? 20 字節
if(fread(ip_header,?sizeof(IPHeader_t),?1,?fp)?!=?1)
{
printf(“%d:?can?not?read?ip_header\n”,?i);
break;
}
inet_ntop(AF_INET,?(void?*)&(ip_header->SrcIP),?src_ip,?16);
inet_ntop(AF_INET,?(void?*)&(ip_header->DstIP),?dst_ip,?16);
ip_proto?=?ip_header->Protocol;
ip_len?=?ip_header->TotalLen;?//IP 數據報總長度
//?printf(“%d:??src=%s\n”,?i,?src_ip);
if(ip_proto?!=?0×06)?// 判斷是否是? TCP? 協議
{
continue;
}
//TCP 頭? 20 字節
if(fread(tcp_header,?sizeof(TCPHeader_t),?1,?fp)?!=?1)
{
printf(“%d:?can?not?read?ip_header\n”,?i);
break;
}
src_port?=?ntohs(tcp_header->SrcPort);
dst_port?=?ntohs(tcp_header->DstPort);
tcp_flags?=?tcp_header->Flags;
//?printf(“%d:??src=%x\n”,?i,?tcp_flags);
if(tcp_flags?==?0×18)?//?(PSH,?ACK)?3 路握手成功后
{
if(dst_port?==?80)?//?HTTP?GET 請求
{
http_len?=?ip_len?–?40;?//http? 報文長度
match_http(fp,?“Host:?“,?“\r\n”,?host,?http_len);?// 查找? host? 值
match_http(fp,?“GET?“,?“HTTP”,?uri,?http_len);?// 查找? uri? 值
sprintf(buf,?“%d:??%s??src=%s:%d??dst=%s:%d??%s%s\r\n”,?i,?my_time,?src_ip,?src_port,?dst_ip,?dst_port,?host,?uri);
//printf(“%s”,?buf);
if(fwrite(buf,?strlen(buf),?1,?output)?!=?1)
{
printf(“output?file?can?not?write”);
break;
}
}
}
}?//?end?while
fclose(fp);
fclose(output);
return?0;
}
// 查找? HTTP? 信息
void?match_http(FILE?*fp,?char?*head_str,?char?*tail_str,?char?*buf,?int?total_len)
{
int?i;
int?http_offset;
int?head_len,?tail_len,?val_len;
char?head_tmp[STRSIZE],?tail_tmp[STRSIZE];
// 初始化
memset(head_tmp,?0,?sizeof(head_tmp));
memset(tail_tmp,?0,?sizeof(tail_tmp));
head_len?=?strlen(head_str);
tail_len?=?strlen(tail_str);
// 查找? head_str
http_offset?=?ftell(fp);?// 記錄下 HTTP 報文初始文件偏移
while((head_tmp[0]?=?fgetc(fp))?!=?EOF)?// 逐個字節遍歷
{
if((ftell(fp)?–?http_offset)?>?total_len)?// 遍歷完成
{
sprintf(buf,?“can?not?find?%s?\r\n”,?head_str);
exit(0);
}
if(head_tmp[0]?==?*head_str)?// 匹配到第一個字符
{
for(i=1;?i<head_len;?i++)?// 匹配? head_str? 的其他字符
{
head_tmp[i]=fgetc(fp);
if(head_tmp[i]?!=?*(head_str+i))
break;
}
if(i?==?head_len)?// 匹配? head_str? 成功,停止遍歷
break;
}
}
//?printf(“head_tmp=%s?\n”,?head_tmp);
// 查找? tail_str
val_len?=?0;
while((tail_tmp[0]?=?fgetc(fp))?!=?EOF)?// 遍歷
{
if((ftell(fp)?–?http_offset)?>?total_len)?// 遍歷完成
{
sprintf(buf,?“can?not?find?%s?\r\n”,?tail_str);
exit(0);
}
buf[val_len++]?=?tail_tmp[0];?// 用 buf? 存儲? value? 直到查找到? tail_str
if(tail_tmp[0]?==?*tail_str)?// 匹配到第一個字符
{
for(i=1;?i<tail_len;?i++)?// 匹配? head_str? 的其他字符
{
tail_tmp[i]=fgetc(fp);
if(tail_tmp[i]?!=?*(tail_str+i))
break;
}
if(i?==?tail_len)?// 匹配? head_str? 成功,停止遍歷
{
buf[val_len-1]?=?0;?// 清除多余的一個字符
break;
}
}
}
//?printf(“val=%s\n”,?buf);
fseek(fp,?http_offset,?SEEK_SET);?// 將文件指針?回到初始偏移
}
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
