面向对象的WinDivertv2.2的dotnet异步封装,轻松实现网络数据拦截与修改。
<PackageReference Include="WindivertDotnet" Version="1.*" />
- 抓取网络数据包
- 过滤或丢弃网络数据包
- 嗅探网络数据包
- 注入网络数据包
- 修改网络数据包
var filter = Filter.True
.And(f => f.Network.Loopback)
.And(f => f.Tcp.DstPort == 443)
.And(f => f.Tcp.Ack == true);
using var divert = new WinDivert(filter, WinDivertLayer.Network);
using var packet = new WinDivertPacket();
using var addr = new WinDivertAddress();
while (true)
{
// 读包
await divert.RecvAsync(packet, addr);
ProcessPacket(packet, addr);
// 修改后发出
await divert.SendAsync(packet, addr);
}
static unsafe void ProcessPacket(WinDivertPacket packet, WinDivertAddress addr)
{
// 解包
var result = packet.GetParseResult();
// 改包
result.TcpHeader->DstPort = 443;
// 重算checksums
packet.CalcChecksums(addr);
}
private async Task SendEchoRequestAsync(IPAddress dstAddr)
{
// 使用router计算将进行通讯的本机地址
var router = new WinDivertRouter(dstAddr);
using var addr = router.CreateAddress();
using var packet = this.CreateIPV4EchoPacket(router.SrcAddress, router.DstAddress);
packet.CalcChecksums(addr); // 计算checksums,因为创建包时没有计算
await this.divert.SendAsync(packet, addr);
}
/// <summary>
/// 创建icmp的echo包
/// </summary>
/// <param name="srcAddr"></param>
/// <param name="dstAddr"></param>
/// <returns></returns>
private unsafe WinDivertPacket CreateIPV4EchoPacket(IPAddress srcAddr, IPAddress dstAddr)
{
// ipv4头
var ipHeader = new IPV4Header
{
TTL = 128,
Version = IPVersion.V4,
DstAddr = dstAddr,
SrcAddr = srcAddr,
Protocol = ProtocolType.Icmp,
HdrLength = (byte)(sizeof(IPV4Header) / 4),
Id = ++this.id,
Length = (ushort)(sizeof(IPV4Header) + sizeof(IcmpV4Header))
};
// icmp头
var icmpHeader = new IcmpV4Header
{
Type = IcmpV4MessageType.EchoRequest,
Code = default,
Identifier = ipHeader.Id,
SequenceNumber = ++this.sequenceNumber,
};
// 将数据写到packet缓冲区
var packet = new WinDivertPacket(ipHeader.Length);
var writer = packet.GetWriter();
writer.Write(ipHeader);
writer.Write(icmpHeader);
return packet;
}