C/C++ 运用Npcap发送UDP数据包

Npcap 是一个功能强大的开源网络抓包库,它是 WinPcap 的一个分支,并提供了一些增强和改进。特别适用于在 Windows 环境下进行网络流量捕获和分析。除了支持通常的网络抓包功能外,Npcap 还提供了对数据包的拼合与构造,使其成为实现 UDP 数据包发包的理想选择。本章将通过Npcap库构造一个UDP原始数据包,并实现对特定主机的发包功能,通过本章的学习读者可以掌握如何使用Npcap库伪造特定的数据包格式。

Npcap的主要特点和概述:

  1. 原始套接字支持: Npcap 允许用户通过原始套接字在网络层捕获和发送数据包。这使得用户能够进行更底层的网络活动监控和分析。
  2. WinPcap 的增强版本: Npcap 是 WinPcap 的一个分支,对其进行了一些增强和改进。这些改进包括对新版本 Windows 的支持、更好的性能和稳定性,以及一些额外的功能。
  3. 支持 Windows 10: Npcap 被设计用于支持 Windows 10 操作系统。它允许用户在最新的 Windows 平台上进行网络抓包和分析。
  4. Loopback 模式: Npcap 允许在 Loopback 接口上进行抓包,使用户能够监视本地主机上的网络流量。
  5. 多种应用场景: Npcap 被广泛应用于网络安全、网络管理、网络调试等各种场景。它为开发人员、网络管理员和安全专家提供了一个功能强大的工具,用于分析和理解网络通信。
  6. 开源: Npcap 是开源项目,其源代码可以在 GitHub 上获得。这使得用户可以自由查看、修改和定制代码,以满足特定需求。

UDP 是一种无连接、轻量级的传输层协议,与 TCP 相比,它不提供可靠性、流控制和错误恢复机制,但却更加简单且具有较低的开销。UDP 主要用于那些对传输速度要求较高、可以容忍少量丢失的应用场景。

UDP 数据包结构: UDP 数据包由报头和数据两部分组成。

  1. 报头(Header):
    • 源端口号(16 位): 指定发送端口。
    • 目标端口号(16 位): 指定接收端口。
    • 长度(16 位): 报头和数据的总长度,以字节为单位。
    • 校验和(16 位): 用于验证数据在传输过程中的完整性。
  2. 数据(Payload):
    • 实际传输的数据,长度可变。

UDP 的特点:

  1. 面向无连接: UDP 是一种无连接协议,通信双方不需要在传输数据之前建立连接。这使得它的开销较低,适用于一些实时性要求较高的应用。
  2. 不可靠性: UDP 不提供数据的可靠性保证,不保证数据包的到达、顺序和完整性。因此,它更适合那些能够容忍一些数据丢失的场景,如音视频传输。
  3. 适用于广播和多播: UDP 支持广播和多播通信,可以通过一个发送操作同时向多个目标发送数据。
  4. 低开销: 由于缺乏连接建立和维护的开销,以及不提供可靠性保证的特性,UDP 具有较低的开销,适用于对实时性要求较高的应用。
  5. 适用于短消息: 由于不需要建立连接,UDP 适合传输短消息,尤其是对实时性要求高的应用。

UDP 的应用场景:

  1. 实时性要求高的应用: 如实时音视频传输、在线游戏等。
  2. 简单的请求-响应通信: 适用于一些简单的请求-响应场景,如 DNS 查询。
  3. 广播和多播应用: UDP 的支持广播和多播特性使其适用于这类通信模式。
  4. 实时数据采集: 例如传感器数据采集等场景。

输出网卡

使用 WinPcap(Windows Packet Capture)库列举系统上的网络接口以及它们的 IP 地址。WinPcap 是一个用于 Windows 操作系统的网络数据包捕获库,可以用于网络数据包的捕获和分析。

代码主要做了以下几个事情:

  1. 使用 pcap_findalldevs_ex 函数查找系统上的所有网络接口。
  2. 遍历每个网络接口,获取其 IP 地址,并将地址列表打印出来。

pcap_findalldevs_ex 用于查找系统上所有网络接口的函数。它的原型如下:

int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);

