npcap获取网卡包

npac获取网卡数据方法

下载lib库和SDK

#include<iostream>
#include<winsock2.h>
#include <conio.h>
#include "pcap.h"
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"packet.lib")
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#define LINE_LEN 16
#define IPTOSBUFFERS 12
using namespace std;
int i = 0;

/*帧首部*/
struct FrameHeader_t {
	byte DesMAC[6]; //目的Mac地址
	byte SrcMAC[6]; //源Mac地址
	WORD FrameType; //协议(帧)类型
};

/*IP首部*/
struct IPHeader_t {
#if defined(WORDS_BIENDIAN)
	byte Version : 4, HeaderLength : 4;
#else
	byte HeaderLength : 4, Version : 4;
#endif
	byte TOS;//服务类型
	WORD TotalLen; //总长度
	WORD ID;//标识
	WORD Flag_Segment;//标志字段
	byte TTL;//生存时间值
	byte Protocol;//协议类型,是TCP/IP体系中的网络层协议
	WORD Checksum;//检验和
	struct in_addr SrcIP;//源IP
	struct in_addr DstIP;//目的IP
};

/*IP协议首部处理函数*/
bool ip_protocol_packet_callback(const struct pcap_pkthdr* packet_header, const u_char* packet_data)
{
	struct IPHeader_t* IPHeader;
	IPHeader = (struct IPHeader_t*)(packet_data + 14);//MAC首部是14位的,加上14位得到IP协议首部
	printf("---------IP协议----------------------------------------------------------\n");
	printf("版本号:%d\n", IPHeader->Version);
	printf("首部长度:%d\n", IPHeader->HeaderLength);
	printf("服务类型:%d\n", IPHeader->TOS);
	printf("总长度:%d\n", ntohs(IPHeader->TotalLen));
	printf("标识:%d\n", ntohs(IPHeader->ID));
	printf("偏移:%d\n", (ntohs(IPHeader->Flag_Segment) & 0x1fff) * 8);
	printf("生存时间:%d\n", IPHeader->TTL);
	printf("协议类型:%d\n", IPHeader->Protocol);
	switch (IPHeader->Protocol)
	{
	case 1: printf("上层协议:ICMP协议\n"); break;
	case 2: printf("上层协议:IGMP协议\n"); break;
	case 6: printf("上层协议:TCP协议\n"); break;
	case 17: printf("上层协议:UDP协议\n"); break;
	default:printf("上层协议:Unknown\n"); break;
	}
	printf("检验和:%d\n", ntohs(IPHeader->Checksum));
	printf("源IP地址:%s\n", inet_ntoa(IPHeader->SrcIP));
	printf("目的地址:%s\n", inet_ntoa(IPHeader->DstIP));

	UINT32 value = (UINT32)(IPHeader->DstIP.S_un.S_addr);
	UINT32 b1, b2, b3, b4 = 0;
	b1 = value >> 24;
	b2 = (value & 0x00FFFFFF) >> 16;
	b3 = (value & 0x0000FFFF) >> 8;
	b4 = (value & 0x000000FF);
	if (b4 == 172 && b3 == 16 && b2 == 30 && b1 == 30)
	{
		return true;
	}
	return false;
}

/*帧首部处理函数*/
bool ethernet_protocol_packet_callback(const struct pcap_pkthdr* packet_header, const u_char* packet_data)
{
	struct FrameHeader_t* frameHeader;
	frameHeader = (struct FrameHeader_t*)packet_data;//获得数据包内容
	printf("---------以太网协议------------------------------------------------------\n");
	printf("以太网类型:0x%04x\n", ntohs(frameHeader->FrameType));
	switch (ntohs(frameHeader->FrameType))
	{
	case 0x0800: printf("上层协议:IP协议\n"); break;
	case 0x0806: printf("上层协议:ARP协议\n"); break;
	case 0x8035: printf("上层协议:RARP协议\n"); break;
	default:printf("上层协议:Unknown\n"); break;
	}

	u_char* macS = frameHeader->SrcMAC;
	u_char* macD = frameHeader->DesMAC;
	printf("MAC帧源地址:%02x:%02x:%02x:%02x:%02x:%02x\n", *macS, *(macS + 1), *(macS + 2), *(macS + 3), *(macS + 4), *(macS + 5));
	printf("MAC帧目的地址:%02x:%02x:%02x:%02x:%02x:%02x\n", *macD, *(macD + 1), *(macD + 2), *(macD + 3), *(macD + 4), *(macD + 5));

	if (ntohs(frameHeader->FrameType) == 0x0800)//继续分析IP协议
	{
		return ip_protocol_packet_callback(packet_header, packet_data);
	}

	return false;
}

/*线程参数结构体*/
struct parame
{
	pcap_t* adhandle;
	struct pcap_pkthdr* packet_header;
	const u_char* packet_data;
	int num;
};

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;

typedef struct
{
	UINT8  HdrLength : 4;
	UINT8  Version : 4;
	UINT8  TOS;
	UINT16 Length;
	UINT16 Id;
	UINT16 FragOff0;
	UINT8  TTL;
	UINT8  Protocol;
	UINT16 Checksum;
	UINT32 SrcAddr;
	UINT32 DstAddr;
} WINDIVERT_IPHDR, * PWINDIVERT_IPHDR;

typedef struct
{
	UINT16 SrcPort;
	UINT16 DstPort;
	UINT32 SeqNum;
	UINT32 AckNum;
	UINT16 Reserved1 : 4;
	UINT16 HdrLength : 4;
	UINT16 Fin : 1;
	UINT16 Syn : 1;
	UINT16 Rst : 1;
	UINT16 Psh : 1;
	UINT16 Ack : 1;
	UINT16 Urg : 1;
	UINT16 Reserved2 : 2;
	UINT16 Window;
	UINT16 Checksum;
	UINT16 UrgPtr;
} WINDIVERT_TCPHDR, * PWINDIVERT_TCPHDR;

//计算校验和
USHORT 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);

}

int SendRaw(pcap_t* handle, 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位序列号,应答号,网络顺序
{
	

	//构造以太网头
	ETH_HEADER eth;
	memcpy(eth.eh_dst, _dmac, 6);
	memcpy(eth.eh_src, _smac, 6);
	// IP协议
	eth.eh_type = htons(0x0800);

	//构造IP头
	WINDIVERT_IPHDR ip;
	ip.Version = 4 << 4 | sizeof(WINDIVERT_IPHDR) / 4;
	ip.TOS = 0;
	ip.Length = htons(sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_TCPHDR));
	ip.Id = _ident;
	ip.FragOff0 = htons(0x4000); //禁止分片
	ip.TTL = 128;
	ip.Protocol = IPPROTO_TCP;
	ip.Checksum = 0;
	ip.SrcAddr = _saddr;
	ip.DstAddr = _daddr;

	//构造TCP头
	WINDIVERT_TCPHDR tcp;
	tcp.SrcPort = _sport;
	tcp.DstPort = _dport;
	tcp.SeqNum = _seq;
	tcp.AckNum = _ack;
	tcp.HdrLength = sizeof(WINDIVERT_TCPHDR) / 4 << 4 | 0;

	tcp.Rst = 1;
	tcp.Window = htons(512);
	tcp.Checksum = 0;
	tcp.UrgPtr = 0;

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

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

	ip.Checksum = 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(handle, (BYTE*)szbuf, len);
	if (ret != 0) {
		bytes_out = -1;
	}
	else {
		bytes_out = len;
	}

	return bytes_out;

}

/*抓包线程*/
DWORD WINAPI Capturer(PVOID hWnd)
{
	int res;
	int packet_number = 0;
	struct tm* ltime;
	time_t local_tv_sec;
	char timestr[16];

	//将传入线程中的参数携带的数据取出
	parame* Packet = (parame*)hWnd;
	pcap_t* adhandle = Packet->adhandle;
	struct pcap_pkthdr* packet_header = Packet->packet_header;
	const u_char* packet_data = Packet->packet_data;
	int num = Packet->num;

	while ((res = pcap_next_ex(adhandle, &packet_header, &packet_data)) >= 0)
	{
		//接收数据包超时
		if (res == 0)
		{
			continue;
		}

		printf("=========================================================================\n");
		packet_number++;

		//将时间戳转化为可识别格式
		local_tv_sec = packet_header->ts.tv_sec;
		ltime = localtime(&local_tv_sec);
		strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);

		printf("捕获第%d个网络数据包\n", packet_number);;
		printf("捕获时间:%s\n", timestr);
		printf("数据包长度:%d\n", packet_header->len);
		printf("---------数据包内容------------------------------------------------------\n");

		//输出数据包的具体内容
		char temp[LINE_LEN + 1];
		for (int i = 0; i < packet_header->caplen; ++i)
		{
			printf("%.2x ", packet_data[i]);
			if (isgraph(packet_data[i]) || packet_data[i] == ' ')
				temp[i % LINE_LEN] = packet_data[i];
			else
				temp[i % LINE_LEN] = '.';

			if (i % LINE_LEN == 15)
			{
				temp[16] = '\0';
				printf("        ");
				printf("%s", temp);
				printf("\n");
				memset(temp, 0, LINE_LEN);
			}
		}
		printf("\n");

		//分析数据包
		bool ret = ethernet_protocol_packet_callback(packet_header, packet_data);
		ETH_HEADER* peth = (ETH_HEADER*)packet_data;
		WINDIVERT_IPHDR* pip = (WINDIVERT_IPHDR*)(packet_data + sizeof(ETH_HEADER));
		WINDIVERT_TCPHDR* ptcp = (WINDIVERT_TCPHDR*)(packet_data + sizeof(ETH_HEADER) + sizeof(WINDIVERT_IPHDR));
		printf("=========================================================================\n");

		if (ret)
		{
			// 实际测试不行
			////反向发RST包
			//SendRaw(adhandle,peth->eh_src, peth->eh_dst,
			//htons(0),
			//pip->DstAddr, ptcp->DstPort,
			//pip->SrcAddr, ptcp->SrcPort,
			//ptcp->Ack,
			//htonl(ntohl(ptcp->SeqNum) + 1));

			////正向发RST包
			// //除掉IP头和TCP头后的数据长度
			//int predatalen = ntohs(pip->Length) - 40;
			//SendRaw(adhandle, peth->eh_dst, peth->eh_src,
			//	htons(ntohs(pip->Id) + 1),
			//	pip->SrcAddr, ptcp->SrcPort,
			//	pip->DstAddr, ptcp->DstPort,
			//	htonl(ntohl(ptcp->SeqNum) + predatalen),
			//	ptcp->Ack);
		}	   

		//停止数据包捕捉
		if (_kbhit())
		{
			int ch = _getch();//使用_getch()函数获取按下的键值
			if (ch == 27)//当按下ESC时退出
			{
				cout << "\nThe Capturer has been closed..." << endl;
				return 0;
			}
		}

		//每1秒抓一次
		//Sleep(1000);
	}
	return 0;
}

/*IP格式转化函数*/
char* iptos(u_long in)
{
	static char output[IPTOSBUFFERS][3 * 4 + 3 + 1];
	static short which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
	u_char* p = (u_char*)&in;
	sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
	return output[which];
}

