Files
NetVizor/WinDivertNet/WinDivertWrapper/PacketSniffer.cs
T
2025-05-30 20:44:10 +08:00

230 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Common.Logger;
namespace WinDivertNet.WinDivertWrapper;
using System;
using System.Runtime.InteropServices;
public static class PacketSniffer
{
public static void Start1()
{
Log.Information($"进入 12313 ");
var handle = WinDivert.Open("true", WinDivert.WINDIVERT_LAYER_NETWORK, 0, WinDivert.WINDIVERT_FLAG_SNIFF);
byte[] buffer = new byte[65535];
WinDivert.WINDIVERT_ADDRESS addr = default;
uint readLen = 0;
while (true)
{
try
{
if (WinDivert.Recv(handle, buffer, (uint)buffer.Length, ref addr, ref readLen))
{
ParsePacketAndLog(buffer, readLen, addr);
}
}
catch (Exception ex)
{
Log.Information($"接收数据包时出错: {ex.Message}");
}
}
void ParsePacketAndLog(byte[] buffer, uint length, WinDivert.WINDIVERT_ADDRESS addr)
{
Log.Information($"length: {length}");
if (buffer == null || length == 0)
return;
try
{
// IPv4 数据包的最小长度为 20 字节
if (length >= 20)
{
// 检查版本 (IPv4 = 4, 位于第一个字节的高 4 位)
int version = (buffer[0] >> 4) & 0xF;
if (version == 4) // IPv4
{
int headerLength = (buffer[0] & 0xF) * 4; // IHL * 4 = 字节数
byte protocol = buffer[9]; // 协议字段
// 源 IP 和目标 IP
uint srcIp = (uint)((buffer[12]) | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24));
uint dstIp = (uint)((buffer[16]) | (buffer[17] << 8) | (buffer[18] << 16) | (buffer[19] << 24));
string srcIpStr = $"{buffer[12]}.{buffer[13]}.{buffer[14]}.{buffer[15]}";
string dstIpStr = $"{buffer[16]}.{buffer[17]}.{buffer[18]}.{buffer[19]}";
Log.Information($"IPv4: Src={srcIpStr}, Dst={dstIpStr}, Protocol={protocol}");
// 如果有足够的数据,解析 TCP 或 UDP
if (length >= (uint)(headerLength + 4) && (protocol == 6 || protocol == 17))
{
// 获取端口 (TCP 和 UDP 的前 4 字节都是源端口和目标端口)
int offset = headerLength;
ushort srcPort = (ushort)((buffer[offset] << 8) | buffer[offset + 1]);
ushort dstPort = (ushort)((buffer[offset + 2] << 8) | buffer[offset + 3]);
if (protocol == 6) // TCP
{
Log.Information($"TCP: SrcPort={srcPort}, DstPort={dstPort}");
}
else if (protocol == 17) // UDP
{
Log.Information($"UDP: SrcPort={srcPort}, DstPort={dstPort}");
}
}
}
else if (version == 6 && length >= 40) // IPv6 (头部固定 40 字节)
{
// IPv6 解析代码...
// 这里略过,需要时可以添加
}
}
}
catch (Exception ex)
{
Log.Information($"解析数据包时出错: {ex.Message}");
}
}
}
public static void Start()
{
Log.Information("WinDivert调试工具启动...");
// 检查是否以管理员身份运行
bool isAdmin = new System.Security.Principal.WindowsPrincipal(
System.Security.Principal.WindowsIdentity.GetCurrent()
).IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
if (!isAdmin)
{
Log.Information("错误: 此程序需要管理员权限才能使用WinDivert!");
Log.Information("请右键点击程序,选择'以管理员身份运行'然后重试。");
return;
}
Log.Information("步骤1: 尝试打开WinDivert...");
// 最简单的过滤器
string filter = "true";
IntPtr handle =
WinDivert.WinDivertOpen(filter, WinDivert.WINDIVERT_LAYER_NETWORK, 0, WinDivert.WINDIVERT_FLAG_SNIFF);
// 检查句柄是否有效
if (handle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
Log.Information($"错误: 无法打开WinDivert,错误码: {errorCode}");
PrintWin32Error(errorCode);
return;
}
Log.Information("成功: WinDivert句柄已打开");
// 尝试接收一个数据包
Log.Information("\n步骤2: 尝试接收数据包...");
// 为数据包分配缓冲区
byte[] buffer = new byte[65535]; // 最大以太网帧大小
// 设置接收地址结构
WinDivert.WINDIVERT_ADDRESS addr = new WinDivert.WINDIVERT_ADDRESS
{
Reserved = new byte[8] // 确保Reserved被初始化
};
// 接收数据包
uint readLen = 0;
// 尝试直接使用基本的Recv函数
Log.Information("尝试WinDivertRecv...");
bool recvResult = WinDivert.WinDivertRecv(handle, buffer, (uint)buffer.Length, ref addr, ref readLen);
if (!recvResult)
{
int errorCode = Marshal.GetLastWin32Error();
Log.Information($"错误: WinDivertRecv失败,错误码: {errorCode}");
PrintWin32Error(errorCode);
}
else
{
Log.Information($"成功: 接收到数据包,大小: {readLen} 字节");
// 打印数据包的前16个字节
string hexData = BitConverter.ToString(buffer, 0, Math.Min((int)readLen, 16));
Log.Information($"数据包前16字节: {hexData}");
}
// 重置并尝试使用Ex版本
readLen = 0;
addr = new WinDivert.WINDIVERT_ADDRESS { Reserved = new byte[8] };
Log.Information("\n尝试WinDivertRecvEx...");
bool recvExResult =
WinDivert.WinDivertRecvEx(handle, buffer, (uint)buffer.Length, 0, ref addr, ref readLen, IntPtr.Zero);
if (!recvExResult)
{
int errorCode = Marshal.GetLastWin32Error();
Log.Information($"错误: WinDivertRecvEx失败,错误码: {errorCode}");
PrintWin32Error(errorCode);
}
else
{
Log.Information($"成功: 接收到数据包,大小: {readLen} 字节");
// 打印数据包的前16个字节
string hexData = BitConverter.ToString(buffer, 0, Math.Min((int)readLen, 16));
Log.Information($"数据包前16字节: {hexData}");
}
// 最后关闭句柄
WinDivert.WinDivertClose(handle);
Log.Information("\nWinDivert句柄已关闭");
Log.Information("\n调试信息收集完成。请检查以上输出以确定问题所在。");
}
// 辅助函数:打印Win32错误信息
private static void PrintWin32Error(int errorCode)
{
switch (errorCode)
{
case 5:
Log.Information("访问被拒绝。请确认程序以管理员权限运行。");
break;
case 87:
Log.Information("参数错误。过滤器语法可能不正确。");
break;
case 123:
Log.Information("文件名、目录名或卷标语法不正确。请检查WinDivert.dll是否位于正确的路径。");
break;
case 126:
Log.Information("找不到指定的模块。无法找到WinDivert.dll文件。");
break;
case 193:
Log.Information("不是有效的Win32应用程序。WinDivert.dll可能是错误的版本(32位/64位)。");
break;
case 997:
Log.Information("正在进行重叠操作。WinDivert可能需要异步调用。");
break;
case 995:
Log.Information("由于线程退出或应用程序请求,已中止I/O操作。");
break;
case 998:
Log.Information("无效访问WinDivert。请检查是否有另一个进程正在使用相同的过滤器。");
break;
case 1450:
Log.Information("系统资源不足,无法完成请求的服务。");
break;
default:
Log.Information($"未知错误。Windows错误码: {errorCode}");
break;
}
}
}