Fork me on GitHub

抓取简单的Pcap文件并读出信息

以下开发均基于Linux平台,以Ubuntu为例进行讲解,具体源码移步这里

抓取Pcap文件

笔者使用libpcap库(libpcap是unix/linux平台下的网络数据包捕获函数包)进行抓包。

安装libpcap库

  1. Libpcap下载
  2. 解压下载的压缩包 tar -zxvf filename.tar.gz (filename是下载的文件名)
  3. 配置生成makefile文件。进入解压的文件夹,执行 ./configure。这里可能会提示缺少flex,使用sudo apt-get install flex即可。
  4. 执行make。这里可能会提示缺少yacc,使用sudo apt-get install yacc即可。
  5. 执行sudo make install

使用库函数抓包

  1. pcap_lookupdev():函数用于查找网络设备,返回可被 pcap_open_live() 函数调用的网络设备名指针。
  2. pcap_lookupnet():函数获得指定网络设备的网络号和掩码。
  3. pcap_open_live(): 函数用于打开网络设备,并且返回用于捕获网络数据包的数据包捕获描述字。对于此网络设备的操作都要基于此网络设备描述字。
  4. pcap_compile(): 函数用于将用户制定的过滤策略编译到过滤程序中。
  5. pcap_setfilter():函数用于设置过滤器。
  6. pcap_loop():函数 pcap_dispatch() 函数用于捕获数据包,捕获后还可以进行处理,此外 pcap_next() 和 pcap_next_ex() 两个函数也可以用来捕获数据包。
  7. pcap_close():函数用于关闭网络设备,释放资源。
  8. pcap_dump_open用于打开保存的文件
  9. pcap_dump用于输出数据到文件。

分析Pcap文件

这里给出用于读取Pcap文件的结构体。读者可以从中看出Pcap文件的结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
Wireshark File Formate

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PCAP File Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PCAP Package Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Ethernet frame header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SCTP Package |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/


typedef unsigned char _1Byte;
typedef unsigned short _2Byte;
typedef unsigned int _4Byte;

#define PCAP_FILE_HEADER_SIZE 24 //24个字节
#define PACKET_HEADER_SIZE 16 //16个字节
#define MAC_HEADER_SIZE 14 //14个字节
#define IP_HEADER_SIZE 20 //20个字节
#define ICMP_HEADER_SIZE 8 //8个字节
#define TCP_HEADER_SIZE 20 //20个字节
#define UDP_HEADER_SIZE 8 //8个字节

/*
PCAP File Header

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Magic Number(0xA1B2C3D4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Magjor Version(0x02) | Minor Version(0x04) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time Zone(0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time Stamp Accuracy(0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Snapshot Length(0xFFFF) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Link Layer Type(0x01) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct PcapFileHeader
{
_4Byte magic; //4Byte:标记文件开始,并用来识别文件自己和字节顺序。
_2Byte majorVersion; //2Byte: 当前文件主要的版本号,一般为 0x0200
_2Byte minorVersion; //2Byte: 当前文件次要的版本号,一般为 0x0400
_4Byte timezone; //4Byte:当地的标准时间,如果用的是GMT则全零
_4Byte sigFlags; //4Byte:时间戳的精度
_4Byte snapLen; //4Byte:最大的存储长度
_4Byte linkType; //4Byte:链路类型
};

/*
Packet Header

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Seconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Microseconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| CapLen |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Len |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

struct PacketHeader
{
_4Byte seconds; //4Byte 秒计时,被捕获时间的高位,单位是seconds
_4Byte microseconds; //4Byte 微秒计时,被捕获时间的低位,单位是microseconds

_4Byte capLen; //4Byte 当前数据区的长度,即抓取到的数据帧长度,不包括Packet Header本身的长度,单位是 Byte
_4Byte len; //4Byte 离线数据长度:网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等
};



/*
IP Header

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

struct IPHeader
{
/*----------第一行-------------------*/
union//共一个字节
{
_1Byte version;//版本号
_1Byte headerLength;//包头长度,指明IPv4协议包头长度的字节数包含多少个32位
};
_1Byte serviceType;//区分服务
_2Byte totalLength;//总长度
/*----------第二行-------------------*/
_2Byte identification;//标识
union
{
_2Byte flags;//标志,当封包在传输过程中进行最佳组合时使用的3个bit的识别记号
_2Byte fragmentOffset;//片偏移
};
/*----------第三行-------------------*/
_1Byte timeToLive;//生存时间
_1Byte protocol;//协议
_2Byte headerChecksum;//首部检验和
/*----------第四行-------------------*/
_4Byte sourceAddress;//源地址
/*----------第五行-------------------*/
_4Byte destinationAddress;//目标地址
};

//MAC帧信息
struct MACHeader{
_1Byte destinationAddress[6];
_1Byte sourceAddress[6];
_2Byte type;
};

/*
ICMPHeader

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| type | code | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification | serial |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

*/
struct ICMPHeader
{
_1Byte type; //类型
_1Byte code; //代码
_2Byte headerChecksum;//首部检验和

_2Byte identification;//标识
_2Byte serial;//序列号

};


/*
TCP Header

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source port | Destination port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Serial |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgement Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|DataOffset|Reserve|u|a|p|r|s|f| Window |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct TCPHeader{
_2Byte sourcePort;//源端口
_2Byte destinationPort;//目的端口

_4Byte serial;//序号

_4Byte acknowledgementNumber;//确认号

union{//共2个字节
_2Byte dataOffset;//数据偏移
_2Byte reserve;//保留
_2Byte urg;//紧急
_2Byte ack;//确认
_2Byte psh;//推送
_2Byte rst;//复位
_2Byte syn;//同步
_2Byte fin;//终止
};
_2Byte window;//窗口

_2Byte checksum;//检验和
_2Byte urgentpointer;//紧急指针
};

struct UDPHeader{
_2Byte sourcePort;//源端口
_2Byte destinationPort;//目的端口
_2Byte length;//长度
_2Byte checksum;//检验和
};

分析的过程即是个读取文件的过程,在此不再赘述。

扫描二维码,拯救贫困山区大学生!
-------------本文结束感谢您的阅读-------------