A: 新增ExceptionExpand异常处理类及相关枚举 (Infrastructure/ExceptionExpand.cs)
A: 新增全局Process缓存类 (Infrastructure/GlobalCaches/ProcessCache.cs) A: 新增WinDivert封装和PacketSniffer数据包捕获功能 (WinDivertNet/WinDivertWrapper) A: 新增Todo文档 (ClientApp/doc/Todo.md) U: 配置生成路由显示 (ClientApp/src/constants/app.ts) U: WebPanel新增数据包捕获触发逻辑 (Shell/Views/WebPanel.xaml.cs) U: 配置Shell项目加载WinDivert相关文件 (Shell/Shell.csproj)
This commit is contained in:
1 parent
078e59ae6b
commit
ad2514e044
21 files changed
+1560
-71
No files matched your search
@@ -0,0 +1,4 @@
|
||||
|
||||
2025年5月18日 18点51分
|
||||
[ ] C# 日志系统配置
|
||||
[ ] Wpf 全局异常捕获
|
||||
@@ -27,7 +27,7 @@ const app = {
|
||||
/**
|
||||
* 是否展示生成路由
|
||||
*/
|
||||
IS_SHOW_GENERATE_ROUTER: false
|
||||
IS_SHOW_GENERATE_ROUTER: true
|
||||
}
|
||||
|
||||
export default app
|
||||
@@ -73,6 +73,12 @@ const commands: CommandType[] = [
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'PacketSnifferStart',
|
||||
description: 'WinDivert!!',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace Infrastructure;
|
||||
|
||||
public class ExceptionExpand : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认异常编码
|
||||
/// </summary>
|
||||
private const long DefaultCode = -1;
|
||||
|
||||
public string ErrorMessage { get; private set; } = "";
|
||||
public long ErrorCode { get; private set; } = DefaultCode;
|
||||
public string Suggestion { get; private set; } = "";
|
||||
|
||||
private ExceptionExpand()
|
||||
{
|
||||
}
|
||||
|
||||
public ExceptionExpand(long errorCode, string massage, string solution) : base(
|
||||
massage)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
Suggestion = solution;
|
||||
}
|
||||
|
||||
public ExceptionExpand(long errorCode, string massage, string solution, Exception? innerException) : base(
|
||||
massage, innerException)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
Suggestion = solution;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Error Code: {ErrorCode}\nMessage: {Message}\nSuggestion: {Suggestion}\n{base.ToString()}";
|
||||
}
|
||||
}
|
||||
|
||||
public class ExceptionEnum
|
||||
{
|
||||
// region 系统常见错误本地化
|
||||
|
||||
/// <summary>
|
||||
/// 进程信息获取失败
|
||||
/// </summary>
|
||||
public static readonly ExceptionExpand ProcessGetException = new(100001L, "进程消息获取失败,指定线程可能不存在或已关闭!", "以管理员权限重试!");
|
||||
|
||||
|
||||
// endregion
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Diagnostics;
|
||||
using Infrastructure.Models;
|
||||
|
||||
namespace Infrastructure.GlobalCaches;
|
||||
|
||||
/// <summary>
|
||||
/// 进程信息缓存
|
||||
/// </summary>
|
||||
public sealed class ProcessCache
|
||||
{
|
||||
private static readonly Lazy<ProcessCache> _instance = new Lazy<ProcessCache>(() => new ProcessCache());
|
||||
|
||||
public static ProcessCache Instance => _instance.Value;
|
||||
|
||||
public record ProcessCacheKey(int Pid, DateTime StartTime);
|
||||
|
||||
public ProcessCacheKey GetProcessKey(int pid)
|
||||
{
|
||||
var process = Process.GetProcessById(pid);
|
||||
return new ProcessCacheKey(pid, process.StartTime);
|
||||
}
|
||||
|
||||
// 私有构造函数,禁止外部创建实例
|
||||
private ProcessCache()
|
||||
{
|
||||
// 初始化缓存等操作
|
||||
}
|
||||
|
||||
// 示例缓存字段
|
||||
private readonly Dictionary<ProcessCacheKey, ProgramInfo> _cache = new Dictionary<ProcessCacheKey, ProgramInfo>();
|
||||
|
||||
// 设置缓存
|
||||
public void Set(ProcessCacheKey key, ProgramInfo value)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
_cache[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取缓存
|
||||
public ProgramInfo? Get(ProcessCacheKey key)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
return _cache.GetValueOrDefault(key);
|
||||
}
|
||||
}
|
||||
|
||||
// 移除缓存
|
||||
public void Remove(ProcessCacheKey key)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
_cache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.21" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.4.25258.110" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WinDivertNet\WinDivertNet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,16 +1,11 @@
|
||||
namespace Infrastructure.Models;
|
||||
|
||||
public class D
|
||||
public class ProgramInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络信息
|
||||
/// </summary>
|
||||
public List<NetInfo> NetInfos { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 进程名称
|
||||
/// </summary>
|
||||
public string ProcessName { get; set; }
|
||||
public string ProcessName { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 进程ID
|
||||
@@ -40,7 +35,7 @@ public class D
|
||||
/// <summary>
|
||||
/// 占用内存
|
||||
/// </summary>
|
||||
public string UseMemory { get; set; }
|
||||
public long UseMemory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 线程数
|
||||
@@ -80,7 +75,12 @@ public class D
|
||||
/// <summary>
|
||||
/// 版权
|
||||
/// </summary>
|
||||
public string? Copyright { get; set; }
|
||||
public string? LegalCopyright { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string IconBase64 { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,5 +151,5 @@ public class NetInfo
|
||||
/// <summary>
|
||||
/// 接收字节数
|
||||
/// </summary>
|
||||
public long TotalRecvBytes { get; set; }
|
||||
public long TotalReceiveBytes { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Infrastructure.utils;
|
||||
|
||||
|
||||
public static class IconHelper
|
||||
{
|
||||
[DllImport("Shell32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
|
||||
|
||||
/// <summary>
|
||||
/// 获取 ICON
|
||||
/// </summary>
|
||||
/// <param name="exePath"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetIconBase64(string? exePath)
|
||||
{
|
||||
if (exePath == null && !File.Exists(exePath)) return "";
|
||||
IntPtr hIcon = ExtractIcon(IntPtr.Zero, exePath, 0);
|
||||
if (hIcon == IntPtr.Zero) return "";
|
||||
|
||||
using Icon icon = Icon.FromHandle(hIcon);
|
||||
using Bitmap bmp = icon.ToBitmap();
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
// 保存为 PNG 格式
|
||||
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
|
||||
byte[] bytes = ms.ToArray();
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,27 @@ using Microsoft.Diagnostics.Tracing;
|
||||
using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
|
||||
using Microsoft.Diagnostics.Tracing.Session;
|
||||
|
||||
public class NetUtils
|
||||
public enum TCP_TABLE_CLASS
|
||||
{
|
||||
TCP_TABLE_BASIC_LISTENER,
|
||||
TCP_TABLE_BASIC_CONNECTIONS,
|
||||
TCP_TABLE_BASIC_ALL,
|
||||
TCP_TABLE_OWNER_PID_LISTENER,
|
||||
TCP_TABLE_OWNER_PID_CONNECTIONS,
|
||||
TCP_TABLE_OWNER_PID_ALL, // 使用这个
|
||||
TCP_TABLE_OWNER_MODULE_LISTENER,
|
||||
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
|
||||
TCP_TABLE_OWNER_MODULE_ALL
|
||||
}
|
||||
|
||||
public enum UDP_TABLE_CLASS
|
||||
{
|
||||
UDP_TABLE_BASIC,
|
||||
UDP_TABLE_OWNER_PID,
|
||||
UDP_TABLE_OWNER_MODULE
|
||||
}
|
||||
|
||||
public static class NetUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 联网内容监视
|
||||
@@ -63,19 +83,6 @@ public class NetUtils
|
||||
}
|
||||
}
|
||||
|
||||
private enum TCP_TABLE_CLASS
|
||||
{
|
||||
TCP_TABLE_BASIC_LISTENER,
|
||||
TCP_TABLE_BASIC_CONNECTIONS,
|
||||
TCP_TABLE_BASIC_ALL,
|
||||
TCP_TABLE_OWNER_PID_LISTENER,
|
||||
TCP_TABLE_OWNER_PID_CONNECTIONS,
|
||||
TCP_TABLE_OWNER_PID_ALL, // 我们使用这个
|
||||
TCP_TABLE_OWNER_MODULE_LISTENER,
|
||||
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
|
||||
TCP_TABLE_OWNER_MODULE_ALL
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有连接
|
||||
/// </summary>
|
||||
@@ -87,8 +94,8 @@ public class NetUtils
|
||||
|
||||
try
|
||||
{
|
||||
if (GetExtendedTcpTable(tcpTablePtr, ref buffSize, true, 2, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) ==
|
||||
0)
|
||||
if (GetExtendedTcpTable(tcpTablePtr, ref buffSize, true, 2,
|
||||
TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) == 0)
|
||||
{
|
||||
int rowCount = Marshal.ReadInt32(tcpTablePtr);
|
||||
IntPtr rowPtr = IntPtr.Add(tcpTablePtr, 4);
|
||||
@@ -113,7 +120,11 @@ public class NetUtils
|
||||
}
|
||||
}
|
||||
|
||||
// 网络字节序转主机字节序
|
||||
/// <summary>
|
||||
/// 网络字节序转主机字节序
|
||||
/// </summary>
|
||||
/// <param name="netshort"></param>
|
||||
/// <returns></returns>
|
||||
private static ushort ntohs(ushort netshort) => (ushort)((netshort >> 8) | (netshort << 8));
|
||||
|
||||
[DllImport("iphlpapi.dll", SetLastError = true)]
|
||||
@@ -153,12 +164,6 @@ public class NetUtils
|
||||
UDP_TABLE_CLASS tableClass,
|
||||
uint reserved = 0);
|
||||
|
||||
public enum UDP_TABLE_CLASS
|
||||
{
|
||||
UDP_TABLE_BASIC,
|
||||
UDP_TABLE_OWNER_PID,
|
||||
UDP_TABLE_OWNER_MODULE
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MIB_UDPROW_OWNER_PID
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Infrastructure.utils;
|
||||
|
||||
using Infrastructure.GlobalCaches;
|
||||
using Infrastructure.Models;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
public static class SysInfoUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序自身信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetProgramDiagnostics()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
@@ -53,48 +51,79 @@ public static class SysInfoUtils
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static void InspectProcess(int pid)
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定进程的信息
|
||||
/// </summary>
|
||||
/// <param name="pid"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ExceptionExpand"></exception>
|
||||
public static ProgramInfo InspectProcess(int pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var proc = Process.GetProcessById(pid);
|
||||
|
||||
Console.WriteLine($"进程名称:{proc.ProcessName}");
|
||||
Console.WriteLine($"进程ID:{proc.Id}");
|
||||
Console.WriteLine($"启动时间:{proc.StartTime}");
|
||||
Console.WriteLine($"是否退出:{proc.HasExited}");
|
||||
Console.WriteLine($"退出时间:{proc.ExitTime}");
|
||||
Console.WriteLine($"退出代码:{proc.ExitCode}");
|
||||
Console.WriteLine($"占用内存:{FormatBytes(proc.WorkingSet64)}");
|
||||
Console.WriteLine($"线程数:{proc.Threads.Count}");
|
||||
Console.WriteLine($"主模块路径:{proc.MainModule?.FileName}");
|
||||
Console.WriteLine($"启动文件名:{proc.MainModule?.ModuleName}");
|
||||
var serialize = JsonSerializer.Serialize(proc.MainModule);
|
||||
Console.WriteLine($"YYY:{serialize}");
|
||||
var filePath = proc.MainModule?.FileName;
|
||||
if (filePath != null)
|
||||
{
|
||||
var versionInfo = FileVersionInfo.GetVersionInfo(filePath);
|
||||
#region 检查缓存
|
||||
|
||||
Console.WriteLine($"文件描述:{versionInfo.FileDescription}");
|
||||
Console.WriteLine($"产品名称:{versionInfo.ProductName}");
|
||||
Console.WriteLine($"公司名称:{versionInfo.CompanyName}");
|
||||
Console.WriteLine($"版本号:{versionInfo.FileVersion}");
|
||||
Console.WriteLine($"版权:{versionInfo.LegalCopyright}");
|
||||
var serialize1 = JsonSerializer.Serialize(versionInfo);
|
||||
|
||||
Console.WriteLine($"XXX:{serialize1}");
|
||||
var pck = new ProcessCache.ProcessCacheKey(pid, proc.StartTime);
|
||||
var programInfo = ProcessCache.Instance.Get(pck);
|
||||
if (programInfo != null)
|
||||
{
|
||||
return programInfo;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取进程信息
|
||||
|
||||
var exeInfo = new ProgramInfo
|
||||
{
|
||||
ProcessName = proc.ProcessName,
|
||||
ProcessId = proc.Id,
|
||||
StartTime = proc.StartTime,
|
||||
HasExited = proc.HasExited,
|
||||
ExitTime = proc.ExitTime,
|
||||
ExitCode = proc.ExitCode,
|
||||
UseMemory = proc.WorkingSet64,
|
||||
ThreadCount = proc.Threads.Count,
|
||||
MainModulePath = proc.MainModule?.FileName,
|
||||
MainModuleName = proc.MainModule?.ModuleName
|
||||
};
|
||||
|
||||
// MainModule 是一个涉及 native 调用的属性,不建议频繁调用,尤其在枚举大量进程时可能影响性能。
|
||||
|
||||
if (exeInfo.MainModulePath != null)
|
||||
{
|
||||
var versionInfo = FileVersionInfo.GetVersionInfo(exeInfo.MainModulePath);
|
||||
|
||||
exeInfo.FileDescription = versionInfo.FileDescription;
|
||||
exeInfo.ProductName = versionInfo.ProductName;
|
||||
exeInfo.CompanyName = versionInfo.CompanyName;
|
||||
exeInfo.Version = versionInfo.FileVersion;
|
||||
exeInfo.LegalCopyright = versionInfo.LegalCopyright;
|
||||
}
|
||||
|
||||
// 获取软件 Icon 【不一定存在】
|
||||
var iconBase64 = IconHelper.GetIconBase64(exeInfo.MainModulePath);
|
||||
exeInfo.IconBase64 = iconBase64;
|
||||
|
||||
#endregion
|
||||
|
||||
ProcessCache.Instance.Set(pck, exeInfo);
|
||||
return exeInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
// 只捕获能遇见的异常
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Console.WriteLine($"获取进程信息失败:{ex.Message}");
|
||||
throw ExceptionEnum.ProcessGetException;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string FormatBytes(long bytes)
|
||||
{
|
||||
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
|
||||
string[] sizes = ["B", "KB", "MB", "GB", "TB"];
|
||||
double len = bytes;
|
||||
int order = 0;
|
||||
while (len >= 1024 && order < sizes.Length - 1)
|
||||
|
||||
@@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastru
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Application\Application.csproj", "{399AF9C6-701E-49B4-B165-FA9C7B7BFAF5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinDivertNet", "WinDivertNet\WinDivertNet.csproj", "{CE7B8A5A-BD55-4945-A844-571DEDB08942}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -30,5 +32,9 @@ Global
|
||||
{399AF9C6-701E-49B4-B165-FA9C7B7BFAF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{399AF9C6-701E-49B4-B165-FA9C7B7BFAF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{399AF9C6-701E-49B4-B165-FA9C7B7BFAF5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CE7B8A5A-BD55-4945-A844-571DEDB08942}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CE7B8A5A-BD55-4945-A844-571DEDB08942}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CE7B8A5A-BD55-4945-A844-571DEDB08942}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CE7B8A5A-BD55-4945-A844-571DEDB08942}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,5 +1,6 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileVersionInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7fad91e527c1434bb313ddbc78144605b8a0_003F3f_003F911bc64d_003FFileVersionInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFile_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F71_003F40854420_003FFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKernelTraceEventParser_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F24_003Fd19d02f2_003FKernelTraceEventParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetworkInterface_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9c72a65889eb40ae9d8e0f130d1572e0268a0_003F34_003F49f5e6ff_003FNetworkInterface_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AProcess_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4a26a752ec6249c4a090905d31c0cdfa528a0_003F8f_003F7037e590_003FProcess_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="WinDivert.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WinDivert64.sys" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
@@ -22,4 +29,13 @@
|
||||
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="WinDivert64.sys">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="WinDivert.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -3,6 +3,7 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Windows;
|
||||
using Infrastructure.utils;
|
||||
using WinDivertNet.WinDivertWrapper;
|
||||
|
||||
namespace Shell.Views;
|
||||
|
||||
@@ -56,6 +57,9 @@ public partial class WebPanel : UserControl
|
||||
case "GetAllTcpConnections":
|
||||
NetUtils.GetAllTcpConnections();
|
||||
break;
|
||||
case "PacketSnifferStart":
|
||||
PacketSniffer.Start();
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("没有任何函数被触发...");
|
||||
break;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
using System.Text;
|
||||
using WinDivertNet.WinDivertWrapper;
|
||||
|
||||
namespace WinDivertNet;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("WinDivert 捕获启动...");
|
||||
PacketSniffer.Start();
|
||||
}
|
||||
|
||||
static void Main1(string[] args)
|
||||
{
|
||||
// 创建 WinDivert 控制器
|
||||
using (WinDivertController controller = new WinDivertController())
|
||||
{
|
||||
// 检查过滤器语法
|
||||
var checkResult = controller.CheckFilter("tcp.DstPort == 80");
|
||||
if (!checkResult.IsValid)
|
||||
{
|
||||
Console.WriteLine($"过滤器语法错误: {checkResult.ErrorMessage}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 打开 WinDivert 句柄
|
||||
bool success = controller.Open(
|
||||
"tcp.DstPort == 80", // 过滤器
|
||||
WinDivert.WINDIVERT_LAYER_NETWORK, // 网络层
|
||||
0, // 优先级
|
||||
WinDivert.WINDIVERT_FLAG_SNIFF // 嗅探模式
|
||||
);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Console.WriteLine("打开 WinDivert 失败!");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("开始监听 HTTP 流量...");
|
||||
Console.WriteLine("按 ESC 键退出");
|
||||
|
||||
// 设置队列长度
|
||||
controller.SetParam(WinDivert.WINDIVERT_PARAM_QUEUE_LENGTH, 8192);
|
||||
|
||||
byte[] packet = new byte[65535];
|
||||
WinDivert.WINDIVERT_ADDRESS addr = new WinDivert.WINDIVERT_ADDRESS();
|
||||
|
||||
// 创建线程处理数据包
|
||||
Thread thread = new Thread(() =>
|
||||
{
|
||||
while (controller.IsValid)
|
||||
{
|
||||
uint readLen = controller.Receive(packet, ref addr);
|
||||
if (readLen > 0)
|
||||
{
|
||||
// 解析数据包
|
||||
PacketHeaders headers = controller.ParsePacket(packet);
|
||||
if (headers.Success)
|
||||
{
|
||||
if (headers.HasTcpHeader && headers.HasIpHeader)
|
||||
{
|
||||
string srcIp = WinDivert.FormatIPv4Address(headers.IpHeader.SrcAddr);
|
||||
string dstIp = WinDivert.FormatIPv4Address(headers.IpHeader.DstAddr);
|
||||
ushort srcPort = headers.TcpHeader.SrcPort;
|
||||
ushort dstPort = headers.TcpHeader.DstPort;
|
||||
|
||||
Console.WriteLine($"捕获到 TCP 数据包: {srcIp}:{srcPort} -> {dstIp}:{dstPort}");
|
||||
|
||||
// 如果有数据,则尝试输出前 100 个字节
|
||||
if (headers.Data != null && headers.DataLength > 0)
|
||||
{
|
||||
int len = (int)Math.Min(headers.DataLength, 100);
|
||||
string data = Encoding.ASCII.GetString(headers.Data, 0, len);
|
||||
Console.WriteLine($"数据内容: {data}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
|
||||
// 等待 ESC 键退出
|
||||
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
|
||||
{
|
||||
}
|
||||
|
||||
// 关闭 WinDivert
|
||||
controller.Close();
|
||||
Console.WriteLine("监听结束!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="WinDivert\WinDivert.dll" />
|
||||
<None Remove="WinDivert\WinDivert64.sys" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,89 @@
|
||||
namespace WinDivertNet.WinDivertWrapper;
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public static class PacketSniffer
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
Console.WriteLine($"进入 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)
|
||||
{
|
||||
Console.WriteLine($"接收数据包时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void ParsePacketAndLog(byte[] buffer, uint length, WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
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]}";
|
||||
|
||||
Console.WriteLine($"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
|
||||
{
|
||||
Console.WriteLine($"TCP: SrcPort={srcPort}, DstPort={dstPort}");
|
||||
}
|
||||
else if (protocol == 17) // UDP
|
||||
{
|
||||
Console.WriteLine($"UDP: SrcPort={srcPort}, DstPort={dstPort}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (version == 6 && length >= 40) // IPv6 (头部固定 40 字节)
|
||||
{
|
||||
// IPv6 解析代码...
|
||||
// 这里略过,需要时可以添加
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"解析数据包时出错: {ex.Message}");
|
||||
}
|
||||
} }
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
namespace WinDivertNet.WinDivertWrapper;
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// WinDivert 的 C# 封装类
|
||||
/// </summary>
|
||||
public static class WinDivert
|
||||
{
|
||||
#region 常量定义
|
||||
|
||||
// 层级常量
|
||||
public const uint WINDIVERT_LAYER_NETWORK = 0;
|
||||
public const uint WINDIVERT_LAYER_NETWORK_FORWARD = 1;
|
||||
public const uint WINDIVERT_LAYER_FLOW = 2;
|
||||
public const uint WINDIVERT_LAYER_SOCKET = 3;
|
||||
public const uint WINDIVERT_LAYER_REFLECT = 4;
|
||||
|
||||
// 标志常量
|
||||
public const ulong WINDIVERT_FLAG_SNIFF = 1;
|
||||
public const ulong WINDIVERT_FLAG_DROP = 2;
|
||||
public const ulong WINDIVERT_FLAG_RECV_ONLY = 4;
|
||||
public const ulong WINDIVERT_FLAG_SEND_ONLY = 8;
|
||||
public const ulong WINDIVERT_FLAG_NO_INSTALL = 16;
|
||||
public const ulong WINDIVERT_FLAG_FRAGMENTS = 32;
|
||||
public const ulong WINDIVERT_FLAG_RECV_PARTIAL = 64;
|
||||
public const ulong WINDIVERT_FLAG_SEND_PARTIAL = 128;
|
||||
|
||||
// 事件常量
|
||||
public const byte WINDIVERT_EVENT_NETWORK_PACKET = 0;
|
||||
public const byte WINDIVERT_EVENT_FLOW_ESTABLISHED = 1;
|
||||
public const byte WINDIVERT_EVENT_FLOW_DELETED = 2;
|
||||
public const byte WINDIVERT_EVENT_SOCKET_BIND = 3;
|
||||
public const byte WINDIVERT_EVENT_SOCKET_CONNECT = 4;
|
||||
public const byte WINDIVERT_EVENT_SOCKET_LISTEN = 5;
|
||||
public const byte WINDIVERT_EVENT_SOCKET_ACCEPT = 6;
|
||||
public const byte WINDIVERT_EVENT_REFLECT_OPEN = 7;
|
||||
public const byte WINDIVERT_EVENT_REFLECT_CLOSE = 8;
|
||||
|
||||
// 方向常量
|
||||
public const byte WINDIVERT_DIRECTION_OUTBOUND = 0;
|
||||
public const byte WINDIVERT_DIRECTION_INBOUND = 1;
|
||||
|
||||
// 参数常量
|
||||
public const int WINDIVERT_PARAM_QUEUE_LENGTH = 0;
|
||||
public const int WINDIVERT_PARAM_QUEUE_TIME = 1;
|
||||
public const int WINDIVERT_PARAM_QUEUE_SIZE = 2;
|
||||
public const int WINDIVERT_PARAM_VERSION_MAJOR = 3;
|
||||
public const int WINDIVERT_PARAM_VERSION_MINOR = 4;
|
||||
|
||||
// 校验和常量
|
||||
public const uint WINDIVERT_HELPER_NO_REPLACE = 0;
|
||||
public const uint WINDIVERT_HELPER_NO_ICMPV6 = 0;
|
||||
public const uint WINDIVERT_HELPER_NO_ICMP = 0;
|
||||
public const uint WINDIVERT_HELPER_NO_TCP = 0;
|
||||
public const uint WINDIVERT_HELPER_NO_UDP = 0;
|
||||
public const uint WINDIVERT_HELPER_NO_IP = 0;
|
||||
public const uint WINDIVERT_HELPER_NO_IPV6 = 0;
|
||||
|
||||
// 优先级范围
|
||||
public const short WINDIVERT_PRIORITY_HIGHEST = 30000;
|
||||
public const short WINDIVERT_PRIORITY_LOWEST = -30000;
|
||||
public const short WINDIVERT_PRIORITY_DEFAULT = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 结构体定义
|
||||
|
||||
/// <summary>
|
||||
/// WinDivert 地址结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_ADDRESS
|
||||
{
|
||||
public long Timestamp; // 时间戳
|
||||
public byte Layer; // 层级
|
||||
public byte Event; // 事件
|
||||
public byte Flags; // 标志
|
||||
public byte Reserved1; // 保留
|
||||
public uint IfIdx; // 接口索引
|
||||
public uint SubIfIdx; // 子接口索引
|
||||
public byte Direction; // 方向
|
||||
public byte Reserved2; // 保留
|
||||
public ulong Reserved3; // 保留
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IPv4 头结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_IPHDR
|
||||
{
|
||||
public byte HdrLength4; // 组合字段: 版本 (4 bits) + 头长度 (4 bits)
|
||||
public byte TOS; // 服务类型
|
||||
public ushort Length; // 总长度
|
||||
public ushort Id; // 标识
|
||||
public ushort FragOff0; // 组合字段: 标志 (3 bits) + 分片偏移 (13 bits)
|
||||
public byte TTL; // 生存时间
|
||||
public byte Protocol; // 协议
|
||||
public ushort Checksum; // 检验和
|
||||
public uint SrcAddr; // 源地址
|
||||
public uint DstAddr; // 目标地址
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IPv6 头结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_IPV6HDR
|
||||
{
|
||||
public uint FlowLabel0; // 组合字段: 版本 (4 bits) + 通信类 (8 bits) + 流标签 (20 bits)
|
||||
public ushort Length; // 有效载荷长度
|
||||
public byte NextHdr; // 下一个头
|
||||
public byte HopLimit; // 跳数限制
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] SrcAddr; // 源地址
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] DstAddr; // 目标地址
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TCP 头结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_TCPHDR
|
||||
{
|
||||
public ushort SrcPort; // 源端口
|
||||
public ushort DstPort; // 目标端口
|
||||
public uint SeqNum; // 序列号
|
||||
public uint AckNum; // 确认号
|
||||
public ushort Reserved10; // 组合字段: 数据偏移 (4 bits) + 保留 (6 bits) + 标志 (6 bits)
|
||||
public ushort Window; // 窗口大小
|
||||
public ushort Checksum; // 检验和
|
||||
public ushort UrgPtr; // 紧急指针
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UDP 头结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_UDPHDR
|
||||
{
|
||||
public ushort SrcPort; // 源端口
|
||||
public ushort DstPort; // 目标端口
|
||||
public ushort Length; // 长度
|
||||
public ushort Checksum; // 检验和
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ICMP 头结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_ICMPHDR
|
||||
{
|
||||
public byte Type; // 类型
|
||||
public byte Code; // 代码
|
||||
public ushort Checksum; // 检验和
|
||||
public uint Body; // 消息体
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ICMPv6 头结构
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDIVERT_ICMPV6HDR
|
||||
{
|
||||
public byte Type; // 类型
|
||||
public byte Code; // 代码
|
||||
public ushort Checksum; // 检验和
|
||||
public uint Body; // 消息体
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 原生 API 导入
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr WinDivertOpen(
|
||||
[MarshalAs(UnmanagedType.LPStr)] string filter,
|
||||
uint layer,
|
||||
short priority,
|
||||
ulong flags);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertRecv(
|
||||
IntPtr handle,
|
||||
byte[] pPacket,
|
||||
uint packetLen,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
ref uint readLen);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertRecvEx(
|
||||
IntPtr handle,
|
||||
byte[] pPacket,
|
||||
uint packetLen,
|
||||
uint flags,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
ref uint readLen,
|
||||
IntPtr overlapped);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertSend(
|
||||
IntPtr handle,
|
||||
byte[] pPacket,
|
||||
uint packetLen,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
ref uint writeLen);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertSendEx(
|
||||
IntPtr handle,
|
||||
byte[] pPacket,
|
||||
uint packetLen,
|
||||
uint flags,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
ref uint writeLen,
|
||||
IntPtr overlapped);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertClose(
|
||||
IntPtr handle);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertSetParam(
|
||||
IntPtr handle,
|
||||
int param,
|
||||
ulong value);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertGetParam(
|
||||
IntPtr handle,
|
||||
int param,
|
||||
ref ulong value);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern uint WinDivertHelperCalcChecksums(
|
||||
byte[] pPacket,
|
||||
uint packetLen,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
uint flags);
|
||||
|
||||
// [DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
// public static extern bool WinDivertHelperParsePacket(
|
||||
// byte[] pPacket,
|
||||
// uint packetLen,
|
||||
// ref IntPtr ppIpHdr,
|
||||
// ref IntPtr ppIpv6Hdr,
|
||||
// ref IntPtr ppIcmpHdr,
|
||||
// ref IntPtr ppIcmpv6Hdr,
|
||||
// ref IntPtr ppTcpHdr,
|
||||
// ref IntPtr ppUdpHdr,
|
||||
// ref IntPtr ppData,
|
||||
// ref uint pDataLen);
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperParsePacket(
|
||||
[In] byte[] pPacket,
|
||||
uint packetLen,
|
||||
[Out] out IntPtr ppIpHdr,
|
||||
[Out] out IntPtr ppIpv6Hdr,
|
||||
[Out] out IntPtr ppIcmpHdr,
|
||||
[Out] out IntPtr ppIcmpv6Hdr,
|
||||
[Out] out IntPtr ppTcpHdr,
|
||||
[Out] out IntPtr ppUdpHdr,
|
||||
[Out] out IntPtr ppData,
|
||||
[Out] out uint pDataLen);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperParseIPv4Address(
|
||||
[MarshalAs(UnmanagedType.LPStr)] string str,
|
||||
ref uint pAddr);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperParseIPv6Address(
|
||||
[MarshalAs(UnmanagedType.LPStr)] string str,
|
||||
byte[] pAddr);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperFormatIPv4Address(
|
||||
uint addr,
|
||||
[MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer,
|
||||
uint bufLen);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperFormatIPv6Address(
|
||||
byte[] addr,
|
||||
[MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer,
|
||||
uint bufLen);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperCheckFilter(
|
||||
[MarshalAs(UnmanagedType.LPStr)] string filter,
|
||||
uint layer,
|
||||
[MarshalAs(UnmanagedType.LPStr)] StringBuilder errorStr,
|
||||
uint errorStrLen);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
/// <summary>
|
||||
/// 打开 WinDivert 句柄
|
||||
/// </summary>
|
||||
/// <param name="filter">过滤器表达式</param>
|
||||
/// <param name="layer">层级</param>
|
||||
/// <param name="priority">优先级</param>
|
||||
/// <param name="flags">标志</param>
|
||||
/// <returns>WinDivert 句柄</returns>
|
||||
public static IntPtr Open(string filter, uint layer, short priority, ulong flags) =>
|
||||
WinDivertOpen(filter, layer, priority, flags);
|
||||
|
||||
/// <summary>
|
||||
/// 接收数据包
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="readLen">实际读取长度</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool Recv(IntPtr handle, byte[] buffer, uint len, ref WINDIVERT_ADDRESS addr, ref uint readLen) =>
|
||||
WinDivertRecv(handle, buffer, len, ref addr, ref readLen);
|
||||
|
||||
/// <summary>
|
||||
/// 扩展接收数据包
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
/// <param name="flags">标志</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="readLen">实际读取长度</param>
|
||||
/// <param name="overlapped">重叠 I/O 结构</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool RecvEx(IntPtr handle, byte[] buffer, uint len, uint flags, ref WINDIVERT_ADDRESS addr,
|
||||
ref uint readLen, IntPtr overlapped) =>
|
||||
WinDivertRecvEx(handle, buffer, len, flags, ref addr, ref readLen, overlapped);
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据包
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="writeLen">实际写入长度</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool Send(IntPtr handle, byte[] buffer, uint len, ref WINDIVERT_ADDRESS addr, ref uint writeLen) =>
|
||||
WinDivertSend(handle, buffer, len, ref addr, ref writeLen);
|
||||
|
||||
/// <summary>
|
||||
/// 扩展发送数据包
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
/// <param name="flags">标志</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="writeLen">实际写入长度</param>
|
||||
/// <param name="overlapped">重叠 I/O 结构</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool SendEx(IntPtr handle, byte[] buffer, uint len, uint flags, ref WINDIVERT_ADDRESS addr,
|
||||
ref uint writeLen, IntPtr overlapped) =>
|
||||
WinDivertSendEx(handle, buffer, len, flags, ref addr, ref writeLen, overlapped);
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 WinDivert 句柄
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool Close(IntPtr handle) =>
|
||||
WinDivertClose(handle);
|
||||
|
||||
/// <summary>
|
||||
/// 设置参数
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <param name="param">参数类型</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool SetParam(IntPtr handle, int param, ulong value) =>
|
||||
WinDivertSetParam(handle, param, value);
|
||||
|
||||
/// <summary>
|
||||
/// 获取参数
|
||||
/// </summary>
|
||||
/// <param name="handle">WinDivert 句柄</param>
|
||||
/// <param name="param">参数类型</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool GetParam(IntPtr handle, int param, ref ulong value) =>
|
||||
WinDivertGetParam(handle, param, ref value);
|
||||
|
||||
/// <summary>
|
||||
/// 计算校验和
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="flags">标志</param>
|
||||
/// <returns>校验和结果</returns>
|
||||
public static uint CalcChecksums(byte[] buffer, uint len, ref WINDIVERT_ADDRESS addr, uint flags) =>
|
||||
WinDivertHelperCalcChecksums(buffer, len, ref addr, flags);
|
||||
|
||||
/// <summary>
|
||||
/// 解析数据包
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
/// <param name="ppIpHdr">IPv4 头指针</param>
|
||||
/// <param name="ppIpv6Hdr">IPv6 头指针</param>
|
||||
/// <param name="ppIcmpHdr">ICMP 头指针</param>
|
||||
/// <param name="ppIcmpv6Hdr">ICMPv6 头指针</param>
|
||||
/// <param name="ppTcpHdr">TCP 头指针</param>
|
||||
/// <param name="ppUdpHdr">UDP 头指针</param>
|
||||
/// <param name="ppData">数据指针</param>
|
||||
/// <param name="pDataLen">数据长度</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool ParsePacket(byte[] buffer, uint len, ref IntPtr ppIpHdr, ref IntPtr ppIpv6Hdr,
|
||||
ref IntPtr ppIcmpHdr, ref IntPtr ppIcmpv6Hdr, ref IntPtr ppTcpHdr, ref IntPtr ppUdpHdr,
|
||||
ref IntPtr ppData, ref uint pDataLen) =>
|
||||
WinDivertHelperParsePacket(buffer, len, out ppIpHdr, out ppIpv6Hdr, out ppIcmpHdr, out ppIcmpv6Hdr,
|
||||
out ppTcpHdr, out ppUdpHdr, out ppData, out pDataLen);
|
||||
|
||||
/// <summary>
|
||||
/// 解析 IPv4 地址
|
||||
/// </summary>
|
||||
/// <param name="str">IP 地址字符串</param>
|
||||
/// <param name="pAddr">地址结果</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool ParseIPv4Address(string str, ref uint pAddr) =>
|
||||
WinDivertHelperParseIPv4Address(str, ref pAddr);
|
||||
|
||||
/// <summary>
|
||||
/// 解析 IPv6 地址
|
||||
/// </summary>
|
||||
/// <param name="str">IP 地址字符串</param>
|
||||
/// <param name="pAddr">地址结果</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool ParseIPv6Address(string str, byte[] pAddr) =>
|
||||
WinDivertHelperParseIPv6Address(str, pAddr);
|
||||
|
||||
/// <summary>
|
||||
/// 格式化 IPv4 地址
|
||||
/// </summary>
|
||||
/// <param name="addr">IP 地址</param>
|
||||
/// <returns>格式化后的字符串</returns>
|
||||
public static string FormatIPv4Address(uint addr)
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder(16);
|
||||
if (WinDivertHelperFormatIPv4Address(addr, buffer, 16))
|
||||
{
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 格式化 IPv6 地址
|
||||
/// </summary>
|
||||
/// <param name="addr">IP 地址</param>
|
||||
/// <returns>格式化后的字符串</returns>
|
||||
public static string FormatIPv6Address(byte[] addr)
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder(46);
|
||||
if (WinDivertHelperFormatIPv6Address(addr, buffer, 46))
|
||||
{
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查过滤器语法
|
||||
/// </summary>
|
||||
/// <param name="filter">过滤器表达式</param>
|
||||
/// <param name="layer">层级</param>
|
||||
/// <param name="errorStr">错误信息</param>
|
||||
/// <param name="errorStrLen">错误信息长度</param>
|
||||
/// <returns>是否有效</returns>
|
||||
public static bool CheckFilter(string filter, uint layer, StringBuilder errorStr, uint errorStrLen) =>
|
||||
WinDivertHelperCheckFilter(filter, layer, errorStr, errorStrLen);
|
||||
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PacketHeaders
|
||||
{
|
||||
public IntPtr IpHdr;
|
||||
public IntPtr Ipv6Hdr;
|
||||
public IntPtr IcmpHdr;
|
||||
public IntPtr Icmpv6Hdr;
|
||||
public IntPtr TcpHdr;
|
||||
public IntPtr UdpHdr;
|
||||
public IntPtr Data;
|
||||
public uint DataLen;
|
||||
}
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperParsePacketEx(
|
||||
[In] byte[] pPacket,
|
||||
uint packetLen,
|
||||
ref PacketHeaders headers);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,561 @@
|
||||
namespace WinDivertNet.WinDivertWrapper;
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// WinDivert 高级封装类
|
||||
/// </summary>
|
||||
public class WinDivertController : IDisposable
|
||||
{
|
||||
private IntPtr _handle;
|
||||
private bool _disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// 获取句柄是否有效
|
||||
/// </summary>
|
||||
public bool IsValid => _handle != IntPtr.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public WinDivertController()
|
||||
{
|
||||
_handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 析构函数
|
||||
/// </summary>
|
||||
~WinDivertController()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 WinDivert 句柄
|
||||
/// </summary>
|
||||
/// <param name="filter">过滤器表达式</param>
|
||||
/// <param name="layer">层级</param>
|
||||
/// <param name="priority">优先级</param>
|
||||
/// <param name="flags">标志</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool Open(string filter, uint layer = WinDivert.WINDIVERT_LAYER_NETWORK,
|
||||
short priority = WinDivert.WINDIVERT_PRIORITY_DEFAULT,
|
||||
ulong flags = 0)
|
||||
{
|
||||
if (IsValid)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
_handle = WinDivert.Open(filter, layer, priority, flags);
|
||||
return IsValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 WinDivert 句柄
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (IsValid)
|
||||
{
|
||||
WinDivert.Close(_handle);
|
||||
_handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收数据包
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <returns>实际读取的字节数,失败返回 0</returns>
|
||||
public uint Receive(byte[] buffer, ref WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
if (!IsValid || buffer == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint readLen = 0;
|
||||
if (WinDivert.Recv(_handle, buffer, (uint)buffer.Length, ref addr, ref readLen))
|
||||
{
|
||||
return readLen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步接收数据包
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <returns>实际读取的字节数的任务</returns>
|
||||
public Task<uint> ReceiveAsync(byte[] buffer, WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
return Task.Run(() => Receive(buffer, ref addr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据包
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <returns>实际写入的字节数,失败返回 0</returns>
|
||||
public uint Send(byte[] buffer, ref WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
if (!IsValid || buffer == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint writeLen = 0;
|
||||
if (WinDivert.Send(_handle, buffer, (uint)buffer.Length, ref addr, ref writeLen))
|
||||
{
|
||||
return writeLen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送数据包
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <returns>实际写入的字节数的任务</returns>
|
||||
public Task<uint> SendAsync(byte[] buffer, WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
return Task.Run(() => Send(buffer, ref addr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置参数
|
||||
/// </summary>
|
||||
/// <param name="param">参数类型</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool SetParam(int param, ulong value)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return WinDivert.SetParam(_handle, param, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取参数
|
||||
/// </summary>
|
||||
/// <param name="param">参数类型</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool GetParam(int param, ref ulong value)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return WinDivert.GetParam(_handle, param, ref value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验包数据的校验和
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="flags">标志</param>
|
||||
/// <returns>校验和结果</returns>
|
||||
public uint CalcChecksums(byte[] buffer, ref WinDivert.WINDIVERT_ADDRESS addr, uint flags = 0)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return WinDivert.CalcChecksums(buffer, (uint)buffer.Length, ref addr, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查过滤器语法
|
||||
/// </summary>
|
||||
/// <param name="filter">过滤器表达式</param>
|
||||
/// <param name="layer">层级</param>
|
||||
/// <returns>检查结果和错误信息</returns>
|
||||
public (bool IsValid, string ErrorMessage) CheckFilter(string filter,
|
||||
uint layer = WinDivert.WINDIVERT_LAYER_NETWORK)
|
||||
{
|
||||
StringBuilder errorStr = new StringBuilder(256);
|
||||
bool isValid = WinDivert.CheckFilter(filter, layer, errorStr, 256);
|
||||
return (isValid, errorStr.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析数据包
|
||||
/// </summary>
|
||||
/// <param name="packet">数据包</param>
|
||||
/// <returns>解析结果</returns>
|
||||
public PacketHeaders ParsePacket(byte[] packet)
|
||||
{
|
||||
if (packet == null)
|
||||
{
|
||||
return new PacketHeaders();
|
||||
}
|
||||
|
||||
IntPtr ppIpHdr = IntPtr.Zero;
|
||||
IntPtr ppIpv6Hdr = IntPtr.Zero;
|
||||
IntPtr ppIcmpHdr = IntPtr.Zero;
|
||||
IntPtr ppIcmpv6Hdr = IntPtr.Zero;
|
||||
IntPtr ppTcpHdr = IntPtr.Zero;
|
||||
IntPtr ppUdpHdr = IntPtr.Zero;
|
||||
IntPtr ppData = IntPtr.Zero;
|
||||
uint pDataLen = 0;
|
||||
|
||||
bool success = WinDivert.ParsePacket(packet, (uint)packet.Length, ref ppIpHdr, ref ppIpv6Hdr,
|
||||
ref ppIcmpHdr, ref ppIcmpv6Hdr, ref ppTcpHdr, ref ppUdpHdr, ref ppData, ref pDataLen);
|
||||
|
||||
PacketHeaders headers = new PacketHeaders
|
||||
{
|
||||
Success = success,
|
||||
DataLength = pDataLen
|
||||
};
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (ppIpHdr != IntPtr.Zero)
|
||||
{
|
||||
headers.IpHeader = Marshal.PtrToStructure<WinDivert.WINDIVERT_IPHDR>(ppIpHdr);
|
||||
headers.HasIpHeader = true;
|
||||
}
|
||||
|
||||
if (ppIpv6Hdr != IntPtr.Zero)
|
||||
{
|
||||
headers.Ipv6Header = Marshal.PtrToStructure<WinDivert.WINDIVERT_IPV6HDR>(ppIpv6Hdr);
|
||||
headers.HasIpv6Header = true;
|
||||
}
|
||||
|
||||
if (ppTcpHdr != IntPtr.Zero)
|
||||
{
|
||||
headers.TcpHeader = Marshal.PtrToStructure<WinDivert.WINDIVERT_TCPHDR>(ppTcpHdr);
|
||||
headers.HasTcpHeader = true;
|
||||
}
|
||||
|
||||
if (ppUdpHdr != IntPtr.Zero)
|
||||
{
|
||||
headers.UdpHeader = Marshal.PtrToStructure<WinDivert.WINDIVERT_UDPHDR>(ppUdpHdr);
|
||||
headers.HasUdpHeader = true;
|
||||
}
|
||||
|
||||
if (ppIcmpHdr != IntPtr.Zero)
|
||||
{
|
||||
headers.IcmpHeader = Marshal.PtrToStructure<WinDivert.WINDIVERT_ICMPHDR>(ppIcmpHdr);
|
||||
headers.HasIcmpHeader = true;
|
||||
}
|
||||
|
||||
if (ppIcmpv6Hdr != IntPtr.Zero)
|
||||
{
|
||||
headers.Icmpv6Header = Marshal.PtrToStructure<WinDivert.WINDIVERT_ICMPV6HDR>(ppIcmpv6Hdr);
|
||||
headers.HasIcmpv6Header = true;
|
||||
}
|
||||
|
||||
if (ppData != IntPtr.Zero && pDataLen > 0)
|
||||
{
|
||||
headers.Data = new byte[pDataLen];
|
||||
Marshal.Copy(ppData, headers.Data, 0, (int)pDataLen);
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改包的源 IP 地址
|
||||
/// </summary>
|
||||
/// <param name="packet">数据包</param>
|
||||
/// <param name="sourceIp">新的源 IP 地址</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ModifySourceIpv4Address(byte[] packet, string sourceIp)
|
||||
{
|
||||
if (packet == null || string.IsNullOrEmpty(sourceIp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketHeaders headers = ParsePacket(packet);
|
||||
if (!headers.Success || !headers.HasIpHeader)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint addr = 0;
|
||||
if (!WinDivert.ParseIPv4Address(sourceIp, ref addr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算 IP 头的偏移量
|
||||
int ipHdrOffset = Marshal.SizeOf<WinDivert.WINDIVERT_IPHDR>();
|
||||
|
||||
// 修改源 IP 地址
|
||||
byte[] addrBytes = BitConverter.GetBytes(addr);
|
||||
Array.Copy(addrBytes, 0, packet, ipHdrOffset - 8, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改包的目标 IP 地址
|
||||
/// </summary>
|
||||
/// <param name="packet">数据包</param>
|
||||
/// <param name="destinationIp">新的目标 IP 地址</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ModifyDestinationIpv4Address(byte[] packet, string destinationIp)
|
||||
{
|
||||
if (packet == null || string.IsNullOrEmpty(destinationIp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketHeaders headers = ParsePacket(packet);
|
||||
if (!headers.Success || !headers.HasIpHeader)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint addr = 0;
|
||||
if (!WinDivert.ParseIPv4Address(destinationIp, ref addr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算 IP 头的偏移量
|
||||
int ipHdrOffset = Marshal.SizeOf<WinDivert.WINDIVERT_IPHDR>();
|
||||
|
||||
// 修改目标 IP 地址
|
||||
byte[] addrBytes = BitConverter.GetBytes(addr);
|
||||
Array.Copy(addrBytes, 0, packet, ipHdrOffset - 4, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改包的源端口
|
||||
/// </summary>
|
||||
/// <param name="packet">数据包</param>
|
||||
/// <param name="sourcePort">新的源端口</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ModifySourcePort(byte[] packet, ushort sourcePort)
|
||||
{
|
||||
if (packet == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketHeaders headers = ParsePacket(packet);
|
||||
if (!headers.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset = -1;
|
||||
|
||||
if (headers.HasTcpHeader)
|
||||
{
|
||||
// 计算 TCP 头的偏移量(简化计算,实际应该考虑 IP 选项)
|
||||
offset = (headers.HasIpHeader ? 20 : 0) + (headers.HasIpv6Header ? 40 : 0);
|
||||
}
|
||||
else if (headers.HasUdpHeader)
|
||||
{
|
||||
// 计算 UDP 头的偏移量(简化计算,实际应该考虑 IP 选项)
|
||||
offset = (headers.HasIpHeader ? 20 : 0) + (headers.HasIpv6Header ? 40 : 0);
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 修改源端口
|
||||
byte[] portBytes = BitConverter.GetBytes(sourcePort);
|
||||
Array.Copy(portBytes, 0, packet, offset, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改包的目标端口
|
||||
/// </summary>
|
||||
/// <param name="packet">数据包</param>
|
||||
/// <param name="destinationPort">新的目标端口</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ModifyDestinationPort(byte[] packet, ushort destinationPort)
|
||||
{
|
||||
if (packet == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketHeaders headers = ParsePacket(packet);
|
||||
if (!headers.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset = -1;
|
||||
|
||||
if (headers.HasTcpHeader)
|
||||
{
|
||||
// 计算 TCP 头的偏移量(简化计算,实际应该考虑 IP 选项)
|
||||
offset = (headers.HasIpHeader ? 20 : 0) + (headers.HasIpv6Header ? 40 : 0) + 2;
|
||||
}
|
||||
else if (headers.HasUdpHeader)
|
||||
{
|
||||
// 计算 UDP 头的偏移量(简化计算,实际应该考虑 IP 选项)
|
||||
offset = (headers.HasIpHeader ? 20 : 0) + (headers.HasIpv6Header ? 40 : 0) + 2;
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 修改目标端口
|
||||
byte[] portBytes = BitConverter.GetBytes(destinationPort);
|
||||
Array.Copy(portBytes, 0, packet, offset, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新计算包的校验和
|
||||
/// </summary>
|
||||
/// <param name="packet">数据包</param>
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool RecalculateChecksums(byte[] packet, ref WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
if (packet == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint result = WinDivert.CalcChecksums(packet, (uint)packet.Length, ref addr, 0);
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
/// <param name="disposing">是否为显式释放</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// 释放托管资源
|
||||
}
|
||||
|
||||
// 释放非托管资源
|
||||
Close();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 数据包头信息
|
||||
/// </summary>
|
||||
public class PacketHeaders
|
||||
{
|
||||
/// <summary>
|
||||
/// 解析是否成功
|
||||
/// </summary>
|
||||
public bool Success { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含 IPv4 头
|
||||
/// </summary>
|
||||
public bool HasIpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含 IPv6 头
|
||||
/// </summary>
|
||||
public bool HasIpv6Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含 TCP 头
|
||||
/// </summary>
|
||||
public bool HasTcpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含 UDP 头
|
||||
/// </summary>
|
||||
public bool HasUdpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含 ICMP 头
|
||||
/// </summary>
|
||||
public bool HasIcmpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含 ICMPv6 头
|
||||
/// </summary>
|
||||
public bool HasIcmpv6Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IPv4 头
|
||||
/// </summary>
|
||||
public WinDivert.WINDIVERT_IPHDR IpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IPv6 头
|
||||
/// </summary>
|
||||
public WinDivert.WINDIVERT_IPV6HDR Ipv6Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TCP 头
|
||||
/// </summary>
|
||||
public WinDivert.WINDIVERT_TCPHDR TcpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// UDP 头
|
||||
/// </summary>
|
||||
public WinDivert.WINDIVERT_UDPHDR UdpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICMP 头
|
||||
/// </summary>
|
||||
public WinDivert.WINDIVERT_ICMPHDR IcmpHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICMPv6 头
|
||||
/// </summary>
|
||||
public WinDivert.WINDIVERT_ICMPV6HDR Icmpv6Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据部分
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据长度
|
||||
/// </summary>
|
||||
public uint DataLength { get; set; }
|
||||
}
|
||||
Reference in new issue
Block a user