使用WinPcap编写Sniffer程序

Slides:



Advertisements
Similar presentations
本周复习一下基本的网络知识 下周开始讲解路由器的配置方法 第四周开始到实验室做实验(主楼910,919)
Advertisements

Wireshark 03/03/2017.
第 8 章 IP 基礎與定址.
第 12 章 UDP 與 TCP.
2017/3/6 WIRESHARK 的安裝與基本操作.
第 4 章 网络层.
计算机网络教程(第 2 版) 第 7 章 网络互连 课件制作人:谢希仁.
MIE-311 Mobile Network Security
因特网 TCP/IP协议 IP路由技术 Internet接入技术 Internet服务.
Chapter 12 UDP 與 TCP.
计算机网络安全技术实验 启动虚拟机、GIF、measpoilt、.
数据转发过程.
NetGuru 創新 網路通訊實驗教學解決方案 PART I TCP/IP通訊協定深入剖析/以NetGuru實作
Netman Linux 的防火牆設計與應用 Netman
计算机网络 吴功宜 编著 欢迎辞.
Socket.
网络安全威胁与防御策略. TCP/IP Protocols  Contains Five Layers  Top three layers contains many protocols  Actual transmission at the physical layer.
潘爱民,北京大学计算机研究所 网络与信息安全 网络安全 (二) 潘爱民,北京大学计算机研究所
NAT-PT (Network Address Translation-Protocol Translation)
Advanced Sockets Programming
第 12 章 UDP 與 TCP.
教师:陈有为 TCP/IP与Internet(A) 教师:陈有为
第三章 ARP与RARP.
單向鏈結串列 Singly Linked Lists.
第 13 章 DNS 著作權所有 © 旗標出版股份有限公司.
IPv6 技術與服務 台東大學 電算中心 郭俊賢 技術師.
通訊協定 OSI分層模式 與 TCP/IP協定
计算机网络原理 计算机与信息工程分院 周文峰.
第六章 差错与控制报文 (ICMP).
TCP和UDP基本原理.
Internet Protocol (IP)
32 bit destination IP address
附錄 通訊協定堆疊.
IP協定 (網路層).
TCP/IP Protocol Suite TCP/IP協定 第二組 投影片製作by簡嘉宏 綦凱宏 林睿敏 滕孟哲.
系統與網路管理工具.
Access Networks.
第十一章 文件 文件概述 文件操作 文件操作实例 本章小结 作业: 练习:
第 2 章 TCP / IP 簡介.
在一定程度上 人类的思维产生于 简单个体之间的相互作用 ——Marvin Minsky.
第4章 OSI傳輸層.
第五章 数据链路层和局域网 链路层和局域网.
fp=fopen("CD2.dat","wb"); fwrite(&min,8,1,fp); fclose(fp);
江西财经大学信息管理学院 《组网技术》课程组
實驗目的 明瞭可靠傳輸層的基礎觀念 TCP協定下區段資料傳送的格式
第七讲 网际协议IP.
NS2 – TCP/IP Simulation How-Wei Wu.
第5讲 网络层 本讲目的: 概述: 理解网络层服务原理: 因特网的实现实例 网络层的服务 路由选择原理 分层的路由选择 IP协议
THE C PROGRAMMING LANGUAGE
第 12 章 UDP 與 TCP 著作權所有 © 旗標出版股份有限公司.
第十三章 TCP/IP 與 Internet 網路連結技術
TANet PROTOCOL ANALYSIS - WIRESHARK - 350.
第7章 传输层协议——TCP与UDP 任课教师 卢豫开.
Struct結構 迴圈
Westmont College 网络应用软件 第一讲 (客户-服务器 概念, 协议端口的使用, 套接字API)
iSoftStone Information Service Corporation
Window Socket 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
第13章 IPv6协议.
Advister: Quincy Wu Speaker: Chenglin Tsai Date:3/26
3.1 通訊協定 3.2 開放系統參考模式(OSI) 3.3 公眾數據網路 3.4 TCP/IP通訊協定
_08遍历物理网卡 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
實驗5 IP協定分析 明瞭IP(Internet Protocol;Internet協定)的基礎觀念
傳輸控制協議 /互聯網協議 TCP/IP.
NAT技术讲座 主讲:周旭 大唐电信科技股份有限公司光通信分公司 数据通信部.
Speaker : Chang Kai-Jia Date : 2010/04/26
第8章 網際網路協定IPv6介紹與設定 蕭志明老師 CCNA教學.
網際網路原理 網際網路源起與發展歷史 1968 ARPANET 1973 TCP/IP協定 1976 乙太網路,促成LAN的發展 … DNS
第7章 传输层协议——TCP与UDP 任课教师 卢豫开.
支援 ZigBee/ 封包分析之 USB封包擷取轉換模組 之實作
第 4 章 网络层.
Presentation transcript:

