1.1 应用层协议分析
要对应用层协议进行分析,首先必须抓取网络数据包,根据数据包的格式对其进行一层一层的剥离头部信息,最后得到应用层的数据,然后再根据获得的数据进行应用层行为的分析。因此必须对各层的数据包格式特别清楚,并且熟悉怎么编制抓包程序。
1.1.1 抓包程序
在编写抓包程序时,一般借助winpcap或libpcap提供的API对网络数据包进行抓取。winpcap是为windows开发环境提供的库函数,而libpcap则是为Linux开发环境提供的库函数。它们都是一个强大的网络开发库,可以实现许多功能,如获取可用的网络适配器、获取指定适配器信息(比如名称和描述信息)、捕获指定网卡的数据封包、发送数据封包、过滤捕获的包以获取特定包等。两者提供的接口基本一致,只是某些函数名略有不同。在使用前必须将winpcap或libpcap安装在系统上,在使用时必须在工程中加入对应的开发包并在程序中声明。
1. 安装和部署winpcap
由于在Linux下安装和部署libpcap非常简单,将libpcap安装到Linux系统中,在程序编译时加上-l pcap即可。本段主要介绍在windows中安装和使用winpcap,具体的部署过程如下所示:
? 下载安装winpcap驱动和DLL组件,即一个winpcap的安装程序,和普通安装程序
一样,点击下一步进行安装,直至完毕
? 下载winpcap的开发包(如WpdPack_4_0_2),将其解压缩到某个路径 ? 在工程和程序中加入开发包
? 在工程中指定WpdPack_4_0_2中的Lib和Include路径 ? 设置编译条件(添加WPCAP和HAVE_REMOTE) ? 设置连接器的选项(添加wpcap.lib和ws2_32.lib) ? 包括头文件#include \
2. winpcap的使用: ?
常用数据结构:
pcap_if_t * allAdapters; //适配器列表 –>next获得下一个适配器 pcap_t * adapterHandle;//适配器句柄 struct pcap_pkthdr * packetHeader; const u_char * packetData;
? 常用函数:
查找系统上所有适配器:
if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&allAdapters,errorBuffer)==-1)
//获得所有设备信息,存放在allAdapters中
pcap_freealldevs( allAdapters ); //释放适配器列表 打开适配器并获取其句柄:
adapterHandle = pcap_open( adapter->name, // name of the adapter
65536, // portion of the packet to capture 65536 guarantees that the whole packet will be captured
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout - 1 millisecond NULL, // authentication on the remote machine errorBuffer // error buffer ); 发送数据包:
if( pcap_sendpacket( adapterHandle, // the adapter handle
packet, // the packet u_char packet[20]; //待发送的数据封包
20 // the length of the packet ) != 0 )
1.1.2 数据包格式和分析
其实协议就是为了规定一种大家都遵循的格式,在应用层、传输层、网络层、数据链路层都有自己的协议数据单元(PDU),按照数据包在网络中传输的过程,首先是应用层将实际的数据根据应用层的协议(格式)封装成一个应用层数据包(相当于一个字符串,更确切的是一个字节串),然后向下传,传到传输层,传输层将拿到的串作为自己数据包的数据部分,并在前面加上自己的头部,头部有许多字段,每个字段都有各自的含义,这样就生成了一个新的串,继续向下传。传到了网络层,网络层进行和上面类似的操作,继续传到数据链路层。数据链路层也加上自己的头部,生成一个新的串,并且在串的头部和尾部都做好标记,然后继续向下传。传到了物理层,物理层就直接将收到的串转化成二进制的电信号进行传输。假如传输到最后的目的地(端系统中),首先是物理层收到电信号,将其转化成一串字节,向上传。传到了数据链路层,数据链路层根据之前对串的头部和尾部做好的记号将有用信息提取出来,并根据头部信息提取出数据部分,只将数据部分向上传。传到了网络层,网络层根据网络层的头部信息,提取出数据部分,传给上一层,依次类推。数据在网络中(整个传输过程不包括两个端系统的部分)的传输过程只有3层,即物理层到数据链路层,再到网络层,传输的过程和上面描述的一样。
由于在对包进行分析时都要参考数据包的格式,所以数据包的格式是相当重要的。在抓包时,首先是获得链路层的帧,根据帧头可以获得源mac和目的mac以及上层的协议。一般帧头是14byte,链路层帧的包头结构在程序中的表示如下:
/* 6字节的mac地址 */ typedef struct mac_address {
u_char byte1; u_char byte2; u_char byte3;
u_char byte4;
u_char byte5; u_char byte6;
} mac_address;
/* 14字节的ether帧头 */ typedef struct ether_header {
mac_address dest_mac; mac_address src_mac; u_short protocal; } ether_header;
根据帧头的长度将指针往后移,然后可以获得IP数据报的头部指针,根据报头信息可以获得源IP、目的IP、上层协议、头部长度、总长度等信息,IP数据报的头部格式如下图所示:
图2.2.2.1 IPV4头部格式
图2.2.2.2 IPV6头部格式
IPV4报文结构在程序中的表示:
/* 4字节的IP地址 */ typedef struct ip_address {
u_char byte1; u_char byte2; u_char byte3; u_char byte4; } ip_address; /* IP头部 */
typedef struct ip_header {
u_char ver_ihl; // 版本 (4 bits) + 首部长度 (4 bits) u_char tos; // 服务类型(Type of service) u_short tlen; // 总长(Total length) u_short identification; // 标识(Identification)
u_short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset)
相关推荐: