winpcap程式設計抓包例項和windump使用
阿新 • • 發佈:2019-01-09
http://www.winpcap.org/archive/
官方文件
http://www.winpcap.org/windump/install/default.htm
http://www.360doc.com/content/11/0319/10/54470_102500630.shtml
WinDump的使用:
WinDump.exe version 3.9.5, based on tcpdump version 3.9.5
WinPcap version 4.1.3 (packet.dll version 4.1.0.2980), based on libpcap version 1.0 branch 1_0_rel0b (20091008)
Usage: WinDump.exe [-aAdDeflLnNOpqRStuUvxX] [ -B size ] [-c count] [ -C file_size ]
[ -E algo:secret ] [ -F file ] [ -i interface ] [ -M secret ]
[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]
[ -W filecount ] [ -y datalinktype ] [ -Z user ]
[ expression ]
windump -D
列出所有的網絡卡。
windump -h 列出幫助。
WinDump.exe -h >mylog.txt 2>&1
WinDump.exe -i 4
windump -i 2 port 80
通過埠80從介面#2記錄所有流量
windump -i 2 host im-chat.com
記錄所有從the host im-chat.com.或來或到介面#2的流量
windump -i 1 net 127
這些引數也可以自由組合。
WinDump手冊
命令格式
windump [ -aBdDeflnNOpqRStvxX ] [ -c count ] [ -F file ] [ -i interface ] [ -m module ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ] [ -E algo:secret ] [ expression ]
描述 Tcpdump 輸出網絡卡資料包中匹配布林表示式的資料包頭。
SunOS 系統下使用nit或bpf:要執行tcpdump,你必須有對dev/nit或/dev/bpf*的權利。Solaris系統下使用dlpi:你必須有對 網路假設定的權利。HP-UX系統下使用dlpi:你應該以超級使用者ROOT或安裝SETUID到ROOT下。IRIX下使用SNOOP:你應該以超級用 戶ROOT或安裝SETUID到ROOT下。
LINUX下:你應該以超級使用者ROOT或安裝SETUID到ROOT下。
在系統Ultrix和Digital UNIX:
命令引數
-a 將網路和廣播地址轉化為名稱
-c 接收指定資料包後退出
-d 接收人可讀的包匹配編譯程式碼到標準輸出,然後停止
-dd 以C程式分段方式捕獲包匹配程式碼
-ddd 以十進位制資料形式捕獲包匹配程式碼
-e 在每個捕獲行列印鏈路層頭標
-E algo:secret為解密IPSE ESP包使用演算法。
演算法可以是des-cbc, 3des-cbc, blowfish-cbc, rc3-cbc, cast128-cbc, 或none。
預設值是desc-cbc。只有當TCPDUMP編譯時使用啟用加密選項時,才可以解密資料包。
Secret是ESP密匙是ASCII碼。當前還不能認為一定是二進位制值。該選項是以RFC2406ESP為假設,而不是RFC1827 ESP。只用於除錯,不鼓勵用真正的密碼作為選項。當你在PS或其他場合,把IPSEC密碼寫在命令列上時,會被他人看到。
-f 不用符號而用數字方式輸出外部英特網地址 -F 使用檔案作為過濾表示式的輸入。命令列的其他部分會被忽略。
-i 在介面上監聽。如果沒有指定,TCPDUMP將搜尋系統介面列表中最小,被配置啟用的介面(LOOPBACK介面除外)。可用最先匹配替換這種關係。在 WINDOWS中介面可以是網絡卡的名稱,或是網絡卡的號碼(-D引數可顯示該號碼)。核心為2。2或其後的LINUX系統,引數“ANY”可以獲取所有介面 的資料。應注意的是在混亂模式下不能使用“ANY”引數。
-l 標準輸出行快取。如果你想在捕獲資料時檢視的話,這個引數很有用。
例如:“tcpdump -l │ tee dat” or “tcpdump -l > dat & tail -f dat”.” n 不要將地址(如主機地址,埠號)轉換為名稱 -N 不要列印主機名稱的域名限定。如:如果你使用該引數,TCPDUMP會輸出“NIC”而不是“NIC。DDN。MIL”。
-m 從檔案模組中載入SMI MIB 模組定義。這個選項可以為TCPDUMP載入多個MIB模組
-O 不要執行包匹配程式碼優化器。只有在你懷疑優化器有問題時可以使用這個引數。
-p 不要讓介面處於“混亂”模式。注意介面可能由於其他原因處於“混亂”模式;因此“-p”不能用作乙太網絡主機或廣播的縮寫。
-q 快速(安靜?)輸出。列印較少的協議資訊,因此輸出行更短。
-r 從檔案中讀取包(與引數據-W一起使用)。如果檔案是“-”就使用標準輸入。
-s 不使用預設的68個位元組,更改從每個包中獲取資料的位元組數量( SunOS系統實際最小為96)。對於IP,ICMP,TCP和UDP包68個位元組已足夠,但是對命名服務和NFS包,他們的協議會被截斷(見下面)。包 被截斷是因為在使用引數“[│proto]”輸出時指定受限制的快照,proto是被截斷協議層的名稱。注意如果使用大的快照會增加處理包的時間,並且明 顯地減少包的快取數量。也許會導致包的丟失。你應該將snaplen 設定成你感興趣協議的最小數。當snaplen 為0時接收整個包。
-T 根據表示式將選中的資料包表達成指定的型別。當前已有的型別有CNFP(Cisco的網路流量協議),rpc(遠端程式呼叫),rtp(實時程式協議), rtcp(實時程式控制協議),snmp(簡單網路管理協議),vat(可視單頻工具),和wb(分散式白板)。 -R 假設ESP/AH包遵守舊的說明(RFC1825到RFC1829)。如果該引數被指定,TCPDUMP不打輸出域。因為在ESP/AH說明中沒有協議版 本,TCPDUMP就無法推斷出其版本號。 -S 輸出絕對TCP序列號,而不是相對號。
-t 每個捕獲行不要顯示時間戳。 -tt 每個捕獲行顯示非格式化的時間時間戳。
-v 詳細輸出。例如,顯示生存時間TTL,識別符號,總長度和IP資料包的選項。也進行額外的包完整性較驗,如驗證IP和ICMP的頭標較驗值。
-vv 更為詳細的輸出。例如,顯示NFS中繼包中的其他域。
-vvv 很詳細的輸出。如,完全輸出TELNET SB… SE選項。帶-X引數的TELNET,列印並以十六進位制輸出。
-w 不對原始資料包解析列印而是轉到檔案中去。以後可用-r選項列印。當檔名為“-”表示標準輸出。 -x 以十六進位制(去除鏈路層頭標)輸出每個資料包。輸出整個包的小部分或snaplen 個位元組。
-X 輸出十六進位制同時,輸出ASCII碼。如果-x也被設定,資料包會以十六制/ASCII碼顯示。這對於分析新協議非常方便。如果-x也沒有設定,一些資料包的部分會以十六制/ASCII碼顯示。 Win32特殊擴充套件
-B 以千位元組為單位設定驅動快取。預設快取為1M(即1000)。如果在獲取資料包時有資料丟失,建議使用該引數增大核心快取大小,因為驅動快取大小對資料捕獲效能有很大影響。
-D 顯示系統上可用的網絡卡列表。該引數將返回每塊網絡卡的號碼,名稱和描述。
官方文件
http://www.ferrisxu.com/WinPcap/html/index.html
http://www.winpcap.org/http://www.winpcap.org/windump/install/default.htm
http://www.360doc.com/content/11/0319/10/54470_102500630.shtml
WinDump的使用:
WinDump.exe version 3.9.5, based on tcpdump version 3.9.5
WinPcap version 4.1.3 (packet.dll version 4.1.0.2980), based on libpcap version 1.0 branch 1_0_rel0b (20091008)
Usage: WinDump.exe [-aAdDeflLnNOpqRStuUvxX] [ -B size ] [-c count] [ -C file_size ]
[ -E algo:secret ] [ -F file ] [ -i interface ] [ -M secret ]
[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]
[ -W filecount ] [ -y datalinktype ] [ -Z user ]
[ expression ]
windump -D
列出所有的網絡卡。
windump -h 列出幫助。
WinDump.exe -h >mylog.txt 2>&1
WinDump.exe -i 4
windump -i 2 port 80
通過埠80從介面#2記錄所有流量
windump -i 2 host im-chat.com
記錄所有從the host im-chat.com.或來或到介面#2的流量
windump -i 1 net 127
這些引數也可以自由組合。
WinDump手冊
命令格式
windump [ -aBdDeflnNOpqRStvxX ] [ -c count ] [ -F file ] [ -i interface ] [ -m module ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ] [ -E algo:secret ] [ expression ]
描述 Tcpdump 輸出網絡卡資料包中匹配布林表示式的資料包頭。
SunOS 系統下使用nit或bpf:要執行tcpdump,你必須有對dev/nit或/dev/bpf*的權利。Solaris系統下使用dlpi:你必須有對 網路假設定的權利。HP-UX系統下使用dlpi:你應該以超級使用者ROOT或安裝SETUID到ROOT下。IRIX下使用SNOOP:你應該以超級用 戶ROOT或安裝SETUID到ROOT下。
LINUX下:你應該以超級使用者ROOT或安裝SETUID到ROOT下。
在系統Ultrix和Digital UNIX:
命令引數
-a 將網路和廣播地址轉化為名稱
-c 接收指定資料包後退出
-d 接收人可讀的包匹配編譯程式碼到標準輸出,然後停止
-dd 以C程式分段方式捕獲包匹配程式碼
-ddd 以十進位制資料形式捕獲包匹配程式碼
-e 在每個捕獲行列印鏈路層頭標
-E algo:secret為解密IPSE ESP包使用演算法。
演算法可以是des-cbc, 3des-cbc, blowfish-cbc, rc3-cbc, cast128-cbc, 或none。
預設值是desc-cbc。只有當TCPDUMP編譯時使用啟用加密選項時,才可以解密資料包。
Secret是ESP密匙是ASCII碼。當前還不能認為一定是二進位制值。該選項是以RFC2406ESP為假設,而不是RFC1827 ESP。只用於除錯,不鼓勵用真正的密碼作為選項。當你在PS或其他場合,把IPSEC密碼寫在命令列上時,會被他人看到。
-f 不用符號而用數字方式輸出外部英特網地址 -F 使用檔案作為過濾表示式的輸入。命令列的其他部分會被忽略。
-i 在介面上監聽。如果沒有指定,TCPDUMP將搜尋系統介面列表中最小,被配置啟用的介面(LOOPBACK介面除外)。可用最先匹配替換這種關係。在 WINDOWS中介面可以是網絡卡的名稱,或是網絡卡的號碼(-D引數可顯示該號碼)。核心為2。2或其後的LINUX系統,引數“ANY”可以獲取所有介面 的資料。應注意的是在混亂模式下不能使用“ANY”引數。
-l 標準輸出行快取。如果你想在捕獲資料時檢視的話,這個引數很有用。
例如:“tcpdump -l │ tee dat” or “tcpdump -l > dat & tail -f dat”.” n 不要將地址(如主機地址,埠號)轉換為名稱 -N 不要列印主機名稱的域名限定。如:如果你使用該引數,TCPDUMP會輸出“NIC”而不是“NIC。DDN。MIL”。
-m 從檔案模組中載入SMI MIB 模組定義。這個選項可以為TCPDUMP載入多個MIB模組
-O 不要執行包匹配程式碼優化器。只有在你懷疑優化器有問題時可以使用這個引數。
-p 不要讓介面處於“混亂”模式。注意介面可能由於其他原因處於“混亂”模式;因此“-p”不能用作乙太網絡主機或廣播的縮寫。
-q 快速(安靜?)輸出。列印較少的協議資訊,因此輸出行更短。
-r 從檔案中讀取包(與引數據-W一起使用)。如果檔案是“-”就使用標準輸入。
-s 不使用預設的68個位元組,更改從每個包中獲取資料的位元組數量( SunOS系統實際最小為96)。對於IP,ICMP,TCP和UDP包68個位元組已足夠,但是對命名服務和NFS包,他們的協議會被截斷(見下面)。包 被截斷是因為在使用引數“[│proto]”輸出時指定受限制的快照,proto是被截斷協議層的名稱。注意如果使用大的快照會增加處理包的時間,並且明 顯地減少包的快取數量。也許會導致包的丟失。你應該將snaplen 設定成你感興趣協議的最小數。當snaplen 為0時接收整個包。
-T 根據表示式將選中的資料包表達成指定的型別。當前已有的型別有CNFP(Cisco的網路流量協議),rpc(遠端程式呼叫),rtp(實時程式協議), rtcp(實時程式控制協議),snmp(簡單網路管理協議),vat(可視單頻工具),和wb(分散式白板)。 -R 假設ESP/AH包遵守舊的說明(RFC1825到RFC1829)。如果該引數被指定,TCPDUMP不打輸出域。因為在ESP/AH說明中沒有協議版 本,TCPDUMP就無法推斷出其版本號。 -S 輸出絕對TCP序列號,而不是相對號。
-t 每個捕獲行不要顯示時間戳。 -tt 每個捕獲行顯示非格式化的時間時間戳。
-v 詳細輸出。例如,顯示生存時間TTL,識別符號,總長度和IP資料包的選項。也進行額外的包完整性較驗,如驗證IP和ICMP的頭標較驗值。
-vv 更為詳細的輸出。例如,顯示NFS中繼包中的其他域。
-vvv 很詳細的輸出。如,完全輸出TELNET SB… SE選項。帶-X引數的TELNET,列印並以十六進位制輸出。
-w 不對原始資料包解析列印而是轉到檔案中去。以後可用-r選項列印。當檔名為“-”表示標準輸出。 -x 以十六進位制(去除鏈路層頭標)輸出每個資料包。輸出整個包的小部分或snaplen 個位元組。
-X 輸出十六進位制同時,輸出ASCII碼。如果-x也被設定,資料包會以十六制/ASCII碼顯示。這對於分析新協議非常方便。如果-x也沒有設定,一些資料包的部分會以十六制/ASCII碼顯示。 Win32特殊擴充套件
-B 以千位元組為單位設定驅動快取。預設快取為1M(即1000)。如果在獲取資料包時有資料丟失,建議使用該引數增大核心快取大小,因為驅動快取大小對資料捕獲效能有很大影響。
-D 顯示系統上可用的網絡卡列表。該引數將返回每塊網絡卡的號碼,名稱和描述。
這個包裡面有很多例子,下面我們就可以程式設計實現了:
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #define HAVE_REMOTE #include <pcap.h> #include <iomanip> #include <string> #include <stdio.h> using namespace std; #include <pcap.h> #pragma comment(lib,"wpcap.lib") #pragma comment(lib,"ws2_32.lib") //https://github.com/yfnick/winpcap/blob/master/ref_http/main.cpp //demo https://github.com/yfnick/winpcap /*Ethernet Heder*/ struct ether_header { u_int8_t ether_dhost[6]; /* destination eth addr */ u_int8_t ether_shost[6]; /* source ether addr */ u_int16_t ether_type; /* packet type ID field */ }; /* 4 bytes IP address */ struct ip_address{ u_char byte1; u_char byte2; u_char byte3; u_char byte4; }; /* IPv4 header */ struct ip_header{ u_char ver_ihl; // Version (4 bits) + Internet header length (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 (13 bits) u_char ttl; // Time to live u_char proto; // Protocol u_short crc; // Header checksum ip_address saddr; // Source address ip_address daddr; // Destination address u_int op_pad; // Option + Padding }; /* UDP header*/ struct udp_header{ u_short sport; // Source port u_short dport; // Destination port u_short len; // Datagram length u_short crc; // Checksum }; /*TCP Header*/ struct tcp_header { u_int16_t th_sport; /* source port */ u_int16_t th_dport; /* destination port */ u_int32_t th_seq; /* sequence number */ u_int32_t th_ack; /* acknowledgement number */ u_int16_t th_len_resv_code; // Datagram length and reserved code u_int16_t th_win; /* window */ u_int16_t th_sum; /* checksum */ u_int16_t th_urp; /* urgent pointer */ }; int main() { //retrieve the devices list pcap_if_t *all_devs; char err_buff[PCAP_ERRBUF_SIZE]; if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &all_devs, err_buff) == -1){ cerr << "Error in pcap_findalldevs_ex " << err_buff << endl; return -1; } //get the device index,default is the first one int dev_idx = 2; pcap_if_t *dev = all_devs; for (int i = 0; i < dev_idx; ++i, dev = dev->next);//jump to the device of the specified index cout << "Listen on: " << dev->name << endl; cout << "****************************************" << endl; //get the netcard adapter pcap_t *adpt_hdl = pcap_open(dev->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, err_buff); if (adpt_hdl == NULL){ cerr << "Unable to open adapter " << dev->name << endl; pcap_freealldevs(all_devs); return -1; } /* At this point, we don't need any more the device list. Free it */ pcap_freealldevs(all_devs); //analyze each packet struct pcap_pkthdr *header; const u_char *pkt_data; int rst = 0; char x; FILE *fp, *fq; fp = fopen("http.txt", "w+"); fq = fopen("ac.txt", "w+"); while ((rst = pcap_next_ex(adpt_hdl, &header, &pkt_data)) >= 0) { if (rst == 0){ //time out and not packet captured continue; } ether_header *eh = (ether_header*)pkt_data; if (ntohs(eh->ether_type) == 0x0800){ // ip packet only ip_header *ih = (ip_header*)(pkt_data + 14); if (ntohs(ih->proto) == 0x0600){ // tcp packet only int ip_len = ntohs(ih->tlen);//ip_len = ip_body + ip_header bool find_http = false; string http_txt = ""; //char* http; char* ip_pkt_data = (char*)ih; for (int i = 0; i < ip_len; ++i){ //check the http request if (!find_http && ( 3 < ip_len && strncmp(ip_pkt_data + i, "GET", strlen("GET")) == 0) || (i + 4 < ip_len && strncmp(ip_pkt_data + i, "POST", strlen("POST")) == 0)){ find_http = true; } //check the http response if (!find_http && i + 8 < ip_len && strncmp(ip_pkt_data + i, "HTTP/1.1", strlen("HTTP/1.1")) == 0){ find_http = true; } //collect the http text if (find_http){ http_txt += ip_pkt_data[i]; fputc(ip_pkt_data[i], fp); if ((ip_pkt_data[i] > 'A'&&ip_pkt_data[i]<'Z') || (ip_pkt_data[i]>'a'&&ip_pkt_data[i]<'z')) { if ((ip_pkt_data[i]>'A'&&ip_pkt_data[i] < 'Z')) x = ip_pkt_data[i] - 'A' + 'a'; else x = ip_pkt_data[i]; fputc(x, fq); } } } //print the http request or response if (http_txt != ""){ cout << http_txt; cout << endl << "***********************************************************" << endl << endl; } } } } return 0; }
#define HAVE_REMOTE #define _CRT_SECURE_NO_WARNINGS 1 #include <pcap.h> #pragma comment(lib,"wpcap.lib") /* 回撥函式原型 */ void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); int main(int argc, char **argv) { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i = 0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; pcap_dumper_t *dumpfile; /* 檢查程式輸入引數 */ if (argc != 2) { printf("usage: %s filename", argv[0]); return -1; } /* 獲取本機裝置列表 */ 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("%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(d->name, // 裝置名 65536, // 要捕捉的資料包的部分 // 65535保證能捕獲到不同資料鏈路層上的每個資料包的全部內容 PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式 1000, // 讀取超時時間 NULL, // 遠端機器驗證 errbuf // 錯誤緩衝池 )) == NULL) { fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); /* 釋放裝置列表 */ pcap_freealldevs(alldevs); return -1; } /* 開啟堆檔案 */ dumpfile = pcap_dump_open(adhandle, argv[1]); if (dumpfile == NULL) { fprintf(stderr, "\nError opening output file\n"); return -1; } printf("\nlistening on %s... Press Ctrl+C to stop...\n", d->description); /* 釋放裝置列表 */ pcap_freealldevs(alldevs); /* 開始捕獲 */ pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile); return 0; } /* 回撥函式,用來處理資料包 */ void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data) { /* 儲存資料包到堆檔案 */ pcap_dump(dumpfile, header, pkt_data); }