使用WinPcap编写Sniffer程序

内容介绍 嗅探器原理 Winpcap介绍 Winpcap安装 Winpcap应用程序结构

Sniffer(嗅探器)设计原理 通常的套接字程序只能响应与自己硬件地址相匹配的或是以广播形 式发出的数据帧,对于其他形式的数据帧,比如已到达网络接口但 却不是发给此地址的数据帧,网络接口在验证投递地址并非自身地 址之后将不引起响应,也就是说应用程序无法收取到达的数据包。 网络嗅探器的目的恰恰在于从网卡接收所有经过它的数据包,这些 数据包既可以是发给本机的也可以是发往别处的。通过将网络接口 设置为混杂模式可以使它接收所有经过它的数据包(例如以太网帧 将会到达同一局域网的所有网络接口)。 但是,此时操作系统不再 行底层的细节操作(协议处理,流量均衡等) ,而是将拆封解释处 理接收到的数据帧(frame)的任务交给应用程序完成,这样应用程 序就可以灵活的获取各类信息。

什么是 Winpcap 网络数据包捕获库函数 直接访问网络,免费、公用 工作于驱动层,网络操作高效 为应用程序提供了一组API接口 Libpcap(UNIX)库 Winpcap(Windows)库 网络数据包捕获库函数 直接访问网络,免费、公用 工作于驱动层,网络操作高效 为应用程序提供了一组API接口 编程容易,源码级移植方便 Winpcap介绍

WinPcap主要功能 捕获原始数据包 将数据包发送给应用程序之前,按照用户规定的规范过滤数据包 将捕获到的数据包输出到文件中,并可以对这些文件进行再分析 向网络发送原始数据包 搜集网络传输统计数据 Winpcap介绍

哪些应用适合使用 WinPcap Winpcap介绍 网络和协议分析network and protocol analyzers 网络监控network monitors 流量记录traffic loggers 流量产生traffic generators 用户级网桥和路由器user-level bridges and routers 网络入侵检测network intrusion detection systems (NIDS) 网络扫描network scanners 安全工具security tools Winpcap介绍

WinPcap不能胜任的事情 立收发数据包。这意味着它不能阻塞、过 滤或者处理同一主机上其他程序产生的数 WinPcap从主机的协议(如TCP/IP)独 立收发数据包。这意味着它不能阻塞、过 滤或者处理同一主机上其他程序产生的数 据包:它仅仅嗅探网线上传输的数据包。 所以它不适合应用于流量均衡、QoS调度 和个人防火墙。 Winpcap介绍

Winpcap的安装 下载安装包和开发包 http://winpcap.polito.it 程序员开发包(WpdPack_3_1.zip) Winpcap的安装包(Winpcap_3_1.exe) 程序员开发包(WpdPack_3_1.zip) 运行Winpcap_3_1.exe 测试安装结果 Winpcap安装

编程环境设定 Winpcap安装 1. 以Administrator身份登录Windows(2000/XP),运行 2. 运行Visual C++ 6.0, 打开WpdPack_3_1\WpdPack\Examples-pcap\下的 任一项目(本例用basic_dump目录下 basic_dump.dsw) 3. 在“工程->设置-> Link->对象/库模块” 中加入 wsock32.lib ws2_32.lib wpcap.lib 在“工具->选择->目录”的include files和library files设置中引入winpcap开发包中的Include和Lib目录 4. 编译,运行 Winpcap安装

例程运行结果: Winpcap安装

获得设备列表 WinPcap的典型应用 打开一个适配器 过滤数据包 回调机制 直接方式 解析数据包 打开离线数据包文件 获得网络流量统计数字 获得已安装设 备的高级信息 获得设备列表 打开一个适配器 打开离线数据包文件 过滤数据包 回调机制 直接方式 解析数据包 获得网络流量统计数字