/*打印本机接口列表*/
void ifprint(pcap_if_t* d)
{
	pcap_addr_t* a;//表示接口地址指针
	printf("%d.%s\n", ++i, d->name);//打印网络接口设备的名字
	if (d->description)
	{
		printf("\tDescription:(%s)\n", d->description);//打印描述信息
	}
	else {
		printf("\t(No description available)\n");
	}
	printf("\tLoopback:%s\n", (d->flags & PCAP_IF_LOOPBACK) ? "yes" : "no");//是否是虚拟接口

	//获取该网络接口设备的IP地址信息
	for (a = d->addresses; a != NULL; a = a->next)
	{
		printf("\tAddress Family:#%d\n", a->addr->sa_family);
		switch (a->addr->sa_family)
		{
		case AF_INET://判断该地址是否IP地址
			printf("\tAddress Family Name:AF_INET\n");
			if (a->addr)//ip地址
			{
				printf("\tAddress:%s\n", iptos(((struct sockaddr_in*)a->addr)->sin_addr.s_addr));
			}
			if (a->netmask)//网络掩码
			{
				printf("\tNetmask:%s\n", iptos(((struct sockaddr_in*)a->netmask)->sin_addr.s_addr));
			}
			if (a->broadaddr)//广播地址
			{
				printf("\tBroadcast Address:%s\n", iptos(((struct sockaddr_in*)a->broadaddr)->sin_addr.s_addr));
			}
			if (a->dstaddr)//目的地址
			{
				printf("\tDestination Address:%s\n", iptos(((struct sockaddr_in*)a->dstaddr)->sin_addr.s_addr));
			}
			break;
		default:
			printf("\tAddressFamilyName:Unknown\n");
			break;
		}
	}
}

int main()
{
	pcap_if_t* alldevs;//指向设备链表首部的指针
	pcap_if_t* d;
	int num;
	pcap_t* adhandle;//定义打开设备的返回值
	char errbuf[PCAP_ERRBUF_SIZE];//错误信息缓冲区

	//取得列表
	if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING,//获取本机的接口设备
		NULL,//无需认证
		&alldevs,//指向设备列表首部
		errbuf//出错信息保存缓冲区
	) == -1)
	{
		printf("Error in pcap_findalldevs_ex!%s\n");//错误处理
		return -1;
	}

	//输出列表
	for (d = alldevs; d != NULL; d = d->next)
	{
		ifprint(d);
	}
	if (i == 0)
	{
		printf("\nNo interfaces found!\n");
		return -1;
	}

LOOP:
	printf("\nEnter the interface number (1-%d):", i);
	scanf("%d", &num);
	if (num <1 || num >i)
	{
		printf("\nInterface number out of range.\n");
		printf("Continue or Quit [c/q]:");
		char a;
		cin >> a;
		if (a == 'c' || a == 'C')
		{
			goto LOOP;
		}
		else if (a == 'q' || a == 'Q')
		{
			pcap_freealldevs(alldevs);
			return 0;
		}
	}

	//转到选择的设备
	for (d = alldevs, i = 0; i < num - 1; d = d->next, i++);
	//打开失败
	if ((adhandle = pcap_open_live(d->name, 65536, 1, 1000, errbuf)) == NULL)
	{
		fprintf(stderr, "\nUnable to open the adapter.\n");
		printf("Continue or Quit [c/q]:");
		char a;
		cin >> a;
		if (a == 'c' || a == 'C')
		{
			goto LOOP;
		}
		else if (a == 'q' || a == 'Q')
		{
			pcap_freealldevs(alldevs);
			return 0;
		}
	}
	//打开成功
	printf("\nlistening on %s...\n\n", d->description);
	//释放列表
	pcap_freealldevs(alldevs);

	//开始抓包,创建线程
	HANDLE m_capturer;
	struct pcap_pkthdr* packet_header = new pcap_pkthdr;
	const u_char* packet_data = new u_char;
	parame* m_pam = new parame;
	m_pam->adhandle = adhandle;
	m_pam->packet_header = packet_header;
	m_pam->packet_data = packet_data;
	m_pam->num = num;
	m_capturer = CreateThread(NULL, NULL, &Capturer, (PVOID*)m_pam, 0, NULL);
	CloseHandle(m_capturer);
	while (1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值