通信网络实验-嗅探器实现
使用WinPcap來實現嗅探器
一、嗅探器簡介
嗅探器程序一般包括內核部分和用戶分析部分,其中內核部分負責從網絡中捕獲和過濾數據,用戶分析部分負責界面、數據轉化和處理、格式化、協議分析,如果在內核中沒有過濾數據包,在這里還要對數據進行過濾。一個較為完整的基于網絡監聽和過濾的程序一般包含以下步驟:數據包捕獲、數據包過濾和分解、數據分析。
數據包捕獲常用的方法有兩種:
(1)通過設置路由器的監聽端口
(2)利用以太網絡的廣播特性。這種特性必須將網卡設置為混雜模式。監聽程序工作在網絡環境的底三層,可以攔截所有經過該機器的網絡上傳送的數據,然后將這些數據做相應處理,可以實時分析這些數據的內容,進而分析網絡當前狀態和整體布局。基于Windows的數據包捕獲方案有以下幾種:
1.使用原始套接字機制。方法簡單,但功能有限,只能捕獲較高層的數據包;
2.直接連接調用NDIS庫函數,這種方法功能非常強大,但是比較危險,很可能導致系統崩潰和網絡癱瘓;
3.使用或者自行編寫中間層驅動程序,這是微軟公司推薦使用的一種方法,微軟提供的Win2000DDK中也提供了幾個這樣的驅動程序,在具體的實現方式上可以分為用戶級和內核級兩類。其中內核級主要是TDI捕獲過濾驅動程序,NDIS中間層捕獲過濾驅動程序,NDIS捕獲過濾鉤子驅動程序等等,它們都是利用網絡驅動來實現的;而用戶級的包括SPI接口,Win2000包捕獲過濾接口等;
4.使用或自行編寫協議驅動程序
5.使用第三方捕獲組件或者庫,比如WinPcap.
捕獲數據包后,我們要進行的工作是對其進行包過濾和分解,就是在海量的數據里面找我們感興趣的內容。一些基礎的過濾規則如下:
站過濾:專門篩選出來自一臺主機或者服務器的數據
協議過濾:根據不同的協議來篩選數據,例如選擇TCP數據而非UDP數據
服務過濾:根據端口號來選擇特定數據包
通用過濾:通過數據包中某一位置開始,選擇某些具有共同特征的數據包;
過濾完成后,必須進行數據分析,這一部分就是對于已經捕獲的數據包進行各種分析,比如網絡流量分析,數據包中信息分析,敏感信息提取分析,其功能取決于系統要達到的目的。
下面,我們著重介紹一下使用WinPcap這一環境來實現一個嗅探器的過程。
WinPcap是用于網絡封包抓取的一套工具,包含了核心的封包過濾,一個底層動態鏈接庫和一個高層系統函數庫。可以進行信息包捕獲和網絡分析。很多不同的工具軟件都是使用WinPcap來進行網絡分析、故障排除和網絡安全監控等操作的,比如大名鼎鼎的WireShark軟件。
在安裝WireShark時,它是默認捆綁安裝WinPcap的。如果你沒有安裝WireShark的話,那么你也可以前往這一網頁進行下載。要注意的是,除了安裝這一文件,我們還要下載開發者套件,這個套間里面包含了一些頭文件、若干文檔和一些范例程序,對于我們的編程有很大的幫助。
下載之后,將開發者工具解壓到某一個目錄下。至于這個庫的使用方法,請參考我的前一篇博文。
好了,現在我們就可以開始進行正式的開發工作了。
使用WinPcap的基本流程十分規范,主要有以下幾步:
這些函數的定義都可以在幫助文檔里找到。在我們解壓后的開發者工具包的docs文件夾里,就有所有我們需要的函數的使用方法和范例。我們可以直接在范例的基礎上進行修改來完成我們的任務。
二、一個過濾UDP數據包的程序
下面是一個過濾網絡中udp數據包的程序。
#include <stdio.h> #include <stdlib.h> #include <ctime> #include "pcap.h" #include "remote-ext.h" typedef struct ip_address{u_char byte1;u_char byte2;u_char byte3;u_char byte4; }ip_address;//IPV4 header typedef struct ip_header{u_char ver_ihl;u_char tos;u_short tlen;u_short identification;u_short flags_fo;u_char ttl;u_char proto;u_short crc;ip_address saddr;ip_address daddr;u_int op_pad; }ip_header; //UDP header typedef struct udp_header{u_short sport;u_short dport;u_short len;u_short crc; }udp_header;void packet_handler(u_char *param, const struct pcap_pkthdr* header, const u_char *pkt_data);int main() {pcap_if_t *alldevs, *d;int inum, i = 0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];u_int netmask;char packet_filter[] = "ip and udp";struct bpf_program fcode;/* pap_findalldevs_ex():this function returns a linked list of pcap_if structures, each of which contains comprehensive information about an attached adapter */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf) == -1) {fprintf(stderr, "Error in pcap_findalldevs :%s\n", errbuf);exit(1); }for (d = alldevs; d ; d = d->next) {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 -1; } printf("Enter the interface number (1-%d):", i); scanf_s("%d", &inum); if (inum <1 || inum > i) {printf("\nInterface number out of range.\n");pcap_freealldevs(alldevs);return -1; } for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++); if ((adhandle = pcap_open_live(d->name,65536,1,1000,errbuf)) == NULL) {fprintf(stderr, "\nUnable to open the adapter.%s is not supported by WinPcap\n");pcap_freealldevs(alldevs);return -1; } 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 packet 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; } printf("\nListening on %s...\n", d->description); pcap_freealldevs(alldevs); pcap_loop(adhandle, 0, packet_handler, NULL); return 0; }//Callback function invoked by libpcap for every incoming packet void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {struct tm ltime;char timestr[16];ip_header *ih;udp_header *uh;u_short sport, dport;time_t local_tv_sec;u_int ip_len;local_tv_sec = header->ts.tv_sec;localtime_s(<ime,&local_tv_sec);strftime(timestr, sizeof(timestr), "%H:%M:%S", <ime);printf("%s,%.6d len:%d", timestr, header->ts.tv_usec, header->len);ih = (ip_header*)(pkt_data + 14);ip_len = (ih->ver_ihl & 0xf) * 4;uh = (udp_header*)((u_char *)ih + ip_len);sport = ntohs(uh->sport);dport = ntohs(uh->dport);printf("%d. %d. %d. %d. %d -> %d. %d. %d. %d. %d.\n", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, sport, ih->daddr.byte1,ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4, dport); }整個代碼的邏輯結構完全遵循我們之前提到的流程,理解起來并不困難,這里就不對代碼做具體分析了。
嗅探器的運行效果如下:
可以看到,這個程序已經將適配器里的udp包信息給打印了出來。這就說明我們的嗅探器已經可以正常工作了。
三、捕獲FTP數據包中的用戶名和密碼
要使這個程序具有捕獲FTP中的用戶名和密碼,我們只需要將我們的過濾機制設置成ftp數據,并且改寫packet_handler函數即可。
首先,我們將packet_filter改寫如下:
char packet_filter[] = "tcp dst port ftp";
然后,在程序中加入tcp_header的定義:
然后,改寫packet_handler函數:
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {struct tm ltime;char timestr[16];ip_header *ih;tcp_header *th;u_short sport, dport;time_t local_tv_sec;u_char *pdata;u_int tcp_len;u_int ip_len;u_int data_len;u_int i;local_tv_sec = header->ts.tv_sec;localtime_s(<ime,&local_tv_sec);strftime(timestr, sizeof(timestr), "%H:%M:%S", <ime);printf("%s,%.6d len:%d ", timestr, header->ts.tv_usec, header->len);ih = (ip_header*)(pkt_data + 14);ip_len = (ih->ver_ihl & 0xf) * 4;th = (tcp_header*)((u_char *)ih + ip_len);sport = ntohs(th->sport);dport = ntohs(th->dport);printf("%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, sport, ih->daddr.byte1,ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4, dport);tcp_len = ((th->ihl & 0xf0) >> 4) * 4;pdata = (u_char*)th + tcp_len;data_len = header->len - ip_len - tcp_len - 16;if (*pdata == 'U' && *(pdata + 1) == 'S' && *(pdata + 2) == 'E' && *(pdata + 3) == 'R'){memset(user, 0, sizeof(user));pdata += 5;for (i = 0; i < data_len-5; i++){user[i] = *pdata;pdata++;}}if (*pdata == 'P' && *(pdata + 1) == 'A' && *(pdata + 2) == 'S' && *(pdata + 3) == 'S'){memset(pass, 0, sizeof(pass));pdata += 5;for (i = 0; i<data_len - 5; i++){pass[i] = *pdata;pdata++;}}printf("User:%s\n", user);printf("Password:%s\n", pass); }然后怎么測試我們的程序能否正常工作呢?我們編譯并執行這個程序,然后點擊開始->運行->輸入cmd->輸入ftp ftp.mcafee.com->輸入用戶名:anonymous->輸入密碼(這個密碼可以任意填寫),這時候在我們的程序里應該就能看到你剛剛輸入的用戶名和密碼了:
總結
以上是生活随笔為你收集整理的通信网络实验-嗅探器实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 功能最完善,代码最简洁的选项卡代码(di
- 下一篇: DesignPattern - 适配器模