P欺诈,使用Winpcap对数据包进行拦截

来源:互联网 发布:电信运营商数据 编辑:程序博客网 时间:2024/04/30 13:51
  

上一篇讲到了对所有的网络数据包进行侦听,并过滤,得到自己想要分析的数据包。数据包被侦听到了,但仍旧发送给了远程的服务器,若我们希望截获这些数据包,但不希望把这些数据被发送给远程服务器,那该如何解决呢?防火墙!对,我也想到了使用防火墙。windows下的防火墙,大多使用NIDS(Network Driver Interface Specification)对中间层驱动(Intermediate drivers)进行操作。NIDS就是把IP包拦截在中间驱动层,使这些不能通过网卡发送。但是这样做的话,上一篇的模拟sniffer程序也侦听不到被NIDS所拦截的IP包。因此,防火墙行不通。

        使用网卡的混杂模式,通过伪造TCP握手信号,赶在本机与远程端握手连通之前,把本机的手牵到自己这里来,不是也可以实现吗?这正是我所要讲的重点。没错,我的实现思路也是这样的。sendto 函数只在windows server 2003 下支持,在windows XP系统下,为了保证网络安全,已经不再被支持。有网友说可以用Wsasend()可以替代sendto,为了节约时间,我没有尝试去用Wsasend()函数。

        使用Winpcap(windows packet capture)可以完成所需要的功能。winpcap独立于主机协议(如TCP-IP)而发送和接收原始数据包。Winpcap为数据包捕获提供了windows下的一个平台,它是由伯克利分组捕获库派生而来的分组捕获库,它是在Windows操作平台上来实现对底层包的截取过滤,它的体系结构是由一个核心的包过滤驱动程序,一个底层的动态连接库packet.dll和一个高层的独立于系统的函数库libpcap组成。

        调用winpcap函数的程序,需要安装winpcap程序,使之能与驱动挂上钩。还需要下载winpcap的头文件和相应的库文件。这样程序才能够跑得起来。


        首先先来介绍一下包头。除了上一篇介绍的IP头,TCP、UDP、ICMP头外,这里还有两个头:以太网地址包头和计算校验码的包头。

        typedef struct _ethhdr
        {
            unsigned char  eh_dst[6];
            unsigned char  eh_src[6];
            unsigned short eh_type;  

        }ETH_HEADER;

 

        typedef struct _psdhdr
        {
            unsigned long saddr;
            unsigned long daddr;
            char mbz;                           //保留,置0
            char ptcl;                            //协议,如IPPROTO_TCP
            unsigned short tcpl;            //TCP报头长度
        }PSD_HEADER;

 

        写一个对数据进行处理的类。

       class CTod
  {
  public:
    CTod(void);
    ~CTod(void);

  public:
    pcap*  m_pCap;    //PCAP句柄

  public:
    int CTod::SendRaw(BYTE *_dmac,BYTE *_smac,  
             USHORT _ident,  

             ULONG _saddr,USHORT _sport,  

             ULONG _daddr,USHORT _dport, 
                                             ULONG _seq,  ULONG  _ack);

              USHORT checksum(USHORT *buffer, int size); 
              BOOL OpenPcap(ULONG _laddr);                     
//打开本地网口
              static DWORD WINAPI WorkSniffer(LPVOID _lp);     
//抓包线程
        };

 

 

        CTod::CTod(void)
        {}

        CTod::~CTod(void)
        {}

        int CTod::SendRaw(BYTE *_dmac,BYTE *_smac,        //目的MAC,源MAC,网络顺序
                          USHORT _ident,                  //IP包标识号
                          ULONG _saddr,USHORT _sport,     //源IP,PORT,网络顺序
                          ULONG _daddr,USHORT _dport,     //目的IP,PORT,网络顺序
                          ULONG _seq,  ULONG  _ack)       //32位序列号,应答号,网络顺序
        {
            if(m_pCap==NULL){
                return -1;
            }

            //构造以太网头
            ETH_HEADER eth;
            memcpy(eth.eh_dst,_dmac,6);
            memcpy(eth.eh_src,_smac,6);
            eth.eh_type=htons(ETH_IP);

            //构造IP头
            IP_HEADER ip;
            ip.h_verlen= 4<<4 | sizeof(IP_HEADER)/4;
            ip.tos=0;
            ip.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER));
            ip.ident=_ident;
            ip.frag_and_frag=htons(0x4000); //禁止分片
            ip.ttl=128;
            ip.proto=IPPROTO_TCP;
            ip.cksum=0;
            ip.saddr=_saddr;
            ip.daddr=_daddr;

            //构造TCP头
            TCP_HEADER tcp;
            tcp.th_sport=_sport;
            tcp.th_dport=_dport;
            tcp.th_seq=_seq;
            tcp.th_ack=_ack;
            tcp.th_lenres=sizeof(TCP_HEADER)/4<<4 | 0;
           
            tcp.th_flag= SYN | ACK;
            tcp.th_win=htons(512);
            tcp.th_cksum=0;
            tcp.th_urp=0;

            //构造PSD头
            PSD_HEADER psd;
            psd.saddr=ip.saddr;
            psd.daddr=ip.daddr;
            psd.mbz=0;
            psd.ptcl=IPPROTO_TCP;
            psd.tcpl=htons(sizeof(TCP_HEADER));

            //开始装包并计算校验和
            char szbuf[128]={0};
            memcpy(szbuf,&psd,sizeof(psd));
            memcpy(szbuf+sizeof(psd),&tcp,sizeof(tcp));
            tcp.th_cksum=checksum((USHORT*)szbuf,sizeof(psd)+sizeof(tcp));

            ip.cksum =checksum((USHORT*)&ip,sizeof(ip));

            memset(szbuf,0,sizeof(szbuf));
            memcpy(szbuf,&eth,sizeof(eth));
            memcpy(szbuf+sizeof(eth),&ip,sizeof(ip));
            memcpy(szbuf+sizeof(eth)+sizeof(ip),&tcp,sizeof(tcp));
            memset(szbuf+sizeof(eth)+sizeof(ip)+sizeof(tcp),0,4);

            int bytes_out=0;
            int len=sizeof(eth)+sizeof(ip)+sizeof(tcp);

           
            int ret=pcap_sendpacket(m_pCap,(BYTE*)szbuf,len);
            if(ret!=0){
                bytes_out=-1;
            }
            else{
                bytes_out=len;
            }

            return bytes_out;

        }

        //计算校验和
        USHORT CTod::checksum(USHORT *buffer, int size)
        {
            unsigned long cksum=0;
            while(size>1){
                cksum+=*buffer++;
                size-=sizeof(USHORT);
            }
            if(size) cksum+=*(UCHAR*)buffer;
            cksum=(cksum>>16)+(cksum&0xffff);
            cksum+=(cksum>>16);
            return (USHORT)(~cksum);

        }

      

    未完,见下一篇。。。 

 

 接上一篇。。。

 

    //打开一个网卡
    BOOL CTod::OpenPcap(ULONG _laddr)
    {
        pcap_if_t *alldevs;  //打开适配器时使用
        pcap_if_t *d;
        char errbuf[PCAP_ERRBUF_SIZE];

        if(pcap_findalldevs(&alldevs,errbuf)==-1){ //获取网卡的列表
            return FALSE;
        }

        BOOL bfind=FALSE;
        for(d=alldevs; d; d=d->next){
            for(pcap_addr_t *a=d->addresses; a; a=a->next){
                struct sockaddr_in *psin=(struct sockaddr_in*)a->addr;
                if( psin->sin_family==AF_INET ){
                    if( psin->sin_addr.s_addr==_laddr ){
                        bfind=TRUE;
                        break;
                    }
                }
            }
            if(bfind)
                break;
        }

        if(!bfind){
            pcap_freealldevs(alldevs);
            return FALSE;

        }

        //打开选择的网卡
        if((m_pCap=pcap_open_live(d->name,  // 设备名称
                              65535,  // portion of the packet to capture
                              1,   // 混杂模式
                              100,  // 读超时为0.1秒
                              errbuf  // error buffer
                              ))==NULL)
        {
            fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
            pcap_freealldevs(alldevs);   //释放设备列表
            return FALSE;
        }

        pcap_setbuff(m_pCap,1024*1024);   //设置内核缓冲区,pcap默认是1M缓冲

        struct bpf_program fcode;    //指向BPF指令所在空间
        char filter[4]="tcp";
        ULONG netmask=0x00ffffff;
        ULONG mask=*(ULONG*)&(((struct sockaddr_in*)d->addresses->netmask)->sin_addr);
        netmask=mask;
        pcap_compile(m_pCap, &fcode,filter,1,netmask); //编译 tcpdump 表达式为BPF程序
        pcap_setfilter(m_pCap, &fcode);     //设置BPF内核过滤器
        pcap_freecode(&fcode);       
//释放指令空间

        pcap_freealldevs(alldevs);  //释放设备列表

        return TRUE;
    }

 

    //抓包子线程
    DWORD WINAPI CTod::WorkSniffer(LPVOID _lp)
    {
        CTod *ptod=(CTod*)_lp;
        struct pcap_pkthdr *header;
        u_char *pkt_data;

        char szSourceIP[MAX_ADDR_LEN];
        char szDestIP[MAX_ADDR_LEN];

        int ret=0;
        while(TRUE)
        
            //捕获数据包
            ret=pcap_next_ex(ptod->m_pCap,
                             &header, //内核过滤器每输出一个包,将在输出的数据前加了20字节的数据
                             (const u_char**)&pkt_data);
            if(ret<=0)
                continue;

            ETH_HEADER *peth=(ETH_HEADER*)pkt_data;
            IP_HEADER *pip=(IP_HEADER*)(pkt_data+sizeof(ETH_HEADER));
            TCP_HEADER *ptcp=(TCP_HEADER*)(pkt_data+sizeof(ETH_HEADER)+sizeof(IP_HEADER));

 

 

            unsigned long szSourIP = pip->saddr;
           if( IsAlexaDes(szSourIP) ){
           }
           unsigned long szDestIP = pip->daddr;
           if( !IsAlexaDes(szDestIP) ){   //目的IP都与Alexa无关
               continue;
           }

           //除掉IP头和TCP头后的数据长度
           int predatalen=ntohs(pip->total_len)-40;

 

           ////正向发RST包
           //ptod->SendRaw(peth->eh_dst,peth->eh_src,
                        // htons(ntohs(pip->ident)+1),
                        // pip->saddr,ptcp->th_sport,
                        // pip->daddr,ptcp->th_dport,
                        // htonl( ntohl(ptcp->th_seq)+predatalen ),
                        // ptcp->th_ack);

           //反向发RST包
           ptod->SendRaw(peth->eh_src,peth->eh_dst,
                         htons(0),
                         pip->daddr,ptcp->th_dport,
                         pip->saddr,ptcp->th_sport,
                         ptcp->th_ack,
                         htonl( ntohl(ptcp->th_seq)+1 ));
        }

        return 0;
    }

 

    程序是通过侦听到TCP连接的握手信号,然后对TCP包进行分析后,发送一个握手应答信号给连接的发起端。当连接的发起端接收到连接应答信号后,会再发送一个应答信号,此时,连接发起端认为TCP连接己经建立,就开始发送数据。再用上一篇讲的办法来侦听数据,即可得到所需的IP包。因此,通过这种IP欺诈的办法,可以骗得所需的TCP数据包。

http://blog.sina.com.cn/s/blog_613e4fea0100l5tj.html

原创粉丝点击