使用Sniffer截獲流經(jīng)本機(jī)網(wǎng)卡的IP數(shù)據(jù)包
發(fā)表時(shí)間:2024-06-09 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]Win2K下的Sniffer源代碼。[代碼性質(zhì)] VC完整應(yīng)用程序代碼[代碼作者] zw[文件大小] 130K [更新日期] 2002-11-26 19:47:00 [下載次數(shù)] 6015 http://www.vckbase.com/code/downcode.asp?id=1692IP包監(jiān)聽...
Win2K下的Sniffer源代碼。
[代碼性質(zhì)] VC完整應(yīng)用程序代碼
[代碼作者] zw
[文件大小] 130K
[更新日期] 2002-11-26 19:47:00
[下載次數(shù)] 6015
http://www.vckbase.com/code/downcode.asp?id=1692
IP包監(jiān)聽程序(For 9x)源代碼 詳細(xì)信息 < 局域網(wǎng) >
IP包監(jiān)聽程序源代碼(包含VXD源代碼)
[代碼性質(zhì)] VC完整應(yīng)用程序代碼
[代碼作者] HiHint
[文件大小] 158K
[更新日期] 2002-3-30 8:48:00
[下載次數(shù)] 9047
http://www.vckbase.com/code/downcode.asp?id=1508
從事網(wǎng)絡(luò)安全的技術(shù)人員和相當(dāng)一部分準(zhǔn)黑客(指那些使用現(xiàn)成的黑客軟件進(jìn)行攻擊而不是根據(jù)需要去自己編寫代碼的人)都一定不會(huì)對(duì)網(wǎng)絡(luò)嗅探器(sniffer)感到陌生,網(wǎng)絡(luò)嗅探器無論是在網(wǎng)絡(luò)安全還是在黑客攻擊方面均扮演了很重要的角色。通過使用網(wǎng)絡(luò)嗅探器可以把網(wǎng)卡設(shè)置于混雜模式,并可實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)包的捕獲與分析。此分析結(jié)果可供網(wǎng)絡(luò)安全分析之用,但如為黑客所利用也可以為其發(fā)動(dòng)進(jìn)一步的攻擊提供有價(jià)值的信息?梢姡崽狡鲗(shí)際是一把雙刃劍。 雖然網(wǎng)絡(luò)嗅探器技術(shù)被黑客利用后會(huì)對(duì)網(wǎng)絡(luò)安全構(gòu)成一定的威脅,但嗅探器本身的危害并不是很大,主要是用來為其他黑客軟件提供網(wǎng)絡(luò)情報(bào),真正的攻擊主要是由其他黑軟來完成的。而在網(wǎng)絡(luò)安全方面,網(wǎng)絡(luò)嗅探手段可以有效地探測(cè)在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)包信息,通過對(duì)這些信息的分析利用是有助于網(wǎng)絡(luò)安全維護(hù)的。權(quán)衡利弊,有必要對(duì)網(wǎng)絡(luò)嗅探器的實(shí)現(xiàn)原理進(jìn)行介紹。
嗅探器設(shè)計(jì)原理
嗅探器作為一種網(wǎng)絡(luò)通訊程序,也是通過對(duì)網(wǎng)卡的編程來實(shí)現(xiàn)網(wǎng)絡(luò)通訊的,對(duì)網(wǎng)卡的編程也是使用通常的套接字(socket)方式來進(jìn)行。但是,通常的套接字程序只能響應(yīng)與自己硬件地址相匹配的或是以廣播形式發(fā)出的數(shù)據(jù)幀,對(duì)于其他形式的數(shù)據(jù)幀比如已到達(dá)網(wǎng)絡(luò)接口但卻不是發(fā)給此地址的數(shù)據(jù)幀,網(wǎng)絡(luò)接口在驗(yàn)證投遞地址并非自身地址之后將不引起響應(yīng),也就是說應(yīng)用程序無法收取到達(dá)的數(shù)據(jù)包。而網(wǎng)絡(luò)嗅探器的目的恰恰在于從網(wǎng)卡接收所有經(jīng)過它的數(shù)據(jù)包,這些數(shù)據(jù)包即可以是發(fā)給它的也可以是發(fā)往別處的。顯然,要達(dá)到此目的就不能再讓網(wǎng)卡按通常的正常模式工作,而必須將其設(shè)置為混雜模式。
具體到編程實(shí)現(xiàn)上,這種對(duì)網(wǎng)卡混雜模式的設(shè)置是通過原始套接字(raw socket)來實(shí)現(xiàn)的,這也有別于通常經(jīng)常使用的數(shù)據(jù)流套接字和數(shù)據(jù)報(bào)套接字。在創(chuàng)建了原始套接字后,需要通過setsockopt()函數(shù)來設(shè)置IP頭操作選項(xiàng),然后再通過bind()函數(shù)將原始套接字綁定到本地網(wǎng)卡。為了讓原始套接字能接受所有的數(shù)據(jù),還需要通過ioctlsocket()來進(jìn)行設(shè)置,而且還可以指定是否親自處理IP頭。至此,實(shí)際就可以開始對(duì)網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)行嗅探了,對(duì)數(shù)據(jù)包的獲取仍象流式套接字或數(shù)據(jù)報(bào)套接字那樣通過recv()函數(shù)來完成。但是與其他兩種套接字不同的是,原始套接字此時(shí)捕獲到的數(shù)據(jù)包并不僅僅是單純的數(shù)據(jù)信息,而是包含有 IP頭、 TCP頭等信息頭的最原始的數(shù)據(jù)信息,這些信息保留了它在網(wǎng)絡(luò)傳輸時(shí)的原貌。通過對(duì)這些在低層傳輸?shù)脑夹畔⒌姆治隹梢缘玫接嘘P(guān)網(wǎng)絡(luò)的一些信息。由于這些數(shù)據(jù)經(jīng)過了網(wǎng)絡(luò)層和傳輸層的打包,因此需要根據(jù)其附加的幀頭對(duì)數(shù)據(jù)包進(jìn)行分析。下面先給出結(jié)構(gòu).數(shù)據(jù)包的總體結(jié)構(gòu):
數(shù)據(jù)包
IP頭 TCP頭(或其他信息頭) 數(shù)據(jù)
數(shù)據(jù)在從應(yīng)用層到達(dá)傳輸層時(shí),將添加TCP數(shù)據(jù)段頭,或是UDP數(shù)據(jù)段頭。其中UDP數(shù)據(jù)段頭比較簡(jiǎn)單,由一個(gè)8字節(jié)的頭和數(shù)據(jù)部分組成,具體格式如下:
16位 16位
源端口 目的端口
UDP長(zhǎng)度 UDP校驗(yàn)和
而TCP數(shù)據(jù)頭則比較復(fù)雜,以20個(gè)固定字節(jié)開始,在固定頭后面還可以有一些長(zhǎng)度不固定的可選項(xiàng),下面給出TCP數(shù)據(jù)段頭的格式組成:
16位 16位
源端口 目的端口
順序號(hào)
確認(rèn)號(hào)
TCP頭長(zhǎng) (保留)7位 URG ACK PSH RST SYN FIN 窗口大小
校驗(yàn)和 緊急指針
可選項(xiàng)(0或更多的32位字)
數(shù)據(jù)(可選項(xiàng))
對(duì)于此TCP數(shù)據(jù)段頭的分析在編程實(shí)現(xiàn)中可通過數(shù)據(jù)結(jié)構(gòu)_TCP來定義:
typedef struct _TCP{ WORD SrcPort; // 源端口
WORD DstPort; // 目的端口
DWORD SeqNum; // 順序號(hào)
DWORD AckNum; // 確認(rèn)號(hào)
BYTE DataOff; // TCP頭長(zhǎng)
BYTE Flags; // 標(biāo)志(URG、ACK等)
WORD Window; // 窗口大小
WORD Chksum; // 校驗(yàn)和
WORD UrgPtr; // 緊急指針
} TCP;
typedef TCP *LPTCP;
typedef TCP UNALIGNED * ULPTCP;
在網(wǎng)絡(luò)層,還要給TCP數(shù)據(jù)包添加一個(gè)IP數(shù)據(jù)段頭以組成IP數(shù)據(jù)報(bào)。IP數(shù)據(jù)頭以大端點(diǎn)機(jī)次序傳送,從左到右,版本字段的高位字節(jié)先傳輸(SPARC是大端點(diǎn)機(jī);Pentium是小端點(diǎn)機(jī))。如果是小端點(diǎn)機(jī),就要在發(fā)送和接收時(shí)先行轉(zhuǎn)換然后才能進(jìn)行傳輸。IP數(shù)據(jù)段頭格式如下:
16位 16位
版本 IHL 服務(wù)類型 總長(zhǎng)
標(biāo)識(shí) 標(biāo)志 分段偏移
生命期 協(xié)議 頭校驗(yàn)和
源地址
目的地址
選項(xiàng)(0或更多)
同樣,在實(shí)際編程中也需要通過一個(gè)數(shù)據(jù)結(jié)構(gòu)來表示此IP數(shù)據(jù)段頭,下面給出此數(shù)據(jù)結(jié)構(gòu)的定義:
typedef struct _IP{
union{ BYTE Version; // 版本
BYTE HdrLen; // IHL
};
BYTE ServiceType; // 服務(wù)類型
WORD TotalLen; // 總長(zhǎng)
WORD ID; // 標(biāo)識(shí)
union{ WORD Flags; // 標(biāo)志
WORD FragOff; // 分段偏移
};
BYTE TimeToLive; // 生命期
BYTE Protocol; // 協(xié)議
WORD HdrChksum; // 頭校驗(yàn)和
DWORD SrcAddr; // 源地址
DWORD DstAddr; // 目的地址
BYTE Options; // 選項(xiàng)
} IP;
typedef IP * LPIP;
typedef IP UNALIGNED * ULPIP;
在明確了以上幾個(gè)數(shù)據(jù)段頭的組成結(jié)構(gòu)后,就可以對(duì)捕獲到的數(shù)據(jù)包進(jìn)行分析了。
嗅探器的具體實(shí)現(xiàn)
根據(jù)前面的設(shè)計(jì)思路,不難寫出網(wǎng)絡(luò)嗅探器的實(shí)現(xiàn)代碼,下面就給出一個(gè)簡(jiǎn)單的示例,該示例可以捕獲到所有經(jīng)過本地網(wǎng)卡的數(shù)據(jù)包,并可從中分析出協(xié)議、IP源地址、IP目標(biāo)地址、TCP源端口號(hào)、TCP目標(biāo)端口號(hào)以及數(shù)據(jù)包長(zhǎng)度等信息。由于前面已經(jīng)將程序的設(shè)計(jì)流程講述的比較清楚了,因此這里就不在贅述了,下面就結(jié)合注釋對(duì)程序的具體是實(shí)現(xiàn)進(jìn)行講解,同時(shí)為程序流程的清晰起見,去掉了錯(cuò)誤檢查等保護(hù)性代碼。主要代碼實(shí)現(xiàn)清單為:
// 檢查 Winsock 版本號(hào),WSAData為WSADATA結(jié)構(gòu)對(duì)象
WSAStartup(MAKEWORD(2, 2), &WSAData);
// 創(chuàng)建原始套接字
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW));
// 設(shè)置IP頭操作選項(xiàng),其中flag 設(shè)置為ture,親自對(duì)IP頭進(jìn)行處理
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));
// 獲取本機(jī)名
gethostname((char*)LocalName, sizeof(LocalName)-1);
// 獲取本地 IP 地址
pHost = gethostbyname((char*)LocalName));
// 填充SOCKADDR_IN結(jié)構(gòu)
addr_in.sin_addr = *(in_addr *)pHost->h_addr_list[0]; //IP
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(57274);
// 把原始套接字sock 綁定到本地網(wǎng)卡地址上
bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in));
// dwValue為輸入輸出參數(shù),為1時(shí)執(zhí)行,0時(shí)取消
DWORD dwValue = 1;
// 設(shè)置 SOCK_RAW 為SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL
// 的定義為: #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
ioctlsocket(sock, SIO_RCVALL, &dwValue);
前面的工作基本上都是對(duì)原始套接字進(jìn)行設(shè)置,在將原始套接字設(shè)置完畢,使其能按預(yù)期目的工作時(shí),就可以通過recv()函數(shù)從網(wǎng)卡接收數(shù)據(jù)了,接收到的原始數(shù)據(jù)包存放在緩存RecvBuf[]中,緩沖區(qū)長(zhǎng)度BUFFER_SIZE定義為65535。然后就可以根據(jù)前面對(duì)IP數(shù)據(jù)段頭、TCP數(shù)據(jù)段頭的結(jié)構(gòu)描述而對(duì)捕獲的數(shù)據(jù)包進(jìn)行分析:
while (true)
{
// 接收原始數(shù)據(jù)包信息
int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);
if (ret > 0)
{
// 對(duì)數(shù)據(jù)包進(jìn)行分析,并輸出分析結(jié)果
ip = *(IP*)RecvBuf;
tcp = *(TCP*)(RecvBuf + ip.HdrLen);
TRACE("協(xié)議: %s\r\n",GetProtocolTxt(ip.Protocol));
TRACE("IP源地址: %s\r\n",inet_ntoa(*(in_addr*)&ip.SrcAddr));
TRACE("IP目標(biāo)地址: %s\r\n",inet_ntoa(*(in_addr*)&ip.DstAddr));
TRACE("TCP源端口號(hào): %d\r\n",tcp.SrcPort);
TRACE("TCP目標(biāo)端口號(hào):%d\r\n",tcp.DstPort);
TRACE("數(shù)據(jù)包長(zhǎng)度: %d\r\n\r\n\r\n",ntohs(ip.TotalLen));
}
}
其中,在進(jìn)行協(xié)議分析時(shí),使用了GetProtocolTxt()函數(shù),該函數(shù)負(fù)責(zé)將IP包中的協(xié)議(數(shù)字標(biāo)識(shí)的)轉(zhuǎn)化為文字輸出,該函數(shù)實(shí)現(xiàn)如下:
#define PROTOCOL_STRING_ICMP_TXT "ICMP"
#define PROTOCOL_STRING_TCP_TXT "TCP"
#define PROTOCOL_STRING_UDP_TXT "UDP"
#define PROTOCOL_STRING_SPX_TXT "SPX"
#define PROTOCOL_STRING_NCP_TXT "NCP"
#define PROTOCOL_STRING_UNKNOW_TXT "UNKNOW"
……
CString CSnifferDlg::GetProtocolTxt(int Protocol)
{
switch (Protocol){
case IPPROTO_ICMP : //1 /* control message protocol */
return PROTOCOL_STRING_ICMP_TXT;
case IPPROTO_TCP : //6 /* tcp */
return PROTOCOL_STRING_TCP_TXT;
case IPPROTO_UDP : //17 /* user datagram protocol */
return PROTOCOL_STRING_UDP_TXT;
default:
return PROTOCOL_STRING_UNKNOW_TXT;
}
最后,為了使程序能成功編譯,需要包含頭文件winsock2.h和ws2tcpip.h。在本示例中將分析結(jié)果用TRACE()宏進(jìn)行輸出,在調(diào)試狀態(tài)下運(yùn)行,得到的一個(gè)分析結(jié)果如下:
協(xié)議: UDP
IP源地址: 172.168.1.5
IP目標(biāo)地址: 172.168.1.255
TCP源端口號(hào): 16707
TCP目標(biāo)端口號(hào):19522
數(shù)據(jù)包長(zhǎng)度: 78
……
協(xié)議: TCP
IP源地址: 172.168.1.17
IP目標(biāo)地址: 172.168.1.1
TCP源端口號(hào): 19714
TCP目標(biāo)端口號(hào):10
數(shù)據(jù)包長(zhǎng)度: 200
……
從分析結(jié)果可以看出,此程序完全具備了嗅探器的數(shù)據(jù)捕獲以及對(duì)數(shù)據(jù)包的分析等基本功能。
小結(jié)
本文介紹的以原始套接字方式對(duì)網(wǎng)絡(luò)數(shù)據(jù)進(jìn)行捕獲的方法實(shí)現(xiàn)起來比較簡(jiǎn)單,尤其是不需要編寫VxD虛擬設(shè)備驅(qū)動(dòng)程序就可以實(shí)現(xiàn)抓包,使得其編寫過程變的非常簡(jiǎn)便,但由于捕獲到的數(shù)據(jù)包頭不包含有幀信息,因此不能接收到與 IP 同屬網(wǎng)絡(luò)層的其它數(shù)據(jù)包, 如 ARP數(shù)據(jù)包、RARP數(shù)據(jù)包等。在前面給出的示例程序中考慮到安全因素,沒有對(duì)數(shù)據(jù)包做進(jìn)一步的分析,而是僅僅給出了對(duì)一般信息的分析方法。通過本文的介紹,可對(duì)原始套接字的使用方法以及TCP/IP協(xié)議結(jié)構(gòu)原理等知識(shí)有一個(gè)基本的認(rèn)識(shí)。本文所述代碼在Windows 2000下由Microsoft Visual C++ 6.0編譯調(diào)試通過。