获得设备列表 (一) 一个基本的WinPcap应用程序所需的第一步 就是获得合适的网络适配器。 Libpcap提供 pcap_findalldevs() 函数完成 这个功能。这个函数返回一个相连的pcap_if结 构的列表,列表的每一项包含关于适配器的复杂 的信息。特别的,name和description域数据包 含设备的名称和可读的描述。

    pcap_if_t *alldevs,*d; int i=0;     char errbuf[PCAP_ERRBUF_SIZE];     if (pcap_findalldevs(&alldevs, errbuf) == -1)     {         fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);         exit(1);     }     for(d=alldevs;d;d=d->next) { /* Print the list */     printf("%d. %s", ++i, d->name);         if (d->description) printf(" (%s)\n", d->description);         else            printf(" (No description available)\n");     }     if(i==0){         printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return; } pcap_freealldevs(alldevs);

获得设备列表 (二) 每个pcap_findalldevs() 返回的 pcap_if 结构也 包含了一个pcap_addr 结构的列表: 该接口的地址列表 网络掩码的列表(每个网络掩码对应地址列表中的一项) 广播地址的列表(每个广播地址对应地址列表中的一项) 目标地址的列表(每个目标地址对应地址列表中的一项) 通过返回的结构,我们可以得到探测到的网卡 设备的更详尽信息。

