隨筆-17  評論-64  文章-79  trackbacks-1

          ??

          ?? ?? 經(jīng)??吹秸搲腥藛柶痍P(guān)于數(shù)據(jù)包的截獲、分析等問題,幸好本人也對此略有所知,也寫過很多的 sniffer ,所以就想寫一系列的文章來詳細深入的探討關(guān)于數(shù)據(jù)包的知識。

          我希望通過這一系列的文章,能使得關(guān)于數(shù)據(jù)包的知識得以普及,所以這系列的每一篇文章我都會有由淺入深的解釋、詳細的分析、以及編碼步驟,另外附上帶有詳細注釋的源碼 ( 為了照顧大多數(shù)朋友,我提供的都是 MFC 的源碼 ) 。

          不過由于也是初學(xué)者,疏漏之處還望不吝指正。

          本文凝聚著筆者心血,如要轉(zhuǎn)載,請指明原作者及出處,謝謝! ^_^

          ?

          OK,. Let’s go !? Have fun ! ! q^_^p

          ?

          第二篇 ?? 手把手教你捕獲數(shù)據(jù)包

          目錄:

          一. 捕獲數(shù)據(jù)包的實現(xiàn)原理

          二. 捕獲數(shù)據(jù)包的編程實現(xiàn):

          1.? ?raw socket 的實現(xiàn)方法

          2.? ?Winpcap 的實現(xiàn)方法

          a.????? 枚舉本機網(wǎng)卡的信息

          b.????? 打開相應(yīng)網(wǎng)卡并設(shè)置為混雜模式

          c.?????? 截獲數(shù)據(jù)包并保存為文件

          ?

          作者:

          CSDN? VC/MFC 網(wǎng)絡(luò)編程版主 PiggyXP?

          ?

          一.捕獲數(shù)據(jù)包的實現(xiàn)原理: --------------------------------------------------------------------

          在通常情況下,網(wǎng)絡(luò)通信的套接字程序只能響應(yīng)與自己硬件地址相匹配的或是以廣播形式發(fā)出的數(shù)據(jù)幀,對于其他形式的數(shù)據(jù)幀比如已到達網(wǎng)絡(luò)接口但卻不是發(fā)給此地址的數(shù)據(jù)幀,網(wǎng)絡(luò)接口在驗證投遞地址并非自身地址之后將不引起響應(yīng),也就是說應(yīng)用程序無法收取與自己無關(guān)的的數(shù)據(jù)包。

          所以我們要想實現(xiàn)截獲流經(jīng)網(wǎng)絡(luò)設(shè)備的所有數(shù)據(jù)包,就要采取一點特別的手段了:

          將網(wǎng)卡設(shè)置為混雜模式。

          這樣一來,該主機的網(wǎng)卡就可以捕獲到所有流經(jīng)其網(wǎng)卡的數(shù)據(jù)包和幀。

          但是要注意一點,這種截獲僅僅是數(shù)據(jù)包的一份拷貝,而不能對其進行截斷,要想截斷網(wǎng)絡(luò)流量就要采用一些更底層的辦法了,不在本文的討論范圍之內(nèi)。

          ?

          二. 捕獲數(shù)據(jù)包的編程實現(xiàn):

          1.raw socket 的實現(xiàn)方法 --------------------------------------------------------------------

          不同于我們常用的數(shù)據(jù)流套接字和數(shù)據(jù)報套接字,在創(chuàng)建了原始套接字后,需要用 WSAIoctl() 函數(shù)來設(shè)置一下,它的定義是這樣的

          int WSAIoctl(

          ? SOCKET s,

          ? DWORD dwIoControlCode,

          ? LPVOID lpvInBuffer,

          ? DWORD cbInBuffer,

          ? LPVOID lpvOutBuffer,

          ? DWORD cbOutBuffer,

          ? LPDWORD lpcbBytesReturned,

          ? LPWSAOVERLAPPED lpOverlapped,

          ? LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

          );

          雖然咋一看參數(shù)比較多,但是其實我們最關(guān)心的只是其中的第二項而已,我們需要做的就是把第二項設(shè)置為 SIO_RCVALL ,講了這么多其實要做的就是這么一行代碼,很簡單吧? ^_^

          ? 當然我們還可以指定是否親自處理 IP 頭,但是這并不是必須的。

          完整的代碼類似與如下這樣,加粗的代碼是與平常不同的需要注意的地方:

          ( 為了讓代碼一目了然,我把錯誤處理去掉了,下同 )

          ?

          #include “WinSock2.h”

          #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)

          ?

          SOCKET SnifferSocket

          ? WSADATA wsaData;

          ? iFlag=WSAStartup(MAKEWORD(2,2),&wsaData);???????? ? // 開啟 winsock.dll

          ?????????????????????????????????

          SnifferSocket=WSASocket(AF_INET, ????????????// 創(chuàng)建 raw? socket

          SOCK_RAW, IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);

          ?

          ? char FAR name[128];???? ???????????????????????????// 獲取本機 IP 地址

          gethostname(name, sizeof(name));

          ? struct hostent FAR * pHostent;

          ? pHostent = gethostbyname(name);

          ?

          ? SOCKADDR_IN sa;?????????????????????????? // 填充 SOCKADDR_IN 結(jié)構(gòu)的內(nèi)容

          ? sa.sin_family = AF_INET;

          ? sa.sin_port = htons(6000);????????? ?// 端口號可以隨便改,當然與當然系統(tǒng)不能沖突

          ? memcpy(&(sa.sin_addr),pHostent->h_addr,pHostent->h_length);

          ?

          bind(SnifferSocket,(LPSOCKADDR)&sa,sizeof(sa));????? ????? // 綁定

          ?

          ? // ioctl 來接收所有網(wǎng)絡(luò)數(shù)據(jù) , 關(guān)鍵步驟

          ? DWORD dwBufferLen[10] ;

          ? DWORD dwBufferInLen = 1 ;

          ? DWORD dwBytesReturned = 0 ;

          ? WSAIoctl(SnifferSocket, IO_RCVALL,&dwBufferInLen, izeof(dwBufferInLen),

          ??????? &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );

          ?

          至此,實際就可以開始對網(wǎng)絡(luò)數(shù)據(jù)包進行嗅探了,而對于數(shù)據(jù)包的接收還是和普通的 socket 一樣,通過 recv() 函數(shù)來完成,因為這里涉及到不同的 socket 模型,接收方法差別很大,所以在此就不提供接收的代碼了。

          ?

          2.winpcap 的實現(xiàn)方法: -----------------------------------------------------------------------

          winpcap 驅(qū)動包,是我們玩轉(zhuǎn)數(shù)據(jù)包不可或缺的好東東, winpcap 的主要功能在于獨立于主機協(xié)議(如 TCP-IP) 而發(fā)送和接收原始數(shù)據(jù)報,主要為我們提供了四大功能:

          功能:
          ??? 1>
          捕獲原始數(shù)據(jù)報,包括在共享網(wǎng)絡(luò)上各主機發(fā)送 / 接收的以及相互之間交換的數(shù)據(jù)報;
          ??? 2>
          在數(shù)據(jù)報發(fā)往應(yīng)用程序之前,按照自定義的規(guī)則將某些特殊的數(shù)據(jù)報過濾掉;
          ??? 3>
          在網(wǎng)絡(luò)上發(fā)送原始的數(shù)據(jù)報;
          ??? 4>
          收集網(wǎng)絡(luò)通信過程中的統(tǒng)計信息

          如果環(huán)境允許的話 ( 比如你做的不是木馬程序 ) ,我還是推薦大家用 winpcap 來截獲數(shù)據(jù)包,因為它的功能更強大,工作效率更高,唯一的缺點就是在運行用 winpcap 開發(fā)的程序以前,都要在主機上先安裝 winpcap driver

          而且一會我們就會發(fā)現(xiàn)它比 raw socket 功能強大的多,而且工作得更為底層,最明顯的理由就是 raw socket 捕獲的數(shù)據(jù)包是沒有以太頭的,此乃后話。

          至于怎么來安裝使用,請參考本系列的系列一《手把手教你玩轉(zhuǎn) ARP 包中的》,里面有詳細的加載 winpcap 驅(qū)動的方法 ^_^

          廢話不多說了,讓我們轉(zhuǎn)入正題 , 具體用 winpcap 來截獲數(shù)據(jù)包需要做如下的一些工作:

          A . 枚舉本機網(wǎng)卡的信息 ( 主要是獲得網(wǎng)卡的名稱 )

          ?? 其中要用到 pcap_findalldevs 函數(shù),它是這樣定義的

          ?? /*************************************************

          int pcap_findalldevs? (? pcap_if_t **??? alldevsp,?

          ? ??????????????????????? ??? ?char *??? errbuf

          ? ? ????????????????? ??? ???)?

          ?? ?? 功能:

          ??????????? ? 枚舉系統(tǒng)所有網(wǎng)絡(luò)設(shè)備的信息

          ???? 參數(shù): ? alldevsp ? 是一個 pcap_if_t 結(jié)構(gòu)體的指針,如果函數(shù) pcap_findalldevs 函數(shù)執(zhí)行成功,將獲得一個可用網(wǎng)卡的列表,而里面存儲的就是第一個元素的指針。

          ????????? ?? ?Errbuf ??? 存儲錯誤信息的字符串

          ???? 返回值: int ?? 如果返回 0 則執(zhí)行成功,錯誤返回 -1

          ? ? *************************************************/

          ?? 我們利用這個函數(shù)來獲得網(wǎng)卡名字的完整代碼如下:

          ?

          ?????? pcap_if_t* alldevs;

          ?????? pcap_if_t* d;

          ?????? char errbuf[PCAP_ERRBUF_SIZE];

          ?????? pcap_findalldevs(&alldevs,errbuf);?????? // 獲得網(wǎng)絡(luò)設(shè)備指針

          ?????? for(d=alldevs;d;d=d->next)?????????????? // 枚舉網(wǎng)卡然后添加到 ComboBox

          ?????? {

          d->name;?????????????????????????? ?// d->name 就是我們需要的網(wǎng)卡名字字符串,按照你 // 自己的需要保存到你的相應(yīng)變量中去

          ?????? }

          pcap_freealldevs(alldevs);?????????????? // 釋放 alldev 資源

          posted on 2007-02-16 15:51 飛鳥 閱讀(638) 評論(0)  編輯  收藏 所屬分類: VC
          主站蜘蛛池模板: 浮梁县| 屏山县| 白河县| 固镇县| 松阳县| 油尖旺区| 宝鸡市| 扬州市| 泰宁县| 越西县| 易门县| 洛南县| 济源市| 双峰县| 年辖:市辖区| 徐州市| 新河县| 石家庄市| 五台县| 永济市| 密云县| 西乌珠穆沁旗| 望谟县| 乐至县| 韶山市| 阳曲县| 云阳县| 嘉义县| 彩票| 永修县| 青龙| 固阳县| 新化县| 黑水县| 南和县| 云霄县| 弋阳县| 从化市| 汨罗市| 万州区| 电白县|