前
??
言
??
??
經(jīng)常看到論壇有人問(wèn)起關(guān)于數(shù)據(jù)包的截獲、分析等問(wèn)題,幸好本人也對(duì)此略有所知,也寫(xiě)過(guò)很多的
sniffer
,所以就想寫(xiě)一系列的文章來(lái)詳細(xì)深入的探討關(guān)于數(shù)據(jù)包的知識(shí)。
我希望通過(guò)這一系列的文章,能使得關(guān)于數(shù)據(jù)包的知識(shí)得以普及,所以這系列的每一篇文章我都會(huì)有由淺入深的解釋、詳細(xì)的分析、以及編碼步驟,另外附上帶有詳細(xì)注釋的源碼
(
為了照顧大多數(shù)朋友,我提供的都是
MFC
的源碼
)
。
不過(guò)由于也是初學(xué)者,疏漏之處還望不吝指正。
本文凝聚著筆者心血,如要轉(zhuǎn)載,請(qǐng)指明原作者及出處,謝謝!
^_^
?
OK,. Let’s go !? Have fun
!
! q^_^p
?
第二篇
??
手把手教你捕獲數(shù)據(jù)包
目錄:
一.
捕獲數(shù)據(jù)包的實(shí)現(xiàn)原理
二.
捕獲數(shù)據(jù)包的編程實(shí)現(xiàn):
1.?
?raw socket
的實(shí)現(xiàn)方法
2.?
?Winpcap
的實(shí)現(xiàn)方法
a.?????
枚舉本機(jī)網(wǎng)卡的信息
b.?????
打開(kāi)相應(yīng)網(wǎng)卡并設(shè)置為混雜模式
c.??????
截獲數(shù)據(jù)包并保存為文件
?
作者:
CSDN? VC/MFC
網(wǎng)絡(luò)編程版主
PiggyXP?
?
一.捕獲數(shù)據(jù)包的實(shí)現(xiàn)原理:
--------------------------------------------------------------------
在通常情況下,網(wǎng)絡(luò)通信的套接字程序只能響應(yīng)與自己硬件地址相匹配的或是以廣播形式發(fā)出的數(shù)據(jù)幀,對(duì)于其他形式的數(shù)據(jù)幀比如已到達(dá)網(wǎng)絡(luò)接口但卻不是發(fā)給此地址的數(shù)據(jù)幀,網(wǎng)絡(luò)接口在驗(yàn)證投遞地址并非自身地址之后將不引起響應(yīng),也就是說(shuō)應(yīng)用程序無(wú)法收取與自己無(wú)關(guān)的的數(shù)據(jù)包。
所以我們要想實(shí)現(xiàn)截獲流經(jīng)網(wǎng)絡(luò)設(shè)備的所有數(shù)據(jù)包,就要采取一點(diǎn)特別的手段了:
將網(wǎng)卡設(shè)置為混雜模式。
這樣一來(lái),該主機(jī)的網(wǎng)卡就可以捕獲到所有流經(jīng)其網(wǎng)卡的數(shù)據(jù)包和幀。
但是要注意一點(diǎn),這種截獲僅僅是數(shù)據(jù)包的一份拷貝,而不能對(duì)其進(jìn)行截?cái)?,要想截?cái)嗑W(wǎng)絡(luò)流量就要采用一些更底層的辦法了,不在本文的討論范圍之內(nèi)。
?
二.
捕獲數(shù)據(jù)包的編程實(shí)現(xiàn):
1.raw socket
的實(shí)現(xiàn)方法
--------------------------------------------------------------------
不同于我們常用的數(shù)據(jù)流套接字和數(shù)據(jù)報(bào)套接字,在創(chuàng)建了原始套接字后,需要用
WSAIoctl()
函數(shù)來(lái)設(shè)置一下,它的定義是這樣的
int WSAIoctl(
? SOCKET s,
? DWORD dwIoControlCode,
? LPVOID lpvInBuffer,
? DWORD cbInBuffer,
? LPVOID lpvOutBuffer,
? DWORD cbOutBuffer,
? LPDWORD lpcbBytesReturned,
? LPWSAOVERLAPPED lpOverlapped,
? LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
雖然咋一看參數(shù)比較多,但是其實(shí)我們最關(guān)心的只是其中的第二項(xiàng)而已,我們需要做的就是把第二項(xiàng)設(shè)置為
SIO_RCVALL
,講了這么多其實(shí)要做的就是這么一行代碼,很簡(jiǎn)單吧?
^_^
?
當(dāng)然我們還可以指定是否親自處理
IP
頭,但是這并不是必須的。
完整的代碼類(lèi)似與如下這樣,加粗的代碼是與平常不同的需要注意的地方:
(
為了讓代碼一目了然,我把錯(cuò)誤處理去掉了,下同
)
?
#include “WinSock2.h”
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
?
SOCKET SnifferSocket
? WSADATA wsaData;
? iFlag=WSAStartup(MAKEWORD(2,2),&wsaData);???????? ? //
開(kāi)啟
winsock.dll
?????????????????????????????????
SnifferSocket=WSASocket(AF_INET, ????????????//
創(chuàng)建
raw? socket
SOCK_RAW,
IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
?
? char FAR name[128];???? ???????????????????????????//
獲取本機(jī)
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);????????? ?//
端口號(hào)可以隨便改,當(dāng)然與當(dāng)然系統(tǒng)不能沖突
? memcpy(&(sa.sin_addr),pHostent->h_addr,pHostent->h_length);
?
bind(SnifferSocket,(LPSOCKADDR)&sa,sizeof(sa));????? ????? //
綁定
?
?
//
置
ioctl
來(lái)接收所有網(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 );
?
至此,實(shí)際就可以開(kāi)始對(duì)網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)行嗅探了,而對(duì)于數(shù)據(jù)包的接收還是和普通的
socket
一樣,通過(guò)
recv()
函數(shù)來(lái)完成,因?yàn)檫@里涉及到不同的
socket
模型,接收方法差別很大,所以在此就不提供接收的代碼了。
?
2.winpcap
的實(shí)現(xiàn)方法:
-----------------------------------------------------------------------
winpcap
驅(qū)動(dòng)包,是我們玩轉(zhuǎn)數(shù)據(jù)包不可或缺的好東東,
winpcap
的主要功能在于獨(dú)立于主機(jī)協(xié)議(如
TCP-IP)
而發(fā)送和接收原始數(shù)據(jù)報(bào),主要為我們提供了四大功能:
功能:
??? 1>
捕獲原始數(shù)據(jù)報(bào),包括在共享網(wǎng)絡(luò)上各主機(jī)發(fā)送
/
接收的以及相互之間交換的數(shù)據(jù)報(bào);
??? 2>
在數(shù)據(jù)報(bào)發(fā)往應(yīng)用程序之前,按照自定義的規(guī)則將某些特殊的數(shù)據(jù)報(bào)過(guò)濾掉;
??? 3>
在網(wǎng)絡(luò)上發(fā)送原始的數(shù)據(jù)報(bào);
??? 4>
收集網(wǎng)絡(luò)通信過(guò)程中的統(tǒng)計(jì)信息
如果環(huán)境允許的話
(
比如你做的不是木馬程序
)
,我還是推薦大家用
winpcap
來(lái)截獲數(shù)據(jù)包,因?yàn)樗墓δ芨鼜?qiáng)大,工作效率更高,唯一的缺點(diǎn)就是在運(yùn)行用
winpcap
開(kāi)發(fā)的程序以前,都要在主機(jī)上先安裝
winpcap
的
driver
。
而且一會(huì)我們就會(huì)發(fā)現(xiàn)它比
raw socket
功能強(qiáng)大的多,而且工作得更為底層,最明顯的理由就是
raw socket
捕獲的數(shù)據(jù)包是沒(méi)有以太頭的,此乃后話。
至于怎么來(lái)安裝使用,請(qǐng)參考本系列的系列一《手把手教你玩轉(zhuǎn)
ARP
包中的》,里面有詳細(xì)的加載
winpcap
驅(qū)動(dòng)的方法
^_^
廢話不多說(shuō)了,讓我們轉(zhuǎn)入正題
,
具體用
winpcap
來(lái)截獲數(shù)據(jù)包需要做如下的一些工作:
A .
枚舉本機(jī)網(wǎng)卡的信息
(
主要是獲得網(wǎng)卡的名稱(chēng)
)
??
其中要用到
pcap_findalldevs
函數(shù),它是這樣定義的
??
/*************************************************
int pcap_findalldevs? (? pcap_if_t **??? alldevsp,?
?
???????????????????????
???
?char *??? errbuf
?
?
?????????????????
???
???)?
??
??
功能:
???????????
?
枚舉系統(tǒng)所有網(wǎng)絡(luò)設(shè)備的信息
????
參數(shù):
? alldevsp
:
?
是一個(gè)
pcap_if_t
結(jié)構(gòu)體的指針,如果函數(shù)
pcap_findalldevs
函數(shù)執(zhí)行成功,將獲得一個(gè)可用網(wǎng)卡的列表,而里面存儲(chǔ)的就是第一個(gè)元素的指針。
?????????
??
?Errbuf
:
???
存儲(chǔ)錯(cuò)誤信息的字符串
????
返回值:
int
:
??
如果返回
0
則執(zhí)行成功,錯(cuò)誤返回
-1
。
?
?
*************************************************/
??
我們利用這個(gè)函數(shù)來(lái)獲得網(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
飛鳥(niǎo) 閱讀(633)
評(píng)論(0) 編輯 收藏 所屬分類(lèi):
VC