函数参数说明:

  • source:一个字符串,用于指定网络接口的来源。可以为 NULL,表示从系统获取网络接口信息。也可以指定为一个网络地址,用于远程捕获。
  • auth:一个 pcap_rmtauth 结构的指针,用于指定远程捕获的认证信息。一般情况下可以为 NULL
  • alldevs:一个 pcap_if_t 类型的指针的地址,用于保存查找到的网络接口链表的头指针。
  • errbuf:一个字符数组,用于保存错误信息。

函数返回值:

  • 成功时返回 0。
  • 失败时返回 -1,错误信息保存在 errbuf 中。

函数功能:

pcap_findalldevs_ex 主要用于查找系统上的网络接口信息。当调用成功后,alldevs 将指向一个链表,链表中的每个节点都包含一个网络接口的信息。这个链表的头指针是 alldevs

pcap_freealldevs 用于释放 pcap_findalldevs_ex 函数分配的资源的函数。其原型如下:

void pcap_freealldevs(pcap_if_t *alldevs);

函数参数说明:

  • alldevs:由 pcap_findalldevs_ex 返回的链表的头指针。

函数功能:

pcap_freealldevs 主要用于释放 pcap_findalldevs_ex 函数返回的链表中分配的资源,包括每个节点和节点中保存的接口信息。

输出当前系统中活动网卡信息,可以这样来写,如下代码所示;

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <pcap.h>#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib, "packet.lib")
#pragma comment(lib, "wpcap.lib")// 打开网卡返回的指针
pcap_t* m_adhandle;
unsigned char* FinalPacket;
unsigned int UserDataLen;int main(int argc, char *argv[])
{// 打开网卡pcap_if_t* alldevs = NULL, *d = NULL;char szErr[MAX_PATH] = { 0 };if (-1 == pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, szErr)){return 0;}// 遍历网卡char* lpszIP = NULL;d = alldevs;while (NULL != d){// 遍历网卡IPchar szAddress[1024] = { 0 };pcap_addr_t* p = d->addresses;while (p){lpszIP = inet_ntoa(((sockaddr_in*)p->addr)->sin_addr);strcpy(szAddress, lpszIP);p = p->next;}std::cout << "地址列表: " << szAddress << std::endl;d = d->next;}// 释放资源pcap_freealldevs(alldevs);system("pause");return 0;
}

输出效果如下图所示;

打开网卡

打开网络适配器的函数,通过传入本机的IP地址,该函数会查找与该IP地址匹配的网络适配器并打开。以下是对该函数的简要分析:

查找网卡设备指针:

if (-1 == pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf))

使用 pcap_findalldevs_ex 函数来获取本机所有网卡设备的链表。如果返回值为 -1,说明发生了错误,这时函数会输出错误信息并直接返回。

选取适合网卡:

for (d = alldevs; d; d = d->next)

通过遍历网卡设备链表,查找与传入的本机IP地址匹配的网卡。首先,通过检查每个网卡的地址列表,找到第一个匹配的网卡。如果找到了,将 flag 标记设为1,然后跳出循环。如果未找到匹配的网卡,输出错误信息并返回。

获取子网掩码:

netmask = ((sockaddr_in*)d->addresses->netmask)->sin_addr.S_un.S_addr;

获取匹配网卡的子网掩码。

打开网卡:

m_adhandle = pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf);

使用 pcap_open 函数打开选择的网卡,该函数的声明如下:

pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);

这里是对参数的简要解释:

  • source: 要打开的网络适配器的名称,例如 “eth0”。

  • snaplen: 指定捕获数据包时每个数据包的最大长度。如果数据包超过这个长度,它将被截断。通常设置为数据包的最大可能长度。

  • flags
    

    : 控制捕获的方式,可以使用位掩码进行组合。常见的标志包括:

    • PCAP_OPENFLAG_PROMISCUOUS: 开启混杂模式,允许捕获所有经过网卡的数据包。
    • PCAP_OPENFLAG_MAX_RESPONSIVENESS: 最大响应性标志,可能在某些平台上影响性能。
  • read_timeout: 设置超时值,以毫秒为单位。如果设置为0,表示无限期等待数据包。

  • auth: 可以指定用于远程捕获的身份验证信息,通常为 NULL

  • errbuf: 用于存储错误信息的缓冲区,如果函数执行失败,会将错误信息写入这个缓冲区。

函数返回一个 pcap_t 类型的指针,它是一个表示打开的网络适配器的结构。如果打开失败,返回 NULL

检查以太网:

if (DLT_EN10MB != pcap_datalink(m_adhandle))

pcap_datalink 函数是 PCAP 库中用于获取网络适配器数据链路类型(datalink type)的函数,确保是以太网,如果不是以太网,输出错误信息并返回。

该函数的声明如下:

int pcap_datalink(pcap_t *p);

这里是对参数的简要解释:

  • p: 表示一个已经打开的网络适配器的 pcap_t 结构指针。

函数返回一个整数,表示数据链路类型。这个值通常是预定义的常量之一,用于标识不同类型的网络数据链路。

常见的一些数据链路类型常量包括:

  • DLT_EN10MB(Ethernet): 表示以太网数据链路。
  • DLT_IEEE802(802.5 Token Ring): 表示 IEEE 802.5 Token Ring 数据链路。
  • DLT_PPP(Point-to-Point Protocol): 表示点对点协议数据链路。
  • DLT_ARCNET(ARCNET): 表示 ARCNET 数据链路。

释放网卡设备列表:

pcap_freealldevs(alldevs);

最后,释放 pcap_findalldevs_ex 函数返回的网卡设备列表,避免内存泄漏。

该函数的其他全局变量 m_adhandleFinalPacketUserDataLen 已经在文章开头声明和定义。

// 通过传入本机IP地址打开网卡
void OpenAdapter(std::string local_address)
{pcap_if_t* alldevs = NULL, * d = NULL;char errbuf[256] = { 0 };bpf_program fcode;u_int netmask;// 获取网卡设备指针if (-1 == pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf)){std::cout << "获取网卡设备指针出错" << std::endl;return;}// 选取适合网卡int flag = 0;for (d = alldevs; d; d = d->next){pcap_addr_t* p = d->addresses;while (p){if (local_address == inet_ntoa(((sockaddr_in*)p->addr)->sin_addr)){flag = 1;break;}p = p->next;}if (1 == flag)break;}if (0 == flag){std::cout << "请检查本机IP地址是否正确" << std::endl;std::cout << local_address.c_str() << std::endl;return;}// 获取子网掩码netmask = ((sockaddr_in*)d->addresses->netmask)->sin_addr.S_un.S_addr;// 打开网卡m_adhandle = pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf);if (NULL == m_adhandle){std::cout << "打开网卡出错" << std::endl;pcap_freealldevs(alldevs);return;}//检查以太网if (DLT_EN10MB != pcap_datalink(m_adhandle)){std::cout << "此程序仅在以太网下工作" << std::endl;pcap_freealldevs(alldevs);return;}// 释放网卡设备列表pcap_freealldevs(alldevs);
}

构造数据

MAC地址转换为Bytes字节

将MAC 地址的字符串表示形式转换为字节数组(unsigned char 数组),函数首先创建了一个临时缓冲区 Tmp 来存储输入字符串的拷贝,然后使用 sscanf 函数将字符串中的每两个字符解析为一个十六进制数,存储到 Returned 数组中。最后,通过调整指针的位置,跳过已经处理的字符,实现了对整个字符串的解析。

下面是这段代码的解释:

// MAC地址转Bytes
unsigned char* MACStringToBytes(std::string String)
{// 获取输入字符串的长度int iLen = strlen(String.c_str());// 创建一个临时缓冲区,用于存储输入字符串的拷贝char* Tmp = new char[(iLen + 1)];// 将输入字符串拷贝到临时缓冲区strcpy(Tmp, String.c_str());// 创建一个用于存储结果的unsigned char数组,数组大小为6unsigned char* Returned = new unsigned char[6];// 循环处理每个字节for (int i = 0; i < 6; i++){// 使用sscanf将字符串中的两个字符转换为16进制数,存储到Returned数组中sscanf(Tmp, "%2X", &Returned[i]);// 移动临时缓冲区的指针,跳过已经处理过的字符memmove((void*)(Tmp), (void*)(Tmp + 3), 19 - i * 3);}// 返回存储结果的数组return Returned;
}

Bytes字节转换为16进制

将两个字节(unsigned char 类型的 XY)组成一个16位的无符号整数。函数的目的是将两个字节的数据合并成一个16位的整数。首先,将 X 左移8位,然后与 Y 进行按位或操作,得到一个包含两个字节信息的16位整数。最后,将这个16位整数返回。这种操作通常在处理网络协议或二进制数据时会经常遇到。

下面是这段代码的解释:

// Bytes地址转16进制
unsigned short BytesTo16(unsigned char X, unsigned char Y)
{// 将 X 左移8位,然后与 Y 进行按位或操作,得到一个16位的无符号整数unsigned short Tmp = X;Tmp = Tmp << 8;Tmp = Tmp | Y;return Tmp;
}

计算 IP 数据报的校验和

这个函数主要通过遍历 IP 头中的每两个字节,将它们合并为一个16位整数,并逐步累加到校验和中。在每次累加时,还需要检查是否发生了溢出,如果溢出则需要额外加1。最后,对累加得到的校验和进行取反操作,得到最终的 IP 校验和,并将其返回。这种校验和计算通常用于验证 IP 数据报的完整性。

下面是这段代码的解释:

// 计算IP校验和
unsigned short CalculateIPChecksum(UINT TotalLen, UINT ID, UINT SourceIP, UINT DestIP)
{// 初始化校验和unsigned short CheckSum = 0;// 遍历 IP 头的每两个字节for (int i = 14; i < 34; i += 2){// 将每两个字节合并为一个16位整数unsigned short Tmp = BytesTo16(FinalPacket[i], FinalPacket[i + 1]);// 计算校验和unsigned short Difference = 65535 - CheckSum;CheckSum += Tmp;// 处理溢出if (Tmp > Difference) { CheckSum += 1; }}// 取反得到最终的校验和CheckSum = ~CheckSum;return CheckSum;
}

计算 UDP 数据报的校验和

这个函数主要通过构造 UDP 数据报的伪首部,包括源 IP、目标 IP、协议类型(UDP)、UDP 长度、源端口、目标端口以及 UDP 数据等字段,并通过遍历伪首部的每两个字节计算校验和。最后取反得到最终的 UDP 校验和,并将其返回。这种校验和计算通常用于验证 UDP 数据报的完整性。

下面是这段代码的解释:

// 计算UDP校验和
unsigned short CalculateUDPChecksum(unsigned char* UserData, int UserDataLen, UINT SourceIP, UINT DestIP, USHORT SourcePort, USHORT DestinationPort, UCHAR Protocol)
{unsigned short CheckSum = 0;// 计算 UDP 数据报的伪首部长度unsigned short PseudoLength = UserDataLen + 8 + 9; // 长度包括 UDP 头(8字节)和伪首部(9字节)// 如果长度不是偶数,添加一个额外的字节PseudoLength += PseudoLength % 2;// 创建 UDP 伪首部unsigned char* PseudoHeader = new unsigned char[PseudoLength];RtlZeroMemory(PseudoHeader, PseudoLength);// 设置伪首部中的协议字段为 UDP (0x11)PseudoHeader[0] = 0x11;// 复制源和目标 IP 地址到伪首部memcpy((void*)(PseudoHeader + 1), (void*)(FinalPacket + 26), 8);// 将 UDP 头的长度字段拷贝到伪首部unsigned short Length = UserDataLen + 8;Length = htons(Length);memcpy((void*)(PseudoHeader + 9), (void*)&Length, 2);memcpy((void*)(PseudoHeader + 11), (void*)&Length, 2);// 将源端口、目标端口和 UDP 数据拷贝到伪首部memcpy((void*)(PseudoHeader + 13), (void*)(FinalPacket + 34), 2);memcpy((void*)(PseudoHeader + 15), (void*)(FinalPacket + 36), 2);memcpy((void*)(PseudoHeader + 17), (void*)UserData, UserDataLen);// 遍历伪首部的每两个字节,计算校验和for (int i = 0; i < PseudoLength; i += 2){unsigned short Tmp = BytesTo16(PseudoHeader[i], PseudoHeader[i + 1]);unsigned short Difference = 65535 - CheckSum;CheckSum += Tmp;if (Tmp > Difference) { CheckSum += 1; }}// 取反得到最终的校验和CheckSum = ~CheckSum;// 释放伪首部的内存delete[] PseudoHeader;return CheckSum;
}