typedef struct pcap_if pcap_if_t struct pcap_if *next; char *name; char *description; struct pcap_addr *addresses; bpf_u_int32 flags; /* PCAP_IF_ interface flags */ }; struct pcap_addr { struct pcap_addr *next; struct sockaddr *addr; struct sockaddr *netmask; struct sockaddr *broadaddr; struct sockaddr *dstaddr;

打开一个适配器开始捕获数据包 设备标识 (字符串) 抓包长度 混杂模式 超时时间 pcap_t * pcap_open_live ( const char *  device, int snaplen, int promisc, int to_ms, char * ebuf ) pcap_t *adhandle= pcap_open_live(d->name, 65536,1, 1000, errbuf ); 设备标识 (字符串) 抓包长度 混杂模式 超时时间

捕获数据包(回调机制) int pcap_loop ( pcap_t * p, int cnt, pcap_handler callback, u_char * user )  例如: pcap_loop(adhandle, 0, packet_handler, NULL); typedef void(* pcap_handler) ( u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)

捕获数据包(直接方式) int pcap_next_ex ( pcap_t * p, struct pcap_pkthdr ** pkt_header, const u_char ** pkt_data ) 该函数从接口或者脱机读取一个数据包。用于接收下一个可用的数 据包,而不使用libpcap提供的传统的回调机制。 pcap_next_ex用下 一个数据包的指向数据包头和数据的指针填充pkt_header和pkt_data 参数。 pcap_next_ex() 目前只在Win32下可用,因为它不是属libpcap 原始的API。这意味着含有这个函数的代码将不能被移植到Unix上。

过滤数据包 int pcap_compile ( pcap_t * p, struct bpf_program * fp, char * str, //过滤表达式 int optimize, bpf_u_int32 netmask ) //掩码 int pcap_setfilter ( pcap_t * p, struct bpf_program * fp ) pcap_compile() 编译一个包过滤器。将一个高级的、布尔形式表 示的字符串转换成低级的、二进制过滤语句,以便被包驱动使用。 pcap_setfilter() 在核心驱动中将过滤器和捕获过程结合在一起。从 这一时刻起,所有网络的数据包都要经过过滤,通过过滤的数据 包将被传入应用程序。

char packet_filter[] = "ip and udp"; 过滤设置举例     char packet_filter[] = "ip and udp"; struct bpf_program fcode; /* 获取接口地址的掩码,如果没有掩码,认为该接口属于一个C类网络 */ if(d->addresses != NULL)     netmask=((struct sockaddr_in *) (d->addresses->netmask))->sin_addr.S_un.S_addr; else netmask=0xffffff; if(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ){ fprintf(stderr,"\nUnable to compile the filter. Check the syntax.\n"); pcap_freealldevs(alldevs); return -1; }     if(pcap_setfilter(adhandle, &fcode)<0){   fprintf(stderr,"\nError setting the filter.\n");   pcap_freealldevs(alldevs); return -1; }

过滤表达式 表达式由一个或多个原语组成。原语通常由一个id(名称或者数字) 和在它前面的一个或几个修饰符组成。有3种不同的修饰符: 可能是host,net和port。 例如 “host foo”、“net 128.3”、“port 20”。如果没有类型修饰符, 缺省为host。 方向   指明向 和/或 从id传输等方向的修饰符。 可能的方向有src、dst、src or dst 和 src and dst。 例如“src foo”、“dst net 128.3”、“src or dst port ftp-data”。如果 缺省为src or dst。 协议   指明符合特定协议的修饰符。 目前的协议包括ether、fddi、ip、ip6、arp、rarp、tcp和udp等。 例如“ether src foo”、 “arp net 128.3”。 如果没有协议修饰符,则表示声明类型的所有协议。 例如“src foo”表示“(ip or arp or rarp) src foo” “port 53”表示“(tcp or udp) port 53”。

解析数据包 不同的网络使用不同的链路层协议,不知道网络类型就无法定位数 据帧(frame) ,所以,首先使用如下函数对网络类型进行判断: int pcap_datalink(pcap_t *p) 它返回适配器的链路层标志,例如DLT_EN10MB表示以太网(10Mb, 100Mb,1000Mb及以上),DLT_IEEE802表示令牌环网。可以在设 置过滤条件之前先对各个设备的网络类型进行探测,以获知物理层 的数据帧格式,接下来就可以针对不同的帧格式解析出封装在其中 的报文(packet),例如IP报文,继而拆封IP报文得到TCP或者UDP 等报文,再深层次的拆封就是应用程序数据了。

解析数据包 前面我们提到,用户在程序中调用的pcap_loop()(或者 pcap_dispatch())函数可以进行数据包的捕获,而每一 个数据包到达时该函数会调用pcap_handler()函数进行数 据包处理,返回一个指向捕获器头部和一个指向帧数据 的指针(包含协议头)。下面我们针对常用的以太网给 出这一过程及IP、TCP的头部格式,其他数据包的格式 请参考RFC文档。注意:在数据包解析时要检查校验和 以及包的顺序。

Ethernet帧头 struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; u_char ether_shost[ETHER_ADDR_LEN]; u_short ether_type; /* IP? ARP? RARP? 等*/ };

IP报文头

#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ struct sniff_ip { #if BYTE_ORDER == LITTLE_ENDIAN u_int ip_hl:4, /* header length */ ip_v:4; /* version */ #endif #if BYTE_ORDER == BIG_ENDIAN u_int ip_v:4, /* version */ ip_hl:4; /* header length */ #endif /* not _IP_VHL */ u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* don’t fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ };

TCP报文头

struct sniff_tcp { u_short th_sport; /* source port */ u_short th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ #if BYTE_ORDER == LITTLE_ENDIAN u_int th_x2:4, /* (unused) */ th_off:4; /* data offset */ #endif #if BYTE_ORDER == BIG_ENDIAN u_int th_off:4, /* data offset */ th_x2:4; /* (unused) */ u_char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /* window */ u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */ };

获取包数据 struct sniff_ethernet* ethernet; struct sniff_ip* ip; pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) handler_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); struct sniff_ethernet* ethernet; struct sniff_ip* ip; struct sniff_tcp* tcp; ethernet = (struct sniff_ethernet*)(packet); ip = (struct sniff_ip*)(packet + size_ethernet); tcp = (struct sniff_tcp*)(packet + size_ethernet + size_ip); payload = (u_char *)(packet + size_ethernet + size_ip + size_tcp);

处理离线数据包文件 WinPcap提供了大批函数,用于将网络数据保存到文 件和将储存文件读出。 文件格式和libpcap保存的是一样的。这种格式比较简 单,用二进制格式保存捕获的数据包的数据,它也是很 多网络工具例如WinDump,Ethereal和Snort等使用的标 准。 这里的函数包括pcap_dump_open()、pcap_dump()、 pcap_open_offline()等。

将数据包存入文件 //主程序 pcap_dumper_t * dumpfile; dumpfile = pcap_dump_open(adhandle, argv[1]); //打开一个存储文件并将它和接口联系起来 if(dumpfile==NULL){         fprintf(stderr,"\nError opening output file\n");return -1; } //… pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile); //packet_handler void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data) { /* save the packet on the dump file */     pcap_dump(dumpfile, header, pkt_data);

