当前位置:   article > 正文

C/C++ Npcap包实现数据嗅探

npcap

Npcap是一款用于Windows操作系统的网络数据包捕获库和驱动程序。它是WinPcap的改进版本,旨在提供更强大、更灵活的网络数据包捕获功能。

Npcap支持Windows 7及更高版本,并提供了一组API供开发人员使用。使用Npcap,开发人员可以编写自定义的网络监控和分析工具,实现对网络数据包的捕获、分析和处理。它可以在本地网络接口上捕获数据包,包括以太网、Wi-Fi、虚拟网络适配器等。

Npcap 开发包解析协议

Npcap 是Nmap项目的网络包抓取库在Windows下的版本,其调用接口完全遵循WinPcap规范.

  1. #include <WinSock2.h>
  2. #include <Windows.h>
  3. #include <pcap.h>
  4. #pragma comment(lib, "packet.lib")
  5. #pragma comment(lib, "wpcap.lib")
  6. int enumAdapters()
  7. {
  8. pcap_if_t *allAdapters; // 所有网卡设备保存
  9. pcap_if_t *ptr; // 用于遍历的指针
  10. int index = 0;
  11. char errbuf[PCAP_ERRBUF_SIZE];
  12. /* 获取本地机器设备列表 */
  13. if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &allAdapters, errbuf) != -1)
  14. {
  15. /* 打印网卡信息列表 */
  16. for (ptr = allAdapters; ptr != NULL; ptr = ptr->next)
  17. {
  18. // printf("网卡地址: %x 网卡ID: %s \n", ptr->addresses, ptr->name);
  19. ++index;
  20. if (ptr->description)
  21. printf("ID: %d --> Name: %s \n", index,ptr->description);
  22. }
  23. }
  24. /* 不再需要设备列表了,释放它 */
  25. pcap_freealldevs(allAdapters);
  26. return index;
  27. }
  28. int main(int argc,char *argv[])
  29. {
  30. int network = enumAdapters();
  31. printf("网卡数量: %d \n", network);
  32. system("Pause");
  33. }

接着我们通过获取到的的网卡对应的值,填入MonitorAdapter中就可以实现监控该网卡的原始数据包,配合下方的解析函数进行各种解析.

  1. #include <WinSock2.h>
  2. #include <Windows.h>
  3. #include <pcap.h>
  4. #pragma comment(lib, "packet.lib")
  5. #pragma comment(lib, "wpcap.lib")
  6. void MonitorAdapter(int nChoose)
  7. {
  8. pcap_if_t *adapters;
  9. char errbuf[PCAP_ERRBUF_SIZE];
  10. if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &adapters, errbuf) != -1)
  11. {
  12. // 找到指定的网卡
  13. for (int x = 0; x < nChoose - 1; ++x)
  14. adapters = adapters->next;
  15. char errorBuf[PCAP_ERRBUF_SIZE];
  16. // PCAP_OPENFLAG_PROMISCUOUS = 网卡设置为混杂模式
  17. // 1000 => 1000毫秒如果读不到数据直接返回超时
  18. pcap_t * handle = pcap_open(adapters->name, 65534, 1, PCAP_OPENFLAG_PROMISCUOUS, 0, 0);
  19. if (adapters == NULL)
  20. return;
  21. // printf("开始侦听: % \n", adapters->description);
  22. pcap_pkthdr *Packet_Header; // 数据包头
  23. const u_char * Packet_Data; // 数据本身
  24. int retValue;
  25. while ((retValue = pcap_next_ex(handle, &Packet_Header, &Packet_Data)) >= 0)
  26. {
  27. if (retValue == 0)
  28. continue;
  29. // printf("侦听长度: %d \n", Packet_Header->len);
  30. PrintEtherHeader(Packet_Data);
  31. }
  32. }
  33. }
  34. int main(int argc,char *argv[])
  35. {
  36. MonitorAdapter(3);
  37. }

