1、网络安全编程技术n第第3讲:数据包的捕获与分析讲:数据包的捕获与分析1 编程实现一个协议分析器。该协议分析器将包编程实现一个协议分析器。该协议分析器将包含以下几部分功能含以下几部分功能:1.数据采集数据采集捕捉捕捉Ethernet网网络络数据包;数据包;2.解析解析Ethernet网数据帧头部的全部信息;网数据帧头部的全部信息;3.解析解析IP数据包的头部信息;数据包的头部信息;4.解析解析TCP和和UDP包的头部信息;包的头部信息;2主要内容n用原始Socket抓包n进行协议分析n使用开发工具包WinPcap抓包31.用原始Socket抓包流程1.创建原始Socket2.获取一个需要监听网络
2、接口的ip地址,并绑定(必须要显示绑定)3.设置网卡为混杂模式4.开始循环接收数据5.关闭Socket4关键代码1:创建原始SocketSnifferSocket=socket(AF_INET,SOCK_RAW,IPPROTO_IP);if(Result=SOCKET_ERROR)printf(socket failed with error%dn,WSAGetLastError();return 0;5原始socket的特点n应用程序可以收到目标是其它主机的包n应用程序会收到ip包n如果设置IP_HDRINCL 选项,可以手动设置发送的ip包的头部n不能拦截数据,因为系统采用的是拷贝的方式n
3、由于安全原因,在xp-sp2,windows 7中原始socket的使用有限制:n不能发送tcp包n不能使用伪造的原ip地址6关键代码2:绑定到一个本地IP地址 Result=gethostname(Name,255);pHostent=(struct hostent*)malloc(sizeof(struct hostent);pHostent=gethostbyname(Name);SOCKADDR_IN sock;sock.sin_family=AF_INET;sock.sin_port=htons(5555);memcpy(&sock.sin_addr.S_un.S_addr,pHos
4、tent-h_addr_list0,pHostent-h_length);Result=bind(SnifferSocket,(PSOCKADDR)&sock,sizeof(sock);想想看这里端口号有没有意义,这个值合不合适一定是第一个接口吗?7获取本地接口的更好方法1.SOCKADDR_INinput;2.charremoteip=8.8.8.8;/可以是任意地址3.shortremoteport=80;4.charbuf1024;5.input.sin_family=AF_INET;6.input.sin_addr.s_addr=inet_addr(remoteip);7.input.
5、sin_port=htons(remoteport);8.9.Result=WSAIoctl(SnifferSocket,SIO_ROUTING_INTERFACE_QUERY,&input,sizeof(input),buf,1024,&dwBytesRet,NULL,NULL);10.SOCKADDR_IN*lpIf=(SOCKADDR_IN*)buf;11.sock.sin_addr=lpIf-sin_addr;8关键代码3:设置为混杂模式u_long InOutParam=1;Result=ioctlsocket(SnifferSocket,SIO_RCVALL,&InOutParam
6、);参数InOutParam表示命令SIO_RCVALL 的输入参数WSAIoctl是相应的Winows扩展函数,更复杂,更强大。9以太网卡的工作模式n网卡的MAC地址(48位)n通过ARP来解析MAC与IP地址的转换n用ipconfig/ifconfig可以查看MAC地址n正常情况下,网卡应该只接收这样的包nMAC地址与自己相匹配的数据帧n广播包n网卡完成收发数据包的工作,两种接收模式n混杂模式:不管数据帧中的目的地址是否与自己的地址匹配,都接收下来n非混杂模式:只接收目的地址相匹配的数据帧,以及广播数据包(和组播数据包)n为了监听网络上的流量,必须设置为混杂模式10共享网络和交换网络n共享
7、式网络n通过网络的所有数据包发往每一个主机n最常见的是通过HUB连接起来的子网n交换式网络n通过交换机连接网络n由交换机构造一个“MAC地址-端口”映射表n发送包的时候,只发到特定的端口上11关键代码4:读取数据 char Packet60000;Result=recv(SnifferSocket,Packet,sizeof(Packet),0);还有没有更好的处理?struct sockaddr_in from;int fromlen;Result=recvfrom(SnifferSocket,Packet,sizeof(Packet),0,(struct sockaddr*)&from,&
8、fromlen);12n阅读p227-229的代码n课后请上机测试,并运行n注意:编译时可能报错,找不到头文件mstcpip.h,请自己上网查找资料来解决。13使用原始socket抓包的缺点n要求管理员权限;n在windows 7之前,该方法只能抓到进来的包;n没有内核级的过滤机制,只能有程序员自己来过滤,既复杂又很慢,在千兆网上很容易丢包;n不能获取链路层信息;n不能获取arp包。142.进行协议分析n目的:对抓获的包进行分析,是不是ip包,ip的头部各个字段是什么,是不是tcp或udp报文等待?n故首先我们需要对ip,tcp和udp等协议有所了解,特别是它们的头部字段。152.1 TCP/
9、IP协议族中的协议协议族中的协议用户进程用户进程用户进程用户进程用户进程用户进程用户进程用户进程TCPTCPUDPUDPICMPICMPIPIPIGMPIGMPARPARP硬件接口硬件接口RARPRARP应用层应用层传输层传输层网络层网络层网络接口层网络接口层媒体媒体那我们发送和接收的数据包的大致格式是什么样的?请以一个网页包为例来说明。162.2 协议分析的难点n在前面抓包程序的基础上,增加简单的协议分析。n协议分析的实质就是识别各个协议头,及其头部各个字段的含义。n故为了程序的处理,必须定义协议头的数据结构。17IP数据报格式版本版本头部长度头部长度服务类型服务类型(TOS)总长度总长度(
10、字节数字节数)标识符标识符3位位标志标志段偏移段偏移生存时间生存时间(TTL)协议协议头部校验和头部校验和源源IP地址地址目的目的IP地址地址选项(如果有)选项(如果有)数据数据18IP头struct IPHeader unsigned char Version_HLen;unsigned char TOS;unsigned short Length;unsigned short Ident;unsigned short Flags_Offset;unsigned char TTL;unsigned char Protocol;unsigned short Checksum;unsigned
11、int SourceAddr;unsigned int DestinationAddr;假设已获取一个ip头部的指针ip,如何获取版本信息呢?ip-Version_HLen 4如何获取头部长度呢?(ip-Version_HLen&0 x0f)*4如何更好的定义版本和头部长度字段?19IP协议分析n获取一个ip包Packetn强制类型转换struct IPHeader*ip=(struct IPHeader*)Packet;n现在就可根据数据结构IPHeader和ip头的标准,来获取ip头部各个字段的值n参见p233-p234的相关代码,应该写成子函数的形式。20如何判断传输层的协议#defin
12、e TCP_PROTOCAL 6#define UDP_PROTOCAL 17unsigned char Prot=ip-Protocol;21TCP包首部数据格式源端口号源端口号(16位)目的端口号目的端口号(16位)序号序号(32位)确认序号确认序号(32位)首部长首部长度度(4位)保留保留(6位)URGACKPSHRSTSYNF I N窗口大小窗口大小(16位)校验和校验和(16位)紧急指针紧急指针(16位)选项(任选,若有)选项(任选,若有)填充填充紧急数据紧急数据数据数据22TCP头struct TcpHeader unsigned short SrcPort;unsigned sh
13、ort DstPort;unsigned int SequenceNum;unsigned int Acknowledgment;unsigned char HdrLen;unsigned char Flags;unsigned short AdvertisedWindow;unsigned short Checksum;unsigned short UrgPtr;假设已获取一个tcp头部的指针tcp,如何获取源端口?ntohs(tcp-SrcPort)如何判断是不是SYN包?(tcp-Flags&0 x02)0?1:023TCP协议分析n已有一个IP头指针ip n强制类型转换struct T
14、cpHeader*tcp=(struct TcpHeader*)(ip+20);struct TcpHeader*tcp=(struct TcpHeader*)(char*)ip+IpHeaderLength);n现在就可根据数据结构TcpHeader和tcp头的标准,来获取tcp头部各个字段的值n参见p234-p235的相关代码,应该写成子函数的形式。24UDP报文格式n端口号:表示发送进程和接收进程nUDP长度:包括UDP头和UDP数据nUDP报文校验和:可选,为0表示不做校验25UDP头struct UdpHeader unsigned short SrcPort;unsigned sh
15、ort DstPort;unsigned short Length;unsigned short Checksum;简单得多263 Winpcap概述nWinpcap是libpcap在Win32平台上移植,是一个用于抓包和网络分析的架构,且开源。n捕获原始数据包,包括链路层信息。n有内核级的过滤机制,用户设置非常简单n独立于主机协议(如TCP-IP)而发送和接收原始数据报。也就是说,winpcap不能阻塞,过滤或控制其他应用程序数据报的收 发。n很多软件必须安装WinPcap才能用的。比如wireshark,网络执法管、P2P终结者、QQ第六感等嗅探和监控软件。27Winpcap的安装n下载w
16、inpcap的驱动程序和相应版本的wpdpack开发包n安装驱动n把wpdpack开发包解压到自己选定的目录n在vc中(tools-option-directories)设定include目录和library目录n连接wpcap.lib28数据包捕获流程图 293.1 网络设备的发现intpcap_findalldevs(pcap_if_t*alldev,char*errbuf);返回一个指向网络设备列表的指针。返回值:-1:出错0:成功pcap_freealldevs(pcap_if_t*alldev);更复杂更强大的函数int pcap_findalldevs_ex(char*source
17、,struct pcap_rmtauth*auth,pcap_if_t*alldevs,char*errbuf)30接口struct pcap_if struct pcap_if*next;/下一个接口char*name;/接口名char*description;struct pcap_addr*addresses;bpf_u_int32 flags;/目前只支PCAP_IF_LOOPBACK;31接口地址struct pcap_addr struct pcap_addr*next;struct sockaddr*addr;struct sockaddr*netmask;struct sock
18、addr*broadaddr;struct sockaddr*dstaddr;/P2P;323.2 打开接口获取抓包描述符pcap_t*pcap_open_live(char*device,/接口名int snaplen,/抓取数据包的最大长度,/多出部分将被截断int promisc,/是否为混杂模式int to_ms,/读多少毫秒的包后再返回char*errorbuf);用途:用来获取一个抓包的 descriptor;返回值为NULL表失败void pcap_close(pcap_t*p)333.3 设置filternint pcap_compile(pcap_t*p,struct bpf
19、_program*fp,char*str,int optimize,bpf_u_int32 netmask)把用户容易理解的字符串形式的过滤规则str翻译成一个程序可以识别的过滤器规则fpnNetmask:被抓包的掩码,用于检查ipv4的广播包n返回值为-1时出错nint pcap_setfilter(pcap_t*p,struct bpf_program*fp)设置一个过滤器34a.捕获捕获 MAC地址为地址为 00:d0:f8:00:00:03 网络设备通信的所网络设备通信的所有报文有报文 ether host 00:d0:f8:00:00:03b.捕获捕获 IP地址为地址为 192.16
20、8.10.1 网络设备通信的所有报文网络设备通信的所有报文 host 192.168.10.1c.捕获网络捕获网络web浏览的所有报文浏览的所有报文 tcp port 80d.捕获捕获192.168.10.1除了除了http外的所有通信数据报文外的所有通信数据报文 host 192.168.10.1 and not tcp port 80这些过滤规则也是软件这些过滤规则也是软件Ethereal直接使用的规则直接使用的规则过滤规则举例35更一般的过滤规则usrc|dst host uether src|dst host ugateway host usrc|dst net mask|len ut
21、cp|udp src|dst port uless|greater uip|ether proto uether|ip broadcast|multicast363.4 捕获数据int pcap_loop(pcap_t*p,int cnt,/捕获的最大数目,-1表无限pcap_handler callback,/用户的处理函数u_char*user/回调函数的参数)返回值:-1出错,0表cnt耗尽int pcap_next_ex(pcap_t*p,struct pcap_pkthdr*pkt_header,const u_char*pkt_data)373.5 用户的包处理函数 void Ca
22、llbackFunc(unsigned char*user,const struct pcap_pkthdr*winpcaphead,const unsigned char*packetdata)参数winpcaphead:说明包的一些辅助信息,包括时间,长度。packetdata:捕获的帧38以太网帧结构 n前导码与帧前定界符:前导码为前导码与帧前定界符:前导码为56bit的的1010101010,帧前定界符为帧前定界符为10101011n目的地址和源地址:目的地址和源地址:MAC地址为地址为48bitn长度长度/类型:长度(小于类型:长度(小于0800H),类型(大于等于),类型(大于等于
23、0800H,如,如IP为为0800H、ARP为为0806H)n数据字段:用于携带上层传下来的数据。数据字段:用于携带上层传下来的数据。n帧校验字段:帧校验字段:32位的位的CRCn前导码、帧前定界符和帧校验和三个字段属于物理层内容,前导码、帧前定界符和帧校验和三个字段属于物理层内容,在数据链路层不会得到这些字段,因此在在数据链路层不会得到这些字段,因此在MAC层只需解析层只需解析目的地址、源地址、长度目的地址、源地址、长度/类型和数据字段。类型和数据字段。39代码阅读nP244-247n改进:识别arp,icmp,tcp和udp包,极其长度n4.8.3节实际上仅仅是多了一个图像界面而已。40 nWinpcap提供了一个简单而快捷的方式发送提供了一个简单而快捷的方式发送一个原始数据包。一个原始数据包。/*发送自定义数据包。*pPacketBuf中是数据缓冲区指针,*iSize是数据包大小*/pcap_sendpacket(hAdapterHandle,pPacketBuf,iSize);可以发送自定义的可以发送自定义的TCP包,而不受包,而不受windows的的限制;但需要自己进行路由(从哪个接口出去,限制;但需要自己进行路由(从哪个接口出去,发送给谁),并填写链路层头部发送给谁),并填写链路层头部。41