网络嗅探器

发布时间:2025-12-09 11:55:39 浏览次数:1

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

原理:

  通常的套接字程序只能响应与自己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:%sn",::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("nn------------------------------------------------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->%sn",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->%dn",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.libclass 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   0x0806typedef 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     17typedef 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   0x80typedef 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("nn-------------------------------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);}

运行结果

网络嗅探器
需要做网站?需要网络推广?欢迎咨询客户经理 13272073477