解析数据链路层

  1. #define hcons(A) (((WORD)(A)&0xFF00)>>8) | (((WORD)(A)&0x00FF)<<8)
  2. // 输出 数据链路层
  3. void PrintEtherHeader(const u_char * packetData)
  4. {
  5. typedef struct ether_header {
  6. u_char ether_dhost[6]; // 目标地址
  7. u_char ether_shost[6]; // 源地址
  8. u_short ether_type; // 以太网类型
  9. } ether_header;
  10. struct ether_header * eth_protocol;
  11. eth_protocol = (struct ether_header *)packetData;
  12. u_short ether_type = ntohs(eth_protocol->ether_type); // 以太网类型
  13. u_char *ether_src = eth_protocol->ether_shost; // 以太网原始MAC地址
  14. u_char *ether_dst = eth_protocol->ether_dhost; // 以太网目标MAC地址
  15. printf("类型: 0x%x \t", ether_type);
  16. printf("原MAC地址: %02X:%02X:%02X:%02X:%02X:%02X \t",
  17. ether_src[0], ether_src[1], ether_src[2], ether_src[3], ether_src[4], ether_src[5]);
  18. printf("目标MAC地址: %02X:%02X:%02X:%02X:%02X:%02X \n",
  19. ether_dst[0], ether_dst[1], ether_dst[2], ether_dst[3], ether_dst[4], ether_dst[5]);
  20. }

解析IP层数据包

  1. void PrintIPHeader(const u_char * packetData)
  2. {
  3. typedef struct ip_header
  4. {
  5. char version : 4;
  6. char headerlength : 4;
  7. char cTOS;
  8. unsigned short totla_length;
  9. unsigned short identification;
  10. unsigned short flags_offset;
  11. char time_to_live;
  12. char Protocol;
  13. unsigned short check_sum;
  14. unsigned int SrcAddr;
  15. unsigned int DstAddr;
  16. }ip_header;
  17. struct ip_header *ip_protocol;
  18. // +14 跳过数据链路层
  19. ip_protocol = (struct ip_header *)(packetData + 14);
  20. SOCKADDR_IN Src_Addr, Dst_Addr = { 0 };
  21. u_short check_sum = ntohs(ip_protocol->check_sum);
  22. int ttl = ip_protocol->time_to_live;
  23. int proto = ip_protocol->Protocol;
  24. Src_Addr.sin_addr.s_addr = ip_protocol->SrcAddr;
  25. Dst_Addr.sin_addr.s_addr = ip_protocol->DstAddr;
  26. printf("源地址: %15s --> ", inet_ntoa(Src_Addr.sin_addr));
  27. printf("目标地址: %15s --> ", inet_ntoa(Dst_Addr.sin_addr));
  28. printf("校验和: %5X --> TTL: %4d --> 协议类型: ", check_sum, ttl);
  29. switch (ip_protocol->Protocol)
  30. {
  31. case 1: printf("ICMP \n"); break;
  32. case 2: printf("IGMP \n"); break;
  33. case 6: printf("TCP \n"); break;
  34. case 17: printf("UDP \n"); break;
  35. case 89: printf("OSPF \n"); break;
  36. default: printf("None \n"); break;
  37. }
  38. }

解析TCP层数据包

  1. void PrintTCPHeader(const unsigned char * packetData)
  2. {
  3. typedef struct tcp_header
  4. {
  5. short SourPort; // 源端口号16bit
  6. short DestPort; // 目的端口号16bit
  7. unsigned int SequNum; // 序列号32bit
  8. unsigned int AcknowledgeNum; // 确认号32bit
  9. unsigned char reserved : 4, offset : 4; // 预留偏移
  10. unsigned char flags; // 标志
  11. short WindowSize; // 窗口大小16bit
  12. short CheckSum; // 检验和16bit
  13. short surgentPointer; // 紧急数据偏移量16bit
  14. }tcp_header;
  15. struct tcp_header *tcp_protocol;
  16. // +14 跳过数据链路层 +20 跳过IP层
  17. tcp_protocol = (struct tcp_header *)(packetData + 14 + 20);
  18. u_short sport = ntohs(tcp_protocol->SourPort);
  19. u_short dport = ntohs(tcp_protocol->DestPort);
  20. int window = tcp_protocol->WindowSize;
  21. int flags = tcp_protocol->flags;
  22. printf("源端口: %6d --> 目标端口: %6d --> 窗口大小: %7d --> 标志: (%d)",
  23. sport, dport, window, flags);
  24. if (flags & 0x08) printf("PSH 数据传输\n");
  25. else if (flags & 0x10) printf("ACK 响应\n");
  26. else if (flags & 0x02) printf("SYN 建立连接\n");
  27. else if (flags & 0x20) printf("URG \n");
  28. else if (flags & 0x01) printf("FIN 关闭连接\n");
  29. else if (flags & 0x04) printf("RST 连接重置\n");
  30. else printf("None 未知\n");
  31. }