这段代码的分析:

  1. 伪首部构造: UDP校验和的计算需要使用UDP头以及伪首部(包含源IP、目标IP、协议类型、UDP长度等信息)。这里使用PseudoHeader数组来构造伪首部。
  2. 伪首部填充: 通过memcpy等操作将源和目标IP地址、UDP头的长度字段以及UDP的源端口、目标端口、UDP数据等内容填充到伪首部中。
  3. 伪首部遍历: 通过遍历伪首部的每两个字节,计算累加和。遍历过程中,将两个字节转换为16位整数Tmp,然后进行累加。如果累加结果大于65535,则向结果中再加1。这是为了处理累加和溢出的情况。
  4. 取反: 计算完毕后,对累加和取反得到最终的UDP校验和。
  5. 内存释放: 最后释放动态分配的伪首部内存。

需要注意的是,UDP校验和是一个16位的值,用于验证UDP数据报在传输过程中是否被修改。这段代码主要完成了构造UDP伪首部和计算校验和的过程。在实际网络通信中,校验和的计算是为了保证数据的完整性,防止在传输过程中的错误。

创建UDP数据包函数

创建一个UDP数据包,该代码是一个简单的网络编程示例,用于创建和发送UDP数据包。其中,UDP数据包的内容和头部信息都可以根据实际需求进行定制。

代码的概述:

  1. 打开网卡: 通过pcap_findalldevs_ex函数获取本机的网卡设备列表,并在控制台输出每个网卡的地址列表。
  2. 选择网卡: 用户输入本机IP地址,程序通过遍历网卡设备列表,找到与输入IP地址匹配的网卡。
  3. 打开选定的网卡: 使用pcap_open函数打开选择的网卡,获取到网卡的句柄。
  4. 创建UDP数据包: 调用CreatePacket函数创建一个UDP数据包。该函数包括以下步骤:
    • 分配内存:使用new运算符为FinalPacket分配内存,内存大小为UserDataLength + 42字节。
    • 填充以太网头:拷贝目标MAC地址、源MAC地址和协议类型(IPv4)到FinalPacket的前12个字节。
    • 填充IP头:填充IPv4头部,包括版本、标题长度、总长度、标识、标志、偏移、生存时间、协议(UDP为0x11),校验和、源IP和目标IP。
    • 填充UDP头:填充UDP头,包括源端口、目标端口、UDP长度(包括UDP头和数据)和校验和。
    • 计算IP校验和:调用CalculateIPChecksum函数计算IP头的校验和。
    • 计算UDP校验和:调用CalculateUDPChecksum函数计算UDP头的校验和。
    • 返回数据包:生成的UDP数据包保存在FinalPacket中。
  5. 释放资源: 在程序结束时,释放分配的内存。
