网络嗅探器

匿名 (未验证) 提交于 2019-12-02 23:43:01

网络嗅探器:把网卡设置成混杂模式,并可实现对网络上传输的数据包的捕获与分析。

原理:

  通常的套接字程序只能响应与自己MAC地址相匹配的 或者是 广播形式发出的数据帧,对于其他形式的数据帧网络接口采取的动作是直接丢弃

  为了使网卡接收所有经过他的封包,要将其设置成混杂模式,通过原始套接字来实现。

设置混杂模式:

  创建原始套接字,

  绑定到一个明确的本地地址,

  向套接字发送SIO_RCVALL控制命令,

  接收所有的IP包

代码实现步骤:

  1 创建原始套接字

  2 绑定到明确地址

  3 这是SIO_RCVALL控制代码

  4 进入循环,调用recv函数接收经过本地网卡的IP封包。

主程序代码如下

void main() {     //创建原始套接字     SOCKET sRaw = socket(AF_INET,SOCK_RAW,IPPROTO_IP);     //获取本地IP地址     char szHostName[56];     SOCKADDR_IN addr_in;     struct hostent *pHost;     gethostname(szHostName,56);     if((pHost=gethostbyname((char*)szHostName))==NULL)         return;     //套接字绑定     addr_in.sin_family = AF_INET;     addr_in.sin_port = htons(0);     memcpy(&addr_in.sin_addr.S_un.S_addr,pHost->h_addr_list[0],pHost->h_length);     printf("Binding to interface:%s\n",::inet_ntoa(addr_in.sin_addr));     if(bind(sRaw,(sockaddr*)&addr_in,sizeof(addr_in))==SOCKET_ERROR)         return;     //设置SIO_RECVALL控制代码     DWORD dwValue = 1;     if(ioctlsocket(sRaw,SIO_RCVALL,&dwValue)!=0)         return;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  //开始接收封包     char buff[1024];     int nRet;     while(true)     {         nRet = recv(sRaw,buff,1024,0);         if(nRet>0)         {             DecodeIPPacket(buff);         }     }     closesocket(sRaw); }

程序接收到IP封包后,调用自定义的DecodeIPPacket进行解包。取出封包中的协议头,向用户打印出协议信息。

解析IP头代码

void DecodeIPPacket(char *pData) {     IPHeader *pIPHdr = (IPHeader*)pData;     in_addr source,dest;     char szSourceIp[32],szDestIp[32];     printf("\n\n------------------------------------------------\n");     //从IP头中取出源IP和目的IP     source.S_un.S_addr = pIPHdr->ipSource;     dest.S_un.S_addr = pIPhdr->ipDestination;      strcpy(szSourceIp,::inet_ntoa(source));     strcpy(szDestIp,::inet_ntoa(dest));     printf("        %s->%s\n",szSourceIp,szDestIp);     //IP长度     int nHeaderLen = (pIPHdr->iphVerLen & 0xf)*sizeof(ULONG);     switch(pIPHdr->ipProtocol)     {     case IPPROTO_TCP:         DecodeTCPPacket(pData+nHeaderLen);         break;     case IPPROTO_UDP:         break;     case IPPROTO_ICMP:         break;     } }

解析TCP头代码如下:取出端口号,输出

void DecodeTCPPacket(char *pData) {     TCPHeader &pTCPHdr = (TCPHeader*)pData;     printf("Port:%d->%d\n",ntohs(pTCPHdr->sourcePort),ntohs(pTCOHdr->destinationPort));     switch(::ntohs(pTCPHdr->destinationPort))     {     case 21:         break;     case 80:         break;     case 8080:         break;     } }

VS下完整代码:

initsock.h:

#include <winsock2.h> #pragma comment(lib, "WS2_32")    // 链接到WS2_32.lib  class CInitSock         { public:     CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)     {         // 初始化WS2_32.dll         WSADATA wsaData;         WORD sockVersion = MAKEWORD(minorVer, majorVer);         if(::WSAStartup(sockVersion, &wsaData) != 0)         {             exit(0);         }     }     ~CInitSock()     {             ::WSACleanup();         } };

protoinfo.h:

////////////////////////////////////////////////// // protoinfo.h文件  /*  定义协议格式 定义协议中使用的宏   */   #ifndef __PROTOINFO_H__ #define __PROTOINFO_H__   #define ETHERTYPE_IP    0x0800 #define ETHERTYPE_ARP   0x0806  typedef struct _ETHeader         // 14字节的以太头 {     UCHAR    dhost[6];            // 目的MAC地址destination mac address     UCHAR    shost[6];            // 源MAC地址source mac address     USHORT    type;                // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等 } ETHeader, *PETHeader;   #define ARPHRD_ETHER     1  // ARP协议opcodes #define    ARPOP_REQUEST    1        // ARP 请求     #define    ARPOP_REPLY        2        // ARP 响应   typedef struct _ARPHeader        // 28字节的ARP头 {     USHORT    hrd;                //    硬件地址空间,以太网中为ARPHRD_ETHER     USHORT    eth_type;            //  以太网类型,ETHERTYPE_IP ??     UCHAR    maclen;                //    MAC地址的长度,为6     UCHAR    iplen;                //    IP地址的长度,为4     USHORT    opcode;                //    操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应     UCHAR    smac[6];            //    源MAC地址     UCHAR    saddr[4];            //    源IP地址     UCHAR    dmac[6];            //    目的MAC地址     UCHAR    daddr[4];            //    目的IP地址 } ARPHeader, *PARPHeader;   // 协议 #define PROTO_ICMP    1 #define PROTO_IGMP    2 #define PROTO_TCP     6 #define PROTO_UDP     17  typedef struct _IPHeader        // 20字节的IP头 {     UCHAR     iphVerLen;      // 版本号和头长度(各占4位)     UCHAR     ipTOS;          // 服务类型      USHORT    ipLength;       // 封包总长度,即整个IP报的长度     USHORT    ipID;              // 封包标识,惟一标识发送的每一个数据报     USHORT    ipFlags;          // 标志     UCHAR     ipTTL;          // 生存时间,就是TTL     UCHAR     ipProtocol;     // 协议,可能是TCP、UDP、ICMP等     USHORT    ipChecksum;     // 校验和     ULONG     ipSource;       // 源IP地址     ULONG     ipDestination;  // 目标IP地址 } IPHeader, *PIPHeader;    // 定义TCP标志 #define   TCP_FIN   0x01 #define   TCP_SYN   0x02 #define   TCP_RST   0x04 #define   TCP_PSH   0x08 #define   TCP_ACK   0x10 #define   TCP_URG   0x20 #define   TCP_ACE   0x40 #define   TCP_CWR   0x80  typedef struct _TCPHeader        // 20字节的TCP头 {     USHORT    sourcePort;            // 16位源端口号     USHORT    destinationPort;    // 16位目的端口号     ULONG    sequenceNumber;        // 32位序列号     ULONG    acknowledgeNumber;    // 32位确认号     UCHAR    dataoffset;            // 高4位表示数据偏移     UCHAR    flags;                // 6位标志位                                 //FIN - 0x01                                 //SYN - 0x02                                 //RST - 0x04                                  //PUSH- 0x08                                 //ACK- 0x10                                 //URG- 0x20                                 //ACE- 0x40                                 //CWR- 0x80      USHORT    windows;            // 16位窗口大小     USHORT    checksum;            // 16位校验和     USHORT    urgentPointer;        // 16位紧急数据偏移量  } TCPHeader, *PTCPHeader;  typedef struct _UDPHeader {     USHORT            sourcePort;        // 源端口号             USHORT            destinationPort;// 目的端口号             USHORT            len;            // 封包长度     USHORT            checksum;        // 校验和 } UDPHeader, *PUDPHeader;  #endif // __PROTOINFO_H__

#include "../common/initsock.h" #include "../common/protoinfo.h"   #include <stdio.h> #include <mstcpip.h>  #pragma comment(lib, "Advapi32.lib")  CInitSock theSock;  void DecodeTCPPacket(char *pData) {     TCPHeader *pTCPHdr = (TCPHeader *)pData;      printf(" Port: %d -> %d \n", ntohs(pTCPHdr->sourcePort), ntohs(pTCPHdr->destinationPort));          // 下面还可以根据目的端口号进一步解析应用层协议     switch(::ntohs(pTCPHdr->destinationPort))     {     case 21:         break;     case 80:     case 8080:         break;     } }  void DecodeIPPacket(char *pData) {     IPHeader *pIPHdr = (IPHeader*)pData;         in_addr source, dest;     char szSourceIp[32], szDestIp[32];       printf("\n\n-------------------------------\n");      // 从IP头中取出源IP地址和目的IP地址     source.S_un.S_addr = pIPHdr->ipSource;     dest.S_un.S_addr = pIPHdr->ipDestination;     strcpy(szSourceIp, ::inet_ntoa(source));     strcpy(szDestIp, ::inet_ntoa(dest));      printf("    %s -> %s \n", szSourceIp, szDestIp);     // IP头长度     int nHeaderLen = (pIPHdr->iphVerLen & 0xf) * sizeof(ULONG);      switch(pIPHdr->ipProtocol)     {     case IPPROTO_TCP: // TCP协议         DecodeTCPPacket(pData + nHeaderLen);         break;     case IPPROTO_UDP:         break;     case IPPROTO_ICMP:         break;      } }   void main() {     // 创建原始套节字     SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);      // 获取本地IP地址     char szHostName[56];     SOCKADDR_IN addr_in;     struct  hostent *pHost;     gethostname(szHostName, 56);     if((pHost = gethostbyname((char*)szHostName)) == NULL)             return ;      // 在调用ioctl之前,套节字必须绑定     addr_in.sin_family  = AF_INET;     addr_in.sin_port    = htons(0);     memcpy(&addr_in.sin_addr.S_un.S_addr, pHost->h_addr_list[0], pHost->h_length);      printf(" Binding to interface : %s \n", ::inet_ntoa(addr_in.sin_addr));     if(bind(sRaw, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)         return;      // 设置SIO_RCVALL控制代码,以便接收所有的IP包         DWORD dwValue = 1;     if(ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0)             return ;          // 开始接收封包     char buff[1024];     int nRet;     while(TRUE)     {         nRet = recv(sRaw, buff, 1024, 0);         if(nRet > 0)         {             DecodeIPPacket(buff);         }     }     closesocket(sRaw); }

运行结果

转载于:https://my.oschina.net/u/204616/blog/545182

文章来源: https://blog.csdn.net/weixin_34029949/article/details/91990189
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!