前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络嗅探器

网络嗅探器

作者头像
用户1154259
发布2018-01-17 15:45:13
2K0
发布2018-01-17 15:45:13
举报

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

原理:

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

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

设置混杂模式:

  创建原始套接字,

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

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

  接收所有的IP包

代码实现步骤:

  1 创建原始套接字

  2 绑定到明确地址

  3 这是SIO_RCVALL控制代码

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

主程序代码如下

代码语言:javascript
复制
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头代码

代码语言:javascript
复制
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头代码如下:取出端口号,输出

代码语言:javascript
复制
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:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
//////////////////////////////////////////////////
// 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__
代码语言:javascript
复制
#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);
}

运行结果

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2012-10-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档