void CreatePacket(unsigned char* SourceMAC, unsigned char* DestinationMAC,unsigned int SourceIP, unsigned int DestIP,unsigned short SourcePort, unsigned short DestinationPort,unsigned char* UserData, unsigned int UserDataLength)
{UserDataLen = UserDataLength;FinalPacket = new unsigned char[UserDataLength + 42]; // 为数据长度加上42字节的标头保留足够的内存USHORT TotalLen = UserDataLength + 20 + 8;            // IP报头使用数据长度加上IP报头长度(通常为20字节)加上udp报头长度(通常为8字节)// 开始填充以太网包头memcpy((void*)FinalPacket, (void*)DestinationMAC, 6);memcpy((void*)(FinalPacket + 6), (void*)SourceMAC, 6);USHORT TmpType = 8;memcpy((void*)(FinalPacket + 12), (void*)&TmpType, 2);  // 使用的协议类型(USHORT)类型0x08是UDP。可以为其他协议(例如TCP)更改此设置// 开始填充IP头数据包memcpy((void*)(FinalPacket + 14), (void*)"\x45", 1);     // 前3位的版本(4)和最后5位的标题长度。memcpy((void*)(FinalPacket + 15), (void*)"\x00", 1);     // 通常为0TmpType = htons(TotalLen);memcpy((void*)(FinalPacket + 16), (void*)&TmpType, 2);TmpType = htons(0x1337);memcpy((void*)(FinalPacket + 18), (void*)&TmpType, 2);    // Identificationmemcpy((void*)(FinalPacket + 20), (void*)"\x00", 1);      // Flagsmemcpy((void*)(FinalPacket + 21), (void*)"\x00", 1);      // Offsetmemcpy((void*)(FinalPacket + 22), (void*)"\x80", 1);      // Time to live.memcpy((void*)(FinalPacket + 23), (void*)"\x11", 1);      // 协议UDP为0x11(17)TCP为6 ICMP为1等memcpy((void*)(FinalPacket + 24), (void*)"\x00\x00", 2);  // 计算校验和memcpy((void*)(FinalPacket + 26), (void*)&SourceIP, 4);   //inet_addr does htonl() for usmemcpy((void*)(FinalPacket + 30), (void*)&DestIP, 4);// 开始填充UDP头部数据包TmpType = htons(SourcePort);memcpy((void*)(FinalPacket + 34), (void*)&TmpType, 2);TmpType = htons(DestinationPort);memcpy((void*)(FinalPacket + 36), (void*)&TmpType, 2);USHORT UDPTotalLen = htons(UserDataLength + 8); // UDP Length does not include length of IP headermemcpy((void*)(FinalPacket + 38), (void*)&UDPTotalLen, 2);//memcpy((void*)(FinalPacket+40),(void*)&TmpType,2); //checksummemcpy((void*)(FinalPacket + 42), (void*)UserData, UserDataLength);unsigned short UDPChecksum = CalculateUDPChecksum(UserData, UserDataLength, SourceIP, DestIP, htons(SourcePort), htons(DestinationPort), 0x11);memcpy((void*)(FinalPacket + 40), (void*)&UDPChecksum, 2);unsigned short IPChecksum = htons(CalculateIPChecksum(TotalLen, 0x1337, SourceIP, DestIP));memcpy((void*)(FinalPacket + 24), (void*)&IPChecksum, 2);return;
}

对该代码的分析:

  1. 分配内存: 使用new运算符为FinalPacket分配内存,内存大小为UserDataLength + 42字节。这足够容纳UDP数据以及以太网、IP和UDP头的长度。
  2. 填充以太网头: 使用memcpy函数将目标MAC地址、源MAC地址和协议类型(这里是IPv4)拷贝到FinalPacket的前12个字节。
  3. 填充IP头:FinalPacket的第14个字节开始,填充IPv4头部。这包括版本、标题长度、总长度、标识、标志、偏移、生存时间、协议(UDP为0x11),校验和、源IP和目标IP。
  4. 填充UDP头:FinalPacket的第34个字节开始,填充UDP头。这包括源端口、目标端口、UDP长度(包括UDP头和数据)和校验和。其中,UDP校验和的计算通过调用CalculateUDPChecksum函数完成。
  5. 计算IP校验和: 在填充IP头后,调用CalculateIPChecksum函数计算IP头的校验和。这个校验和是IPv4头的一个字段。
  6. 返回数据包: 函数执行完毕后,生成的UDP数据包保存在FinalPacket中,可以将其用于发送到网络。

需要注意的是,这段代码中的硬编码可能需要根据实际需求进行修改,例如协议类型、标识、生存时间等。此外,计算校验和是网络协议中用于检测数据完整性的一种机制。

发送UDP数据包

代码演示了如何打开网卡,生成UDP数据包,并通过pcap_sendpacket函数发送数据包到网络。需要注意的是,数据包的内容和地址是硬编码的,实际应用中可能需要根据需要进行更改。

int main(int argc, char* argv[])
{// 打开网卡OpenAdapter("10.0.66.24");// 填充地址并生成数据包包头char SourceMAC[MAX_PATH] = "8C-ff-ff-ff-ff-ff";char SourceIP[MAX_PATH] = "192.168.93.11";char SourcePort[MAX_PATH] = "80";char DestinationMAC[MAX_PATH] = "8C-dd-dd-dd-dd-dd";char DestinationIP[MAX_PATH] = "192.168.93.11";char DestinationPort[MAX_PATH] = "8080";char DataString[MAX_PATH] = "hello lyshark";CreatePacket(MACStringToBytes(SourceMAC), MACStringToBytes(DestinationMAC), inet_addr(SourceIP), inet_addr(DestinationIP), atoi(SourcePort), atoi(DestinationPort), (UCHAR*)DataString, (strlen(DataString) + 1));// 循环发包for (int x = 0; x < 10; x++){if (0 != pcap_sendpacket(m_adhandle, FinalPacket, (UserDataLen + 42))){char* szErr = pcap_geterr(m_adhandle);return 0;}}system("pause");return 0;
}

