基于原始套接字的嗅探器
嗅探器這個(gè)代碼我去年的時(shí)候就已經(jīng)寫過了,這個(gè)學(xué)期并不是非常忙,順手復(fù)習(xí)網(wǎng)絡(luò),就又嘗試著寫了一遍。
其實(shí)在寫嗅探器的時(shí)候,最主要的還是要將網(wǎng)卡設(shè)置為混雜模式。在此基礎(chǔ)之上,對(duì)抓到的數(shù)據(jù)包進(jìn)行分析。
這個(gè)是我寫出來的效果圖,目前只是方便于查看,連菜單都沒添加:
左面的界面顯示的是主機(jī)和主機(jī)之間的鏈接信息,而右面則是選中主機(jī)信息之間的數(shù)據(jù)交互情況。
我覺得我這個(gè)嗅探器應(yīng)該是個(gè)失敗品,或者說,沒能夠真正的將網(wǎng)卡設(shè)置為混雜模式。因?yàn)榭梢钥吹?#xff0c;上面的源地址全部都是本地主機(jī)地址,我在下載視頻文件的時(shí)候,每秒幾百kb的數(shù)據(jù)交互我的這個(gè)程序基本沒響應(yīng)。網(wǎng)頁信息也都是發(fā)送的數(shù)據(jù)請(qǐng)求,根本抓不到接收數(shù)據(jù)。對(duì)于這一點(diǎn)希望高手能幫我指點(diǎn)一下。
使用原始套接字寫嗅探器的流程:
1 使用socket創(chuàng)建基于IP協(xié)議的原始套接字。
2 獲取本地IP地址。
3 將原始套接字綁定到本地IP地址上。
4 使用ioctlsocket函數(shù)設(shè)置套接字選項(xiàng)SIO_RCVALL,即接受所有數(shù)據(jù)。
5 無盡調(diào)用recv函數(shù)。
為了方便界面化我將Sniffer的核心代碼封裝到了一個(gè)類中,原本應(yīng)該做成單件類的,但是懶得改了。
1 class CSniffer 2 { 3 public: 4 static DWORD WINAPI SnifferThread(LPVOID lpData);//線程函數(shù) 5 public: 6 CSniffer(HostArray * pOutPut);//構(gòu)造函數(shù),數(shù)據(jù)輸出指針 7 ~CSniffer(void);//析構(gòu)函數(shù),負(fù)責(zé)終止線程 8 DWORD IsSucceed();//判斷構(gòu)造函數(shù)是否成功,我代碼中沒用上,就是單純的返回dwSucceed 9 private://Method 10 int IPHeadAnylasis(const char * pRecvBuf, const int nLen);//將IP數(shù)據(jù)存放到對(duì)應(yīng)數(shù)據(jù)結(jié)構(gòu)中。 11 unsigned short q_ntohs(const unsigned short nVal);//之前的遺留代碼,沒用上 12 const char * TypeTell(unsigned char type);//同上 13 unsigned short CheckSum(const void * pData, int size);//校驗(yàn)和函數(shù),可以用一下,但是我沒檢驗(yàn) 14 void AddToInfoVector(PPortArray pInfoVector, ip_hdr * pIp, int nLen);//添加新的端口信息 15 private://Data 16 PHostArray pSnifferPool;//指向輸出數(shù)據(jù),全部的信息都存在其指向 17 HANDLE hThread;//線程句柄 18 DWORD dwSucceed;//標(biāo)示參數(shù) 19 };然后值得看一看的就是線程函數(shù)代碼了,其余的沒有太多需要介紹的,這段代碼其實(shí)就是從之前的控制臺(tái)程序扒下來的,現(xiàn)在單獨(dú)放到一個(gè)函數(shù)中。
1 DWORD WINAPI CSniffer::SnifferThread(LPVOID lpData) 2 { 3 CSniffer * pSniffer = (CSniffer *)lpData; 4 5 SOCKET hSnifferSock = socket(AF_INET, SOCK_RAW, IPPROTO_IP); 6 DWORD dwSetVal = 1; 7 char szhostname[32]; 8 char RecvBuff[65536]; 9 hostent * phost; 10 SOCKADDR_IN LocalIP; 11 //先進(jìn)行綁定,綁定前先獲取本地地址 12 LocalIP.sin_family = AF_INET; 13 LocalIP.sin_port = htons(0); 14 gethostname(szhostname, 32); 15 phost = gethostbyname(szhostname); 16 memcpy(&LocalIP.sin_addr.S_un.S_addr, phost->h_addr_list[0], phost->h_length); 17 //cout << "LocalIP" << inet_ntoa(LocalIP.sin_addr) << endl; 18 if(SOCKET_ERROR == bind(hSnifferSock, (sockaddr *)&LocalIP, sizeof(sockaddr))) 19 { 20 ;//cout << "bind error" << endl; 21 } 22 //設(shè)置套接字選項(xiàng) 23 ioctlsocket(hSnifferSock, SIO_RCVALL, &dwSetVal); 24 //cout << q_ntohs(0x3100) << endl; 25 //std::vector<ConnectBetweenTwoHost> SnifferPool; 26 27 while(1) 28 { 29 int nRecvLen = recv(hSnifferSock, RecvBuff, 65536, 0); 30 if(nRecvLen != SOCKET_ERROR) 31 { 32 //cout << "Get Message" << endl; 33 pSniffer->IPHeadAnylasis(RecvBuff, 65536); 34 } 35 else 36 { 37 continue;//cout << "Nothing Valid" << endl; 38 } 39 } 40 41 return 0; 42 }感覺這一套下來卻是是沒什么東西,不過我也是在程序跑出來之后,才觀察到我的這個(gè)程序在數(shù)據(jù)抓包上面真心做的不怎么樣。chrome瀏覽器的數(shù)據(jù)請(qǐng)求能抓到,但是反饋回來的數(shù)據(jù)就完全抓不到了。
列表數(shù)據(jù)原本應(yīng)該做個(gè)排序的,整個(gè)散列也不錯(cuò),這樣當(dāng)數(shù)據(jù)量比較大的時(shí)候插入效率能高一點(diǎn)。而我這個(gè)就呵呵了。。。
值得一提的就是我這次兩個(gè)列表全部使用的虛擬列表。使用之前還查看了我以前代碼中關(guān)于ListCtrl的使用文檔,這算是沒白寫。不過這里要補(bǔ)充的就是,使用虛擬列表前,需要設(shè)置ownerdata選項(xiàng),也即是用戶擁有數(shù)據(jù),列表僅僅負(fù)責(zé)數(shù)據(jù)的顯示,而不是把所有的數(shù)據(jù)都放到列表中。
對(duì)虛擬列表進(jìn)行顯示刷新的方法比較簡單,只要調(diào)用SetItemCountEx就能實(shí)現(xiàn)刷新過程。
另外我昨天在網(wǎng)上下載了一個(gè)嗅探器,這叫一個(gè)慘啊,各種彈網(wǎng)頁,估計(jì)現(xiàn)在電腦是出于中木馬狀態(tài)。后來程序好不容易跑起來了,結(jié)果和我這個(gè)差不多,就是能判斷出來網(wǎng)頁請(qǐng)求信息資源的類型,僅僅是比我分析的深入了一點(diǎn),至于數(shù)據(jù)接收,也是沒找到。如果您知道哪有比較好的嗅探器,麻煩給發(fā)個(gè)鏈接,我學(xué)習(xí)下。
另外關(guān)于網(wǎng)卡混雜模式設(shè)置貌似需要借助winpcap.dll的幫助,有沒有大神比較了解,給個(gè)學(xué)習(xí)鏈接往我看一下。
總結(jié)
以上是生活随笔為你收集整理的基于原始套接字的嗅探器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网卡MAC地址相关信息大全
- 下一篇: 原始套接字与sniffer