解析UDP层数据包

  1. void PrintUDPHeader(const unsigned char * packetData)
  2. {
  3. typedef struct udp_header {
  4. uint32_t sport; // 源端口
  5. uint32_t dport; // 目标端口
  6. uint8_t zero; // 保留位
  7. uint8_t proto; // 协议标识
  8. uint16_t datalen; // UDP数据长度
  9. }udp_header;
  10. struct udp_header *udp_protocol;
  11. // +14 跳过数据链路层 +20 跳过IP层
  12. udp_protocol = (struct udp_header *)(packetData + 14 + 20);
  13. u_short sport = ntohs(udp_protocol->sport);
  14. u_short dport = ntohs(udp_protocol->dport);
  15. u_short datalen = ntohs(udp_protocol->datalen);
  16. printf("源端口: %5d --> 目标端口: %5d --> 大小: %5d \n", sport, dport,datalen);
  17. }

解析ICMP层数据包

  1. void PrintICMPHeader(const unsigned char * packetData)
  2. {
  3. typedef struct icmp_header {
  4. uint8_t type; // ICMP类型
  5. uint8_t code; // 代码
  6. uint16_t checksum; // 校验和
  7. uint16_t identification; // 标识
  8. uint16_t sequence; // 序列号
  9. uint32_t init_time; // 发起时间戳
  10. uint16_t recv_time; // 接受时间戳
  11. uint16_t send_time; // 传输时间戳
  12. }icmp_header;
  13. struct icmp_header *icmp_protocol;
  14. // +14 跳过数据链路层 +20 跳过IP层
  15. icmp_protocol = (struct icmp_header *)(packetData + 14 + 20);
  16. int type = icmp_protocol->type;
  17. int init_time = icmp_protocol->init_time;
  18. int send_time = icmp_protocol->send_time;
  19. int recv_time = icmp_protocol->recv_time;
  20. if (type == 8)
  21. {
  22. printf("发起时间戳: %d --> 传输时间戳: %d --> 接收时间戳: %d 方向: ",
  23. init_time, send_time, recv_time);
  24. switch (type)
  25. {
  26. case 0: printf("回显应答报文 \n"); break;
  27. case 8: printf("回显请求报文 \n"); break;
  28. default:break;
  29. }
  30. }
  31. }

Npcap发送ARP数据包

通过使用Npcap实现发送一个ARP广播数据包,这里需要先构建数据包的结构,然后在发送出去.

  1. #include <stdio.h>
  2. #include <winsock2.h>
  3. #include <Windows.h>
  4. #include <pcap.h>
  5. #pragma comment(lib, "packet.lib")
  6. #pragma comment(lib, "wpcap.lib")
  7. #pragma comment(lib,"WS2_32.lib")
  8. #define ETH_ARP 0x0806 // 以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为x0806
  9. #define ARP_HARDWARE 1 // 硬件类型字段值为表示以太网地址
  10. #define ETH_IP 0x0800 // 协议类型字段表示要映射的协议地址类型值为x0800表示IP地址
  11. #define ARP_REQUEST 1 // ARP请求
  12. #define ARP_RESPONSE 2 // ARP应答
  13. //14字节以太网首部
  14. struct EthernetHeader
  15. {
  16. u_char DestMAC[6]; // 目的MAC地址6字节
  17. u_char SourMAC[6]; // 源MAC地址 6字节
  18. u_short EthType; // 上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 2字节
  19. };
  20. //28字节ARP帧结构
  21. struct ArpHeader
  22. {
  23. unsigned short hdType; // 硬件类型
  24. unsigned short proType; // 协议类型
  25. unsigned char hdSize; // 硬件地址长度
  26. unsigned char proSize; // 协议地址长度
  27. unsigned short op; // 操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
  28. u_char smac[6]; // 源MAC地址
  29. u_char sip[4]; // 源IP地址
  30. u_char dmac[6]; // 目的MAC地址
  31. u_char dip[4]; // 目的IP地址
  32. };
  33. //定义整个arp报文包,总长度42字节
  34. struct ArpPacket {
  35. EthernetHeader ed;
  36. ArpHeader ah;
  37. };
  38. // 获取到指定网卡的句柄
  39. pcap_t * OpenPcap(int nChoose)
  40. {
  41. pcap_t *pcap_handle; //打开网络适配器,捕捉实例,是pcap_open返回的对象
  42. pcap_if_t *alldevs;
  43. char errbuf[PCAP_ERRBUF_SIZE]; //错误缓冲区,大小为256
  44. // 获取到所有设备列表
  45. if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
  46. exit(0);
  47. // 找到指定的网卡设备
  48. for (int x = 0; x < nChoose - 1; ++x)
  49. alldevs = alldevs->next;
  50. if ((pcap_handle = pcap_open(alldevs->name, // 设备名
  51. 65536, // 每个包长度
  52. PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
  53. 1000, // 读取超时时间
  54. NULL, // 远程机器验证
  55. errbuf // 错误缓冲池
  56. )) == NULL)
  57. {
  58. pcap_freealldevs(alldevs);
  59. exit(0);
  60. }
  61. return pcap_handle;
  62. }
  63. int main(int argc, char *argv[])
  64. {
  65. pcap_t *handle; // 打开网络适配器
  66. EthernetHeader eh; // 定义以太网包头
  67. ArpHeader ah; // 定义ARP包头
  68. unsigned char sendbuf[42]; // arp包结构大小42个字节
  69. unsigned char src_mac[6] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff };
  70. unsigned char src_ip[4] = { 0x01, 0x02, 0x03, 0x04 };
  71. handle = OpenPcap(3); // 拿到第三个网卡的句柄
  72. // 开始填充ARP包
  73. memset(eh.DestMAC, 0xff, 6); // 以太网首部目的MAC地址,全为广播地址
  74. memcpy(eh.SourMAC, src_mac, 6); // 以太网首部源MAC地址
  75. memcpy(ah.smac, src_mac, 6); // ARP字段源MAC地址
  76. memset(ah.dmac, 0xff, 6); // ARP字段目的MAC地址
  77. memcpy(ah.sip, src_ip, 4); // ARP字段源IP地址
  78. memset(ah.dip, 0x05, 4); // ARP字段目的IP地址
  79. // 赋值MAC地址
  80. eh.EthType = htons(ETH_ARP); //htons:将主机的无符号短整形数转换成网络字节顺序
  81. ah.hdType = htons(ARP_HARDWARE);
  82. ah.proType = htons(ETH_IP);
  83. ah.hdSize = 6;
  84. ah.proSize = 4;
  85. ah.op = htons(ARP_REQUEST);
  86. // 构造一个ARP请求
  87. memset(sendbuf, 0, sizeof(sendbuf)); // ARP清零
  88. memcpy(sendbuf, &eh, sizeof(eh)); // 首先把eh以太网结构填充上
  89. memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah)); // 接着在eh后面填充arp结构
  90. // 发送数据包
  91. if (pcap_sendpacket(handle, sendbuf, 42) == 0)
  92. {
  93. printf("发送ARP数据包成功! \n");
  94. }
  95. system("pause");
  96. return 0;
  97. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/162590
推荐阅读
相关标签
  

闽ICP备14008679号