赞
踩
Npcap是一款用于Windows操作系统的网络数据包捕获库和驱动程序。它是WinPcap的改进版本,旨在提供更强大、更灵活的网络数据包捕获功能。
Npcap支持Windows 7及更高版本,并提供了一组API供开发人员使用。使用Npcap,开发人员可以编写自定义的网络监控和分析工具,实现对网络数据包的捕获、分析和处理。它可以在本地网络接口上捕获数据包,包括以太网、Wi-Fi、虚拟网络适配器等。
Npcap 是Nmap项目的网络包抓取库在Windows下的版本,其调用接口完全遵循WinPcap规范.
- #include <WinSock2.h>
- #include <Windows.h>
- #include <pcap.h>
-
- #pragma comment(lib, "packet.lib")
- #pragma comment(lib, "wpcap.lib")
-
- int enumAdapters()
- {
- pcap_if_t *allAdapters; // 所有网卡设备保存
- pcap_if_t *ptr; // 用于遍历的指针
- int index = 0;
- char errbuf[PCAP_ERRBUF_SIZE];
-
- /* 获取本地机器设备列表 */
- if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &allAdapters, errbuf) != -1)
- {
- /* 打印网卡信息列表 */
- for (ptr = allAdapters; ptr != NULL; ptr = ptr->next)
- {
- // printf("网卡地址: %x 网卡ID: %s \n", ptr->addresses, ptr->name);
- ++index;
- if (ptr->description)
- printf("ID: %d --> Name: %s \n", index,ptr->description);
- }
- }
-
- /* 不再需要设备列表了,释放它 */
- pcap_freealldevs(allAdapters);
- return index;
- }
-
- int main(int argc,char *argv[])
- {
- int network = enumAdapters();
- printf("网卡数量: %d \n", network);
- system("Pause");
- }
接着我们通过获取到的的网卡对应的值,填入MonitorAdapter中就可以实现监控该网卡的原始数据包,配合下方的解析函数进行各种解析.
- #include <WinSock2.h>
- #include <Windows.h>
- #include <pcap.h>
-
- #pragma comment(lib, "packet.lib")
- #pragma comment(lib, "wpcap.lib")
-
- void MonitorAdapter(int nChoose)
- {
- pcap_if_t *adapters;
- char errbuf[PCAP_ERRBUF_SIZE];
-
- if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &adapters, errbuf) != -1)
- {
- // 找到指定的网卡
- for (int x = 0; x < nChoose - 1; ++x)
- adapters = adapters->next;
-
- char errorBuf[PCAP_ERRBUF_SIZE];
-
- // PCAP_OPENFLAG_PROMISCUOUS = 网卡设置为混杂模式
- // 1000 => 1000毫秒如果读不到数据直接返回超时
- pcap_t * handle = pcap_open(adapters->name, 65534, 1, PCAP_OPENFLAG_PROMISCUOUS, 0, 0);
-
- if (adapters == NULL)
- return;
-
- // printf("开始侦听: % \n", adapters->description);
- pcap_pkthdr *Packet_Header; // 数据包头
- const u_char * Packet_Data; // 数据本身
- int retValue;
- while ((retValue = pcap_next_ex(handle, &Packet_Header, &Packet_Data)) >= 0)
- {
- if (retValue == 0)
- continue;
- // printf("侦听长度: %d \n", Packet_Header->len);
- PrintEtherHeader(Packet_Data);
- }
- }
- }
-
- int main(int argc,char *argv[])
- {
- MonitorAdapter(3);
- }
- #define hcons(A) (((WORD)(A)&0xFF00)>>8) | (((WORD)(A)&0x00FF)<<8)
-
- // 输出 数据链路层
- void PrintEtherHeader(const u_char * packetData)
- {
- typedef struct ether_header {
- u_char ether_dhost[6]; // 目标地址
- u_char ether_shost[6]; // 源地址
- u_short ether_type; // 以太网类型
- } ether_header;
-
- struct ether_header * eth_protocol;
- eth_protocol = (struct ether_header *)packetData;
-
- u_short ether_type = ntohs(eth_protocol->ether_type); // 以太网类型
- u_char *ether_src = eth_protocol->ether_shost; // 以太网原始MAC地址
- u_char *ether_dst = eth_protocol->ether_dhost; // 以太网目标MAC地址
-
- printf("类型: 0x%x \t", ether_type);
- printf("原MAC地址: %02X:%02X:%02X:%02X:%02X:%02X \t",
- ether_src[0], ether_src[1], ether_src[2], ether_src[3], ether_src[4], ether_src[5]);
- printf("目标MAC地址: %02X:%02X:%02X:%02X:%02X:%02X \n",
- ether_dst[0], ether_dst[1], ether_dst[2], ether_dst[3], ether_dst[4], ether_dst[5]);
- }
- void PrintIPHeader(const u_char * packetData)
- {
- typedef struct ip_header
- {
- char version : 4;
- char headerlength : 4;
- char cTOS;
- unsigned short totla_length;
- unsigned short identification;
- unsigned short flags_offset;
- char time_to_live;
- char Protocol;
- unsigned short check_sum;
- unsigned int SrcAddr;
- unsigned int DstAddr;
- }ip_header;
-
- struct ip_header *ip_protocol;
-
- // +14 跳过数据链路层
- ip_protocol = (struct ip_header *)(packetData + 14);
- SOCKADDR_IN Src_Addr, Dst_Addr = { 0 };
-
- u_short check_sum = ntohs(ip_protocol->check_sum);
- int ttl = ip_protocol->time_to_live;
- int proto = ip_protocol->Protocol;
-
- Src_Addr.sin_addr.s_addr = ip_protocol->SrcAddr;
- Dst_Addr.sin_addr.s_addr = ip_protocol->DstAddr;
-
- printf("源地址: %15s --> ", inet_ntoa(Src_Addr.sin_addr));
- printf("目标地址: %15s --> ", inet_ntoa(Dst_Addr.sin_addr));
-
- printf("校验和: %5X --> TTL: %4d --> 协议类型: ", check_sum, ttl);
- switch (ip_protocol->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;
- case 89: printf("OSPF \n"); break;
- default: printf("None \n"); break;
- }
- }
- void PrintTCPHeader(const unsigned char * packetData)
- {
- typedef struct tcp_header
- {
- short SourPort; // 源端口号16bit
- short DestPort; // 目的端口号16bit
- unsigned int SequNum; // 序列号32bit
- unsigned int AcknowledgeNum; // 确认号32bit
- unsigned char reserved : 4, offset : 4; // 预留偏移
-
- unsigned char flags; // 标志
-
- short WindowSize; // 窗口大小16bit
- short CheckSum; // 检验和16bit
- short surgentPointer; // 紧急数据偏移量16bit
- }tcp_header;
-
- struct tcp_header *tcp_protocol;
- // +14 跳过数据链路层 +20 跳过IP层
- tcp_protocol = (struct tcp_header *)(packetData + 14 + 20);
-
- u_short sport = ntohs(tcp_protocol->SourPort);
- u_short dport = ntohs(tcp_protocol->DestPort);
- int window = tcp_protocol->WindowSize;
- int flags = tcp_protocol->flags;
-
- printf("源端口: %6d --> 目标端口: %6d --> 窗口大小: %7d --> 标志: (%d)",
- sport, dport, window, flags);
-
- if (flags & 0x08) printf("PSH 数据传输\n");
- else if (flags & 0x10) printf("ACK 响应\n");
- else if (flags & 0x02) printf("SYN 建立连接\n");
- else if (flags & 0x20) printf("URG \n");
- else if (flags & 0x01) printf("FIN 关闭连接\n");
- else if (flags & 0x04) printf("RST 连接重置\n");
- else printf("None 未知\n");
- }
- void PrintUDPHeader(const unsigned char * packetData)
- {
- typedef struct udp_header {
- uint32_t sport; // 源端口
- uint32_t dport; // 目标端口
- uint8_t zero; // 保留位
- uint8_t proto; // 协议标识
- uint16_t datalen; // UDP数据长度
- }udp_header;
-
- struct udp_header *udp_protocol;
- // +14 跳过数据链路层 +20 跳过IP层
- udp_protocol = (struct udp_header *)(packetData + 14 + 20);
-
- u_short sport = ntohs(udp_protocol->sport);
- u_short dport = ntohs(udp_protocol->dport);
- u_short datalen = ntohs(udp_protocol->datalen);
-
- printf("源端口: %5d --> 目标端口: %5d --> 大小: %5d \n", sport, dport,datalen);
- }
- void PrintICMPHeader(const unsigned char * packetData)
- {
- typedef struct icmp_header {
- uint8_t type; // ICMP类型
- uint8_t code; // 代码
- uint16_t checksum; // 校验和
- uint16_t identification; // 标识
- uint16_t sequence; // 序列号
- uint32_t init_time; // 发起时间戳
- uint16_t recv_time; // 接受时间戳
- uint16_t send_time; // 传输时间戳
- }icmp_header;
-
-
- struct icmp_header *icmp_protocol;
- // +14 跳过数据链路层 +20 跳过IP层
- icmp_protocol = (struct icmp_header *)(packetData + 14 + 20);
-
- int type = icmp_protocol->type;
- int init_time = icmp_protocol->init_time;
- int send_time = icmp_protocol->send_time;
- int recv_time = icmp_protocol->recv_time;
- if (type == 8)
- {
- printf("发起时间戳: %d --> 传输时间戳: %d --> 接收时间戳: %d 方向: ",
- init_time, send_time, recv_time);
-
- switch (type)
- {
- case 0: printf("回显应答报文 \n"); break;
- case 8: printf("回显请求报文 \n"); break;
- default:break;
- }
- }
- }
通过使用Npcap实现发送一个ARP广播数据包,这里需要先构建数据包的结构,然后在发送出去.
- #include <stdio.h>
- #include <winsock2.h>
- #include <Windows.h>
- #include <pcap.h>
-
- #pragma comment(lib, "packet.lib")
- #pragma comment(lib, "wpcap.lib")
- #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
- {
- 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;
- };
-
- // 获取到指定网卡的句柄
- pcap_t * OpenPcap(int nChoose)
- {
- pcap_t *pcap_handle; //打开网络适配器,捕捉实例,是pcap_open返回的对象
- pcap_if_t *alldevs;
- char errbuf[PCAP_ERRBUF_SIZE]; //错误缓冲区,大小为256
-
- // 获取到所有设备列表
- if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
- exit(0);
- // 找到指定的网卡设备
- for (int x = 0; x < nChoose - 1; ++x)
- alldevs = alldevs->next;
-
- if ((pcap_handle = pcap_open(alldevs->name, // 设备名
- 65536, // 每个包长度
- PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
- 1000, // 读取超时时间
- NULL, // 远程机器验证
- errbuf // 错误缓冲池
- )) == NULL)
- {
- pcap_freealldevs(alldevs);
- exit(0);
- }
- return pcap_handle;
- }
-
- int main(int argc, char *argv[])
- {
- pcap_t *handle; // 打开网络适配器
- EthernetHeader eh; // 定义以太网包头
- ArpHeader ah; // 定义ARP包头
-
- unsigned char sendbuf[42]; // arp包结构大小42个字节
- unsigned char src_mac[6] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff };
- unsigned char src_ip[4] = { 0x01, 0x02, 0x03, 0x04 };
-
- handle = OpenPcap(3); // 拿到第三个网卡的句柄
-
- // 开始填充ARP包
- memset(eh.DestMAC, 0xff, 6); // 以太网首部目的MAC地址,全为广播地址
- memcpy(eh.SourMAC, src_mac, 6); // 以太网首部源MAC地址
- memcpy(ah.smac, src_mac, 6); // ARP字段源MAC地址
- memset(ah.dmac, 0xff, 6); // ARP字段目的MAC地址
- memcpy(ah.sip, src_ip, 4); // ARP字段源IP地址
- memset(ah.dip, 0x05, 4); // ARP字段目的IP地址
-
- // 赋值MAC地址
- 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)); // 首先把eh以太网结构填充上
- memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah)); // 接着在eh后面填充arp结构
-
- // 发送数据包
- if (pcap_sendpacket(handle, sendbuf, 42) == 0)
- {
- printf("发送ARP数据包成功! \n");
- }
-
- system("pause");
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。