zoukankan      html  css  js  c++  java
  • 网络嗅探器

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

    原理:

      通常的套接字程序只能响应与自己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);
    }

    运行结果

  • 相关阅读:
    字典树Trie
    转载一个不错的LRU cache
    git和github基础入门
    git基础之常用操作
    python矩阵和向量的转置问题
    梯度下降法注意要点
    python 浮点数问题
    Python数据分析基础——读写CSV文件2
    Python数据分析基础——读写CSV文件
    读书笔记----javascript函数编程
  • 原文地址:https://www.cnblogs.com/xing901022/p/2734389.html
Copyright © 2011-2022 走看看