WinDivert网络数据拦截测试(C++)
Posted on 2021-07-15 16:58:45 by 主打一个C++
WinDivert是一个用于Windows的网络数据包捕获和修改的库,它允许你在用户态拦截、检查、修改和重定向网络数据包。WinDivert可以用于实现网络监控、过滤和修改等功能。
官网:WinDivert
关键函数:
WINDIVERTEXPORT HANDLE WinDivertOpen(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__in INT16 priority,
__in UINT64 flags);
//参数说明
打开一个windivert对象,返回一个对象指针。打开的过程中,需要制定 过滤规则,过滤层,过滤器的优先级,以及windivert对象的工作模式。
过滤规则的编写:参考https://reqrypt.org/windivert-doc.html 第7部分
过滤层参数说明:
Layer | Description |
---|---|
WINDIVERT_LAYER_NETWORK = 0 | The network layer. This is the default. 网络层 |
WINDIVERT_LAYER_NETWORK_FORWARD | The network layer (forwarded packets).转发层 |
优先级的说明:其实这里说明的就是指明过滤规则的优先级。值越小,优先级越大。 -1000的优先级最高,1000优先级最低。 对于一个数据包,如果它同时匹配多个Windivert对象的规则,那么,它依次被这些对象安装优先级从高到低的次序处理。
过滤FLAG :该参数指明Windivert对象到底是用于监听、丢包、还是修改包模式。
Flag | Description |
---|---|
WINDIVERT_FLAG_SNIFF | WinDivert进入监听模式,只是被动监听,其功能等同于Winpcap |
WINDIVERT_FLAG_DROP | WinDivert单纯地把满足过滤条件的包丢弃,此模式下不能读取包内容 |
WINDIVERT_FLAG_DEBUG | WinDivert把满足过滤的条件的包扣下来,等待被修改然后重新注入 |
WINDIVERTEXPORT BOOL WinDivertRecv(
__in HANDLE handle,
__out_opt VOID *pPacket,
__in UINT packetLen,
__out_opt UINT *pRecvLen,
__out_opt WINDIVERT_ADDRESS *pAddr);
接收特定WinDivert对象的捕获的包的函数。
handle: WinDivertOpen的返回值
pPacket : 用于存储包的buffer,缓冲区,这个是用户提供的。
packetLen: 缓冲区的大小;如果包的实际长度大于此值,则截取packetLen个字节到pPacket。
pAddr :包性质说明结构。该结构体,指明目前抓取到的包的性质。说明如下:
typedef struct
{
INT64 Timestamp;
UINT32 IfIdx;
UINT32 SubIfIdx;
UINT8 Direction:1;
UINT8 Loopback:1;
UINT8 Impostor:1;
UINT8 PseudoIPChecksum:1;
UINT8 PseudoTCPChecksum:1;
UINT8 PseudoUDPChecksum:1;
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
字段说明:
Timestamp: WinDivert捕获到该包的时间戳
IfIdx: 该包所在的网卡序号
SubIfIdx: 网卡子序号
Direction: 包的方向,主要有入包和出包之分。
值 | 含义 |
---|---|
WINDIVERT_DIRECTION_OUTBOUND | with value 0 for outbound packets. |
WINDIVERT_DIRECTION_INBOUND | with value 1 for inbound packets. |
Loopback: 是否是回环包。Set to 1 for loopback packets, 0 otherwise
Impostor: 是否是已经修改的包。Set to 1 for impostor packets, 0 otherwise. 注意,如果是修改后的包,这个值会被值为1。这个值主要是为了防止出现同一个包先被WinDivert捕获到,然后WinDivertSend后,又被捕获到。PseudoIPChecksum: Set to 1 for packets with a pseudo IPv4 checksum, 0 otherwise.
PseudoTCPChecksum: Set to 1 for packets with a pseudo TCP checksum, 0 otherwise.
PseudoTCPChecksum: Set to 1 for packets with a pseudo UDP checksum, 0 otherwise.
recvlen:实际拷贝到pPacket缓冲区的字节数。可能为0.
- WinDivertSend
BOOL WinDivertSend(
__in HANDLE handle,
__in PVOID pPacket,
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr,
__out_opt UINT *sendLen
);
handle: WinDivertOpen()返回值.
pPacket: 待发包的内容.
packetLen: pPacket的总长度.
pAddr: 待发包的性质 WINDIVERT_ADDRESS.
sendLen: The total number of bytes injected. Can be NULL if this information is not required.
注意:发包之前 ,一定要让包有正确的校验值。!!!
- WinDivertClose
BOOL WinDivertClose(
__in HANDLE handle
);
一些辅助API
主要是一些包的解析、校验和的计算api.
- WinDivertHelperParsePacket 头部解析api
BOOL WinDivertHelperParsePacket(
__in PVOID pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_IPHDR *ppIpHdr,
__out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
__out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr,
__out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
__out_opt PWINDIVERT_TCPHDR *ppTcpHdr,
__out_opt PWINDIVERT_UDPHDR *ppUdpHdr,
__out_opt PVOID *ppData,
__out_opt UINT *pDataLen
);
- WinDivertHelperParseIPv4Address ip地址转换api ,点分十进制转INT。
BOOL WinDivertHelperParseIPv4Address(
__in const char *addrStr,
__out_opt UINT32 *pAddr
);
- WinDivertHelperCalcChecksums 计算校验值
UINT WinDivertHelperCalcChecksums(
__inout PVOID pPacket,
__in UINT packetLen,
__in_opt PWINDIVERT_ADDRESS pAddr,
__in UINT64 flags
);
注意!这个函数会直接在pPacket缓冲区中计算各个校验值。返回值是表明计算了多少个校验值。
//示例代码:
#include <iostream>
#include<Windows.h>
#include "./WinDivert-2.2.2-A/include/windivert.h"
#pragma comment(lib, "WinDivert.lib")
using namespace std;
int main()
{
//HANDLE handle = ::WinDivertOpen("tcp.DstPort == 3002 || tcp.SrcPort == 3002", //过滤规则
// WINDIVERT_LAYER_NETWORK, //过滤层
// 0, //优先级
// 0);
HANDLE handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, 0, WINDIVERT_FLAG_DROP);
if (handle == INVALID_HANDLE_VALUE) // 开启过滤对象
{
DWORD res = ::GetLastError();
return 0;
}
UINT packetLen = WINDIVERT_MTU_MAX;
char* packet = new char[WINDIVERT_MTU_MAX];
UINT recvSize = 0;
UINT sendSize = 0;
WINDIVERT_ADDRESS addr = { 0 };
CHAR outbuff[1024] = { 0 };
while (true)
{
ZeroMemory(packet, packetLen);
if (!::WinDivertRecv(handle, //windivert对象
packet, // 缓存
packetLen, //缓存长度
&recvSize, // 实际读取的数据长度
&addr)) // WINDIVERT_ADDRESS对象
{
DWORD res = ::GetLastError();
cout << "WinDivertRecv error:" << res << endl;
continue;
}
//cout << "接收数据长度:" << recvSize << endl;
PWINDIVERT_IPHDR iphdr = nullptr;
PWINDIVERT_TCPHDR tcphdr = nullptr;
PWINDIVERT_UDPHDR udphdr = nullptr;
// 网络包头部解析
if (!::WinDivertHelperParsePacket(packet, recvSize, &iphdr, nullptr, nullptr, nullptr, nullptr, &tcphdr, &udphdr, nullptr, nullptr, nullptr, nullptr))
{
DWORD res = ::GetLastError();
cout << "WinDivertHelperParsePacket error:" << res << endl;
continue;
}
if (tcphdr != nullptr && iphdr != nullptr)
{
UINT dstPort = WinDivertHelperHtons(tcphdr->DstPort);
UINT srcPort = ::WinDivertHelperHtons(tcphdr->SrcPort);
UINT length = ::WinDivertHelperHtons(iphdr->Length);
char srcAddress[1024] = { 0 };
char dstAddress[1024] = { 0 };
::WinDivertHelperFormatIPv4Address(::WinDivertHelperNtohl(iphdr->SrcAddr), srcAddress, 1024);
::WinDivertHelperFormatIPv4Address(::WinDivertHelperNtohl(iphdr->DstAddr), dstAddress, 1024);
ZeroMemory(outbuff, sizeof(outbuff));
sprintf_s(outbuff, "id:%d 长度:%d 目标IP:%s 端口:%d,本地IP:%s 端口:%d ACK:%d SYN:%d Fin:%d Rst:%d Psh:%d Urg:%d UrgPtr:%d Window:%d Checksum:%d",
iphdr->Id, length, dstAddress, dstPort, srcAddress, srcPort, tcphdr->Ack, tcphdr->Syn, tcphdr->Fin,
tcphdr->Rst, tcphdr->Psh, tcphdr->Urg, tcphdr->UrgPtr, tcphdr->Window, tcphdr->Checksum);
cout << outbuff << endl;
INT tcpHeadLen = sizeof(WINDIVERT_TCPHDR);
INT ipHeadLen = sizeof(WINDIVERT_IPHDR);
INT dataLen = recvSize - 16 - ipHeadLen - tcpHeadLen;
if (dataLen > 0) //解析数据
{
char* data = packet + 16 + ipHeadLen + tcpHeadLen;
cout << data << endl; //输出数据内容
}
else
{
//无有效数据
}
}
//计算校验和
if (!::WinDivertHelperCalcChecksums(packet, packetLen, &addr, 0))
{
DWORD res = ::GetLastError();
cout << "WinDivertHelperCalcChecksums error:" << res << endl;
continue;
}
::Sleep(3); //可延迟接收处理
// 把修改后的包发送出去
if (!::WinDivertSend(handle, packet, packetLen, &sendSize, &addr))
{
DWORD res = ::GetLastError();
cout << "WinDivertSend: " << res << endl;
}
}
::WinDivertShutdown(handle, WINDIVERT_SHUTDOWN_BOTH);
::WinDivertClose(handle);
std::cout << "Hello World!
";
}
*转载请注明出处:原文链接:https://cpp.vin/page/4.html