从保存文件中读取数据包 第一步:打开离线数据文件 第二步:读取离线数据 (一)使用回调函数 (二)不使用回调函数 if ( (fp = pcap_open_offline(argv[1], errbuf) ) == NULL) {         fprintf(stderr,"\nError opening dump file\n");return -1; } 第二步:读取离线数据 (一)使用回调函数 (二)不使用回调函数 pcap_loop(fp, 0, dispatcher_handler, NULL);//主程序中 void dispatcher_handler(u_char *temp1,                         const struct pcap_pkthdr *header, const u_char *pkt_data) { //处理代码 } while((res = pcap_next_ex( fp, &header, &pkt_data)) >= 0){         //处理代码  }//主程序中

发送数据包 pcap_sendpacket发送单个数据包 发送队列(查看winpcap手册)

pcap_sendpacket发送单个数据包 来发送一个手写的数据包。 pcap_sendpacket()用一个包含要发送的数据 的缓冲区、该缓冲区的长度和发送它的适配器作 为参数。注意该缓冲区是不经任何处理向外发出 的,这意味着,如果想发些有用的东西的话,应 用程序必须产生正确的协议头。

u_char packet[100]; if((fp = pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL) { fprintf(stderr,"\nError opening adapter: %s\n", error); return; } /* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */ packet[0…5]=1; /* set mac source to 2:2:2:2:2:2 */ packet[6…11]=2; /* Fill the rest of the packet */ for(i=12;i<100;i++){ packet[i]=i%256; /* Send down the packet */ pcap_sendpacket ( fp, packet, 100);

获得网络流量统计数字 统计的内容: 最后一个时间间隔内的数据包的数目和接收 的比特数 为了用这个功能来监视网络,程序员必须打开适配器并 将它设置为统计模式。这可以通过调用pcap_setmode() 完成,此时这个函数的mode参数应该为MODE_STAT。

获得网络流量统计数字 统计模式需要的数据拷贝和内容交换最少,所以CPU的 利用率比较高。并且所需要的内存很少。 注意:开始激活统计模式之前,用户可以设置过滤器,定义监视网络流量的一部分。如果没有设置过虑器,整个流量都要被监视。

fp = pcap_open_live(argv[1], 100, 1, 1000, error); struct timeval st_ts; fp = pcap_open_live(argv[1], 100, 1, 1000, error); pcap_setmode(fp, MODE_STAT); pcap_loop(fp, 0, dispatcher_handler, (PUCHAR)&st_ts); void dispatcher_handler(u_char *state, const struct pcap_pkthdr *header, const u_char *pkt_data) { struct timeval *old_ts = (struct timeval *)state; //注意这里指针的使用 u_int delay; //提供了两个64位计数器: //统计最后一个时间间隔内的数据包的数目和接收的比特数。 LARGE_INTEGER Bps,Pps; struct tm *ltime; char timestr[16];   //利用采样的时间戳计算自上一次采样以来的延迟时间(毫秒) delay=(header->ts.tv_sec - old_ts->tv_sec) * 1000000 – old_ts->tv_usec + header->ts.tv_usec; 注意:此处dispatch_handler每次回调时填入的 第二个和第三个参数,前者还是和驱动 有关的抓包头部,而后者指向封装了接 收包数目和接收字节数目的数据区

//计算每秒获取的二进制位数 Bps. QuadPart=(((. (LONGLONG. )(pkt_data + 8)). 8 //计算每秒获取的二进制位数 Bps.QuadPart=(((*(LONGLONG*)(pkt_data + 8)) * 8 * 1000000) / (delay)); /* 计算每秒获取的包数 */ Pps.QuadPart=(((*(LONGLONG*)(pkt_data)) * 1000000) / (delay)); //打印时间戳 ltime=localtime(&header->ts.tv_sec); strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); printf("%s ", timestr); //打印采样值 printf("BPS=%I64u ", Bps.QuadPart); printf("PPS=%I64u\n", Pps.QuadPart); //保存当前的时间戳 old_ts->tv_sec=header->ts.tv_sec; old_ts->tv_usec=header->ts.tv_usec; }

例:应用程序模块及工作流程