• 热门专题

VC++基于winpcap实现ARP攻击禁止访问相关网站

作者:yincheng01@CSDN  发布日期:2012-11-15 10:00:33
Tag标签:VC++  winpcap  ARP攻击  
  • 地址解析协议(Address Resolution Protocol,ARP)是在仅知道主机的IP地址时确  地址解析协议定其物理地址的一种协议。因IPv4和以太网的广泛应用,其主要用作将IP地址翻译为以太网的MAC地址,但其也能在ATM( 异步传输模式)和FDDIIP(Fiber Distributed Data Interface 光纤分布式数据接口)网络中使用。从IP地址到物理地址的映射有两种方式:表格方式和非表格方式。ARP具体说来就是将网络层(IP层,也就是相当于OSI的第三层)地址解析为数据连接层(MAC层,也就是相当于OSI的第二层)的MAC地址。
    1. 什么是ARP?
      ARP (Address Resolution Protocol) 是个地址解析协议。最直白的说法是:在IP-以太网中,当一个上层协议要发包时,有了节点的IP地址,ARP就能提供该节点的MAC地址。
      2. 为什么要有ARP?
      OSI 模式把网络工作分为七层,彼此不直接打交道,只通过接口(layer interface). IP地址在第三层, MAC地址在第二层。协议在发送数据包时,得先封装第三层(IP地址),第二层(MAC地址)的报头, 但协议只知道目的节点的IP地址,不知道其MAC地址,又不能跨第二、三层,所以得用ARP的服务。
      3. 什么是ARP
      cache? ARP cache 是个用来储存(IP, MAC)地址的缓冲区。当ARP被询问一个已知IP地址节点的MAC地址时,先在ARP cache 查看,若存在,就直接返回MAC地址,若不存在,才发送ARP request向局域网查询。
      4. ARP 有什么命令行?
      常用的包括:(格式因操作系统、路由器而异,但作用类似)- 显示ARP cache: show arp; arp -a - 清除ARP cache: arp -d;clear arp。
     在TCP/IP协议中,A给B发送IP包,在报头中需要填写B的IP为目标地址,但这个IP包在以太网上传输的时候,还需要进行一次以太包的封装,在这个以太包中,目标地址就是B的MAC地址.
      计算机A是如何得知B的MAC地址的呢?解决问题的关键就在于ARP协议。
      在A不知道B的MAC地址的情况下,A就广播一个ARP请求包,请求包中填有B的IP(192.168.1.2),以太网中的所有计算机都会接收这个请求,而正常的情况下只有B会给出ARP应答包,包中就填充上了B的MAC地址,并回复给A。
      A得到ARP应答后,将B的MAC地址放入本机缓存,便于下次使用。
      本机MAC缓存是有生存期的,生存期结束后,将再次重复上面的过程。
      ARP协议并不只在发送了ARP请求才接收ARP应答。当计算机接收到ARP应答数据包的时候,就会对本地的ARP缓存进行更新,将应答中的IP和MAC地址存储在ARP缓存中。因此,当局域网中的某台机器B向A发送一个自己伪造的ARP应答,而如果这个应答是B冒充C伪造来的,即IP地址为C的IP,而MAC地址是伪造的,则当A接收到B伪造的ARP应答后,就会更新本地的ARP缓存,这样在A看来C的IP地址没有变,而它的MAC地址已经不是原来那个了。由于局域网的网络流通不是根据IP地址进行,而是按照MAC地址进行传输。所以,那个伪造出来的MAC地址在A上被改变成一个不存在的MAC地址,这样就会造成网络不通,导致A不能Ping通C!这就是一个简单的ARP欺骗。
     在网络执法官中,要想限制某台机器上网,只要点击“网卡”菜单中的“权限”,选择指定的网卡号或在用户列表中点击该网卡所在行,从右键菜单中选择“权限”,在弹出的对话框中即可限制该用户的权限。对于未登记网卡,可以这样限定其上线:只要设定好所有已知用户(登记)后,将网卡的默认权限改为禁止上线即可阻止所有未知的网卡上线。使用这两个功能就可限制用户上网。其原理是通过ARP欺骗发给被攻击的电脑一个假的网关IP地址对应的MAC,使其找不到网关真正的MAC地址,这样就可以禁止其上网。
    ARP欺骗可以导致目标计算机与网关通信失败;


     

    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <pcap.h>
    #include <remote-ext.h>
    #include "CheckSum.h"
    #include "Aho-Corasick.h"
    
    using namespace std;
    #pragma comment(lib,"wpcap.lib")
    #pragma comment(lib,"ws2_32.lib")
    
    bool cut = false;
    
    pcap_t * adapter;
    //检查数据包,进行模式匹配,并阻断非法连接
    void CheckPacket(const u_char *pkt_data);
    
    //winpcap中pcap_loop()函数的回调函数--当网卡捕获到指定数据包时调用
    void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
    
    //保存缓存数据到文件
    bool SaveToFile(char filename[], const void *data,const unsigned int size);
    
    //保存网页数据到文件
    void SavePacket(const u_char *pkt_data);
    //构造发向服务器的RST包
    void RSTPacketToServer(const u_char *old_pkt,u_char *pkt);
    //构造发向客户端的RST包
    void RSTPacketToClient(const u_char *old_pkt,u_char *pkt);
    int _tmain(int argc, _TCHAR* argv[])
    {
    	prec();
    	pcap_if_t *alldevs;
        pcap_if_t *d;
        char errbuf[PCAP_ERRBUF_SIZE];
    	int num_adapter=0;
    
    	unsigned int netmask;
    	char packet_filter[] = "tcp port 80";
    	struct bpf_program fcode;
        /* Retrieve the device list from the local machine */
        
        if(pcap_findalldevs(&alldevs,errbuf) == -1)
    	{
            fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf);
            exit(1);
        }
        
        /* Print the list */
        for(d= alldevs; d != NULL; d= d->next)
        {
            printf("%d. %s\n", ++num_adapter, d->name);
    		pcap_addr *addrs = d->addresses;
    		while(addrs != NULL)
    		{
    			sockaddr_in *addr = (sockaddr_in *)addrs->addr;
    			char *address = inet_ntoa(addr->sin_addr);
    			printf("%s\n",address);
    			addrs = addrs->next;
    		}
            if (d->description)
                printf(" (%s)\n", d->description);
            else
                printf(" (No description available)\n");
        }
        
        if (num_adapter == 0)
        {
            printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
    		pcap_freealldevs(alldevs);
            return -1;
        }
    	cout<<"Enter the adapter's number!\n";
    	int num = 0;
    	cin >> num;
    	if(num > num_adapter || num < 1)
    	{
    		cout<<"\nInterface number out of range.\n";
    		pcap_freealldevs(alldevs);
    		return -1;
    	}
    
    	d = alldevs;
    	for(int i = 0;i < num - 1;i++)
    	{
    		d = d->next;
    	}
    // 打开选择的网络接口
    	adapter = pcap_open_live(d->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1,errbuf);
    	if(adapter==NULL)	
    	{
    		cout <<"\nUnable to open the adapter. "<<d->name<<" is not supported by WinPcap\n";
    		pcap_freealldevs(alldevs);
    		return -1;
    	}
    
    
    	 /* Check the link layer. We support only Ethernet for simplicity */
     if (pcap_datalink(adapter) != DLT_EN10MB)
     {
      cout<<"is program works only on Ethernet networks.\n";
      /* Free the devices list */
      pcap_freealldevs(alldevs);
      return -1;
     }
    
    	if (d->addresses != NULL)
            /* Retrieve the mask of the first address of the interface */
            netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
        else
            /* If the interface is without an address we suppose to be in a C class network */
            netmask=0xffffff; 
    
    
        //compile the filter
        if (pcap_compile(adapter, &fcode, packet_filter, 1, netmask) < 0)
        {
            cout<<"\nUnable to compile the packet filter. Check the syntax.\n";
            /* Free the device list */
            pcap_freealldevs(alldevs);
            return -1;
        }
        
        //set the filter
        if (pcap_setfilter(adapter, &fcode) < 0)
        {
            cout<<"\nError setting the filter.\n";
            /* Free the device list */
            pcap_freealldevs(alldevs);
            return -1;
        }
    
        /* We don't need any more the device list. Free it */
        pcap_freealldevs(alldevs);
    
    	cout <<"Listening....."<<endl;
    
    	if(pcap_loop(adapter,0,packet_handler,NULL) == -2)
    	{
    		cout<<"\nTotal:\n";
    		pcap_stat * state = new pcap_stat();
    		pcap_stats(adapter,state);
    		cout <<"ps_drop:"<< state->ps_drop<<"\n";
    		cout <<"ps_ifdrop:"<< state->ps_ifdrop<<"\n";
    		cout <<"ps_recv:"<< state->ps_recv<<"\n";
    	}
    	else
    	{
    		cout << "something wrong when caputer the network's packet!\n";
    		return -1;
    	}
    	pcap_close(adapter);
    	system("pause");
    	return 0;
    
    }
    
    
    void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
    {
    	//保存数据包到文件
    	SavePacket(pkt_data);
    	CheckPacket(pkt_data);
    }
    
    void SavePacket(const u_char *pkt_data)
    {
     //获得以太网头 ip数据包头 tcp头位置
        Ip_Header* ipHeader;
    	Tcp_Header* tcpHeader;
    	unsigned int ipHeaderLen;
    	unsigned short sport, dport;
    
    		//Ethernet frame 
    	Ether_Header* eh = (Ether_Header*)pkt_data;
    	//retrieve the position of the ip header 
    	ipHeader = (Ip_Header*)(pkt_data + 14);        //length of ethernet header 
    	//retrieve the position of the tcp header
    	ipHeaderLen = (ipHeader->iphVerLen & 0xf) * 4; //length of ip header
    	tcpHeader = (Tcp_Header*)(pkt_data + 14 + ipHeaderLen);
    
    	// 将端口信息从网络型转变为主机顺序
    	sport = ntohs(tcpHeader->sourcePort);
    	dport = ntohs(tcpHeader->destinationPort);
    
    	UCHAR Flags = tcpHeader->flags;
    
    	
    	//得到Tcp数据部分的位置
    	unsigned int TcpHeadLen = ((tcpHeader->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移
    	unsigned char* HttpData = (unsigned char*)tcpHeader+TcpHeadLen;
    
    	unsigned int IpLength = ntohs(ipHeader->ipLength);
    	unsigned int HttpDataLen = IpLength - ipHeaderLen - TcpHeadLen;
    
    	if(HttpDataLen != 0)
    	{
    		//保存
    		SaveToFile("cap.log",HttpData,HttpDataLen);
    	}
    
    }
    
    //
    // 把数据写入文件
    // 入口参数: filename ==> 数据文件名 data ==> 指向数据块的空指针 size ==> 数据块大小
    // 返回值类型 bool
    //
    
    bool SaveToFile(char filename[], const void *data,const unsigned int size)
    {
    	ofstream onput;
    	onput.open(filename,ios::out|ios.binary|ios::ate|ios::app);
    	if(onput.fail())
    		return false;
    	onput.write((char *)data,size);
    	onput.close();
    	return true;
    }
    
    
    //构造R发送给服务器端的RST包
    //输入:old_pkt - 收到的原数据包 pkt - 构造出来的RST包
    void RSTPacketToServer(const u_char *old_pkt,u_char *pkt)
    {
    	Ip_Header *old_ih,*ih;
    	Tcp_Header *old_th,*th;
    	Ether_Header *old_eh,*eh;
    	unsigned int ipHeaderLen;
    	
    	memcpy (pkt,old_pkt,40+14);
    
    	old_eh = (Ether_Header *)old_pkt;
    	eh = (Ether_Header *)pkt;
    
    	memcpy(old_eh->dhost,eh->shost,sizeof(eh->shost));
    	memcpy(old_eh->shost,eh->dhost,sizeof(eh->dhost));
    
    	/* retrieve the position of the ip header */
    	old_ih = (Ip_Header*)(old_pkt + 14);  /* length of ethernet header */	
    	ih = (Ip_Header*)(pkt + 14);
    	
    
    	memcpy(ih,old_ih,sizeof(Ip_Header));  //ip头
    	ih->ipSource = old_ih->ipDestination;
    	ih->ipDestination = old_ih->ipSource;
    	ih->ipLength = htons(40);
    	
    	
    	/* retrieve the position of the udp header */
    	ipHeaderLen = (old_ih->iphVerLen & 0xf) * 4;
    	old_th = (Tcp_Header*)(old_pkt + 14 + ipHeaderLen);
    	th = (Tcp_Header*)(pkt + 14 + ipHeaderLen);
    
    	th->destinationPort = old_th->sourcePort;
    	th->sourcePort = old_th->destinationPort;
    	th->flags = 0x04; //rst
    	th->sequenceNumber = htonl(ntohl(old_th->acknowledgeNumber));
    	
    
    	unsigned int TcpHeadLen = ((th->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移
    	unsigned char* HttpData = (unsigned char*)th+TcpHeadLen;	
    
    	int lentcp = ntohs(ih->ipLength) - (sizeof(Ip_Header) + sizeof(Tcp_Header));
    
    	th->acknowledgeNumber=0;
    	ih->ipChecksum = 0;
    	th->checksum = 0;
    	ih->ipChecksum = checksum((USHORT *)ih, sizeof(Ip_Header));
    	ComputeTcpPseudoHeaderChecksum(ih, th, (char *)HttpData, lentcp);
    }
    
    
    //构造R发送给客户端的RST包
    //输入:old_pkt - 收到的原数据包 pkt - 构造出来的RST包
    void RSTPacketToClient(const u_char *old_pkt,u_char *pkt)
    {
    	Ip_Header *old_ih,*ih;
    	Tcp_Header *old_th,*th;
    	Ether_Header *old_eh,*eh;
    	unsigned int ipHeaderLen;
    	
    	memcpy (pkt,old_pkt,40+14);
    
    	old_eh = (Ether_Header *)old_pkt;
    	eh = (Ether_Header *)pkt;
    
    	/* retrieve the position of the ip header */
    	old_ih = (Ip_Header*)(old_pkt + 14);  /* length of ethernet header */	
    	ih = (Ip_Header*)(pkt + 14);
    
    	memcpy(ih,old_ih,sizeof(Ip_Header));  //ip头
    	ih->ipLength = htons(40);
    
    	
    	/* retrieve the position of the udp header */
    	ipHeaderLen = (old_ih->iphVerLen & 0xf) * 4;
    	old_th = (Tcp_Header*)(old_pkt + 14 + ipHeaderLen);
    	th = (Tcp_Header*)(pkt + 14 + ipHeaderLen);
    
    	th->flags =4;  //rst
    	
    	
    
    	unsigned int TcpHeadLen = ((th->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移
    	unsigned char* HttpData = (unsigned char*)th+TcpHeadLen;	
    
    	int lentcp = ntohs(ih->ipLength) - (sizeof(Ip_Header) + sizeof(Tcp_Header));
    	th->sequenceNumber = htonl(ntohl(old_th->sequenceNumber) + lentcp);
    	if(old_th->flags & 0x02) 
    		th->sequenceNumber = htonl(ntohl(old_th->sequenceNumber) + 1);
    	th->acknowledgeNumber = 0;
    
    	ih->ipChecksum = 0;
    	th->checksum = 0;
    	ih->ipChecksum = checksum((USHORT *)ih, sizeof(Ip_Header));
    	ComputeTcpPseudoHeaderChecksum(ih, th, (char *)HttpData, lentcp);
    
    }
    
    
    void CheckPacket(const u_char *pkt_data)
    {
    	//获得以太网头 ip数据包头 tcp头位置
        Ip_Header* ipHeader;
    	Tcp_Header* tcpHeader;
    	unsigned int ipHeaderLen;
    
    	//Ethernet frame 
    	Ether_Header* eh = (Ether_Header*)pkt_data;
    	//retrieve the position of the ip header 
    	ipHeader = (Ip_Header*)(pkt_data + 14);        //length of ethernet header 
    	//retrieve the position of the tcp header
    	ipHeaderLen = (ipHeader->iphVerLen & 0xf) * 4; //length of ip header
    	tcpHeader = (Tcp_Header*)(pkt_data + 14 + ipHeaderLen);
    
    	//得到Tcp数据部分的位置
    	unsigned int TcpHeadLen = ((tcpHeader->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移
    	unsigned char* HttpData = (unsigned char*)tcpHeader+TcpHeadLen;
    
    	unsigned int IpLength = ntohs(ipHeader->ipLength);
    	int HttpDataLen = (int)(IpLength - ipHeaderLen - TcpHeadLen);
    	if(cut)
    	{
    		if(tcpHeader->flags & 0x02)
    		{
    			u_char * send_mdata = new u_char[54];
    				RSTPacketToServer(pkt_data,send_mdata);
    				pcap_sendpacket(adapter,send_mdata,54);
    				return;
    		}
    	}
    
    	if(HttpDataLen > 0)
    	{
    			
    		for (int i = 0 ; i < HttpDataLen; i++)
    		{
    			if (AC(*(HttpData+i),false))	//ac算法
    			{
    				printf("---------------------------------------------------\n");
    			    printf("关键字位置:%d\n",i);
    				cut = true;    //
    				u_char * send_data = new u_char[54];
    
    
    
    				//发送rst包给客户端
    
    			   RSTPacketToClient(pkt_data,send_data);
    			   pcap_sendpacket(adapter,send_data,54);
    				//发送rst包给服务端
    				RSTPacketToServer(pkt_data,send_data);
    				 pcap_sendpacket(adapter,send_data,54);
    				cout<<"Finded!"<<endl;
    			}
    		}
    	}	
    
    }

     

延伸阅读:

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规