打开wireshark抓包工具,过滤目标地址为ip.dst==192.168.93.11然后抓包,运行编译后的程序,则你会看到我们自己构建的数据包被发送了10次,如下图所示;

随便打开一个数据包看下结构,源地址目标地址均是伪造的地址,数据包中的内容是hello lyshark,如下图所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/169343.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【迅搜03】全文检索、文档、倒排索引与分词

全文检索、文档、倒排索引与分词 今天还是概念性的内容&#xff0c;但是这些概念却是整个搜索引擎中最重要的概念。可以说&#xff0c;所有的搜索引擎就是实现了类似的概念才能称之为搜索引擎。而且今天的内容其实都是相关联的&#xff0c;所以不要以为标题上有四个名词就感觉好…

【探索Linux】—— 强大的命令行工具 P.16(进程信号 —— 信号产生 | 信号发送 | 核心转储)

阅读导航 引言一、概念&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;kill -l命令&#xff08;察看系统定义的信号列表&#xff09; 二、产生信号&#xff08;1&#xff09;通过终端按键产生信号-- 信号产生-- Core Dump&#xff08;核心转储&#xff09; &#…

ZC-OFDM模糊函数原理及仿真

文章目录 前言一、ZC 序列二、ZC-OFDM 信号1、OFDM 信号表达式2、模糊函数表达式三、MATLAB 仿真1、MATLAB 核心源码2、仿真结果①、ZC-OFDM 模糊函数②、ZC-OFDM 距离分辨率③、ZC-OFDM 速度分辨率前言 本文进行 ZC-OFDM 的原理讲解及仿真,首先看一下 ZC-OFDM 的模糊函数仿真…

【持续更新】汇总了一份前端领域必看面试题

文章目录 1. 写在前面2. 前端面试汇总2.0.1. 如何提⾼webpack的打包速度2.0.2. 数组去重2.0.3. 前端有几种缓存方式&#xff1f;2.0.4. nextTick描述一下&#xff1f;2.0.5. Webpack层面的优化&#xff1f;2.0.6. 代码层面的优化&#xff1f;2.0.7. Web 技术的优化&#xff1f;…

【C++】PACS医学图像存储和传输系统源码带三维重建

PACS&#xff08;Picture Archiving and Communication System&#xff09;系统作为医学图像的存储和传输平台&#xff0c;为医生和患者提供了便捷高效的诊疗服务支持。近年来&#xff0c;三维重建技术在PACS系统中的应用越来越广泛。 三维后处理功能是临床数字技术中的重要组成…

【Linux】Linux权限管理

目录 一、Linux中权限的概念 二、 Linux下的用户 2.1 用户的类型 2.2 用户创建、切换和删除 2.2.1 useradd或adduser命令创建用户 2.2.2 passwd命令设置用户密码 2.2.3 userdel命令删除用户 2.2.4 su命令切换用户身份等来管理和操作用户 2.3 注意事项 三、权限的管理…

浅析基于物联网的远程抄表系统的设计及应用

安科瑞 华楠 摘 要&#xff1a;本文基于物联网的概念&#xff0c;使用 ZigBee、通用分组无线服务技术两种无线通信技术相结合的方式实现远程抄表并对数据进行存储和管理。此系统设计主要分为硬件方面的设计和软件方面的设计&#xff0c;硬件方面的设计需要完成三个部分的硬件制…

redis运维(二十)redis 的扩展应用 lua(二)

一 redis 的扩展应用 lua redis lua脚本语法 ① 什么是脚本缓存 redis 缓存lua脚本 说明&#xff1a; 重启redis,脚本缓存会丢失 下面讲解 SCRIPT ... 系列 SCRIPT ② LOAD 语法&#xff1a;SCRIPT LOAD lua代码 -->载入一个脚本,只是预加载,不执行思考1&#xff1…

Vue解析器

解析器本质上是一个状态机。但我们也曾提到&#xff0c;正则表达式其实也是一个状态机。因此在编写 parser 的时候&#xff0c;利用正则表达式能够让我们少写不少代码。本章我们将更多地利用正则表达式来实现 HTML 解析器。另外&#xff0c;一个完善的 HTML 解析器远比想象的要…

PyQt基础_004_ 按钮类控件QPushButton以及自定义按钮控件

Qpushbutton基本操作 1.热键 2.按钮加图标 3.按钮事件等 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class Form(QDialog):def __init__(self, parentNone):super(Form, self).__init__(parent)layout QVBoxLayout()se…

Android 打包aar包含第三方aar 解决方案

Android 打包aar包含第三方aar 因项目需要&#xff0c;打包aar包含第三方aar&#xff0c;如果直接对module进行打包会产生一些问题。 * What went wrong: Direct local .aar file dependencies are not supported when building an AAR. The resulting AAR would be broken be…

如何将Postman API转换JMeter进行扩展

可扩展性 Postman测试无法扩展。如果您的集合中有很多请求&#xff0c;Postman / Newman将使用1个线程&#xff08;用户&#xff09;并按顺序执行这些请求&#xff0c;而不是使用多个线程并发执行。 性能测试能力 由于可扩展性限制&#xff0c;Postman不适合API性能测试。性…

力扣二叉树--总结篇(1)

前言 七天写了二十道题&#xff0c;前面感觉不错&#xff0c;后面越来越写不出来&#xff0c;刷题的心境和效果已然发生了变化。写个阶段总结&#xff0c;及时调整。 内容 先是二叉树的遍历 前序&#xff0c;中序&#xff0c;后序&#xff0c;即对应的递归&#xff0c;迭代…

visual studio 下的git

我这个是看视频笔记 YouTube : https://www.youtube.com/watch?vgkDASVE_Hdg 主要内容是&#xff1a;建立git 库&#xff0c; 保存commit&#xff0c; 建立分支 create branch, 合并分支merge branch,比较 diff&#xff0c;Revert ,history,delete branch, rename branch, t…

金融众筹模式系统源码 适合创业孵化机构+天使投资机构+投资基金会等 附带完整的搭建教程

随着互联网技术的发展和金融市场的开放&#xff0c;金融众筹模式逐渐成为一种新型的融资方式。这种模式通过互联网平台聚集大量投资者&#xff0c;共同参与到一个项目中&#xff0c;为项目提供资金支持&#xff0c;最终获得投资回报。今天罗峰给大家分享一款金融众筹模式系统源…

基于springboot实现学生成绩管理系统项目【项目源码+论文说明】

基于springboot实现学生成绩管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&am…

Spring框架学习 -- Bean的生命周期和作用域

目录 前言 案例 案例分析 作用域的定义 Bean对象的6种作用域 Singleton prototype 设置作用域 ​编辑延迟初始化 Spring的执行流程 Bean的生命周期 前言 我们可以类比一下普通变量的生命周期和作用域, 大多数变量的生命周期和作用域都被限定在了花括号内 {}, 除…

微信公众号快速接入大模型

今天找到一个可以快速将大模型接入公众号的方法&#xff0c;现在跟大家分享一下。 如何让微信公众号接入大模型文案创作能力&#xff0c;实现类似ChatGPT文案创作功能。方法其实很简单&#xff0c;只需打开地址“http://www.botaigc.cn:8900/mpauth”&#xff0c;用微信扫码即可…

根据商品ID获取淘宝数据接口|淘宝商品详情接口|淘宝关键词搜索商品列表接口|淘宝到手价接口|淘宝API接口

淘宝API接口可以运用到多种业务场景中&#xff0c;以下列举了一些主要的场景&#xff1a; 商品信息展示&#xff1a;通过调用淘宝API详情接口&#xff0c;可以获取商品的详细信息&#xff0c;如商品标题、价格、库存、销量、评价等数据。这些信息可以用于在自己的网站或应用程…

实时LCM的ImgPilot搭建部署

ImgPilot是具有实时潜在一致性模型&#xff08;LCM&#xff09;功能的图像试点 下载源码 GitHub - leptonai/imgpilot: Image pilot with the power of Real-Time Latent Consistency Modelhttps://github.com/leptonai/imgpilot安装前端web cd imgpilot npm install 安装…