C# C中的风之河

C# C中的风之河,c#,c,pinvoke,unmanaged-memory,C#,C,Pinvoke,Unmanaged Memory,我想用C代码调用5个WinDivert函数,第一个反射:PInvoke以下是签名: internal enum WINDIVERT_LAYER { WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ WINDIVERT_LAYER_NETWORK_FORWARD = 1 /* Network layer (forwarded packets) */

我想用C代码调用5个WinDivert函数,第一个反射:PInvoke以下是签名:

        internal enum WINDIVERT_LAYER
        {
            WINDIVERT_LAYER_NETWORK = 0,        /* Network layer. */
            WINDIVERT_LAYER_NETWORK_FORWARD = 1 /* Network layer (forwarded packets) */
        }

        internal const UInt64 WINDIVERT_FLAG_SNIFF = 1;

        /*
         * typedef struct
            {
                UINT32 IfIdx;
                UINT32 SubIfIdx;
                UINT8  Direction;
            } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
         * */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal struct WINDIVERT_ADDRESS
        {
            UInt32 IfIdx;
            UInt32 SubIfIdx;
            byte  Direction;
        }


        /*
         * typedef struct
            {
                UINT8  HdrLength:4;
                UINT8  Version:4;
                UINT8  TOS;
                UINT16 Length;
                UINT16 Id;
                UINT16 FragOff0;
                UINT8  TTL;
                UINT8  Protocol;
                UINT16 Checksum;
                UINT32 SrcAddr;
                UINT32 DstAddr;
            } WINDIVERT_IPHDR, *PWINDIVERT_IPHDR;
         * */

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal struct WINDIVERT_IPHDR
        {
            byte  HdrLengthAndVersion; 
            byte  TOS;
            UInt16 Length;
            UInt16 Id;
            UInt16 FragOff0;
            byte  TTL;
            byte  Protocol;
            UInt16 Checksum;
            UInt32 SrcAddr;
            UInt32 DstAddr;
        }


        /*
         * typedef struct
            {
                UINT16 SrcPort;
                UINT16 DstPort;
                UINT16 Length;
                UINT16 Checksum;
            } WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
         * */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal struct WINDIVERT_UDPHDR
        {
            UInt16 SrcPort;
            UInt16 DstPort;
            UInt16 Length;
            UInt16 Checksum;
        }

        /*
         * HANDLE WinDivertOpen(
                __in const char *filter,
                __in WINDIVERT_LAYER layer,
                __in INT16 priority,
                __in UINT64 flags
            );
         * */
        [DllImport("WinDivert.dll", EntryPoint = "WinDivertOpen", SetLastError = true, CharSet = CharSet.Auto, 
            ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr WinDivertOpen(
            [MarshalAs(UnmanagedType.LPStr)] string filter, 
            WINDIVERT_LAYER layer,
            Int16 priority,
            UInt64 flags);


        /*
         * BOOL WinDivertClose(
                __in HANDLE handle
            );
         * */
        [DllImport("WinDivert.dll", EntryPoint = "WinDivertClose", SetLastError = true, CharSet = CharSet.Auto,
            ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        [return:MarshalAs(UnmanagedType.Bool)]
        internal static extern bool WinDivertClose(IntPtr handle);

        /*
         * BOOL WinDivertRecv(
                __in HANDLE handle,
                __out PVOID pPacket,
                __in UINT packetLen,
                __out_opt PWINDIVERT_ADDRESS pAddr,
                __out_opt UINT *recvLen
            );
         * */
        [DllImport("WinDivert.dll", EntryPoint = "WinDivertRecv", SetLastError = true, CharSet = CharSet.Auto, 
            ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool WinDivertRecv(IntPtr handle, out IntPtr pPacket, uint packetLen, [Optional] out IntPtr pAddr, [Optional] out uint readLen);



        /*
         * 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
            );
         * */
        [DllImport("WinDivert.dll", EntryPoint = "WinDivertHelperParsePacket", SetLastError = true, CharSet = CharSet.Auto,
            ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool WinDivertHelperParsePacket(IntPtr pPacket, uint packetLen, [Optional] out IntPtr ppIpHdr, [Optional] out IntPtr ppIpv6Hdr,
           [Optional] out IntPtr ppIcmpHdr, [Optional] out IntPtr ppTcpHdr, [Optional] out IntPtr ppUdpHdr, [Optional] out IntPtr ppData, 
            [Optional]out uint pDataLen);

        /*
         * BOOL WinDivertSend(
                __in HANDLE handle,
                __in PVOID pPacket,
                __in UINT packetLen,
                __in PWINDIVERT_ADDRESS pAddr,
                __out_opt UINT *sendLen
            );
         * */
        [DllImport("WinDivert.dll", EntryPoint = "WinDivertSend", SetLastError = true, CharSet = CharSet.Auto,
            ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool WinDivertSend(IntPtr handle, IntPtr pPacket, uint packetLen, IntPtr pAddr, [Optional] out uint sendLen);
在调用WinDivertOpen、WinDivertClose和WinDivertRecv时,我已成功避免了87=ERROR\u INVALID\u参数、998=ERROR\u NOACCESS错误,但我仍然获得System.AccessViolationException:尝试读取或写入受保护内存。当试图调用WinDiverThePerParsePacket时,这通常表示其他内存已损坏,998=错误\u未访问

代码如下:

static void Main(string[] args)
    {
        const uint MAXBUF = 0xFFFF;
        IntPtr handle;
        IntPtr addr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.WINDIVERT_ADDRESS)));
        IntPtr packet = Marshal.AllocHGlobal((int)MAXBUF);
        uint packetLen;
        IntPtr ip_header = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.WINDIVERT_IPHDR)));
        IntPtr udp_header = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.WINDIVERT_UDPHDR)));
        IntPtr payload;
        uint payload_len;
        uint sendLen;
        IntPtr opt_param = IntPtr.Zero;
                    byte[] managedPacket;
        IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        handle = NativeMethods.WinDivertOpen("udp.DstPort == 53", NativeMethods.WINDIVERT_LAYER.WINDIVERT_LAYER_NETWORK, 404, NativeMethods.WINDIVERT_FLAG_SNIFF);
        if (handle == INVALID_HANDLE_VALUE) Console.WriteLine("open error:" + Marshal.GetLastWin32Error());
        else
        {
            while (true)
            {
                if (!NativeMethods.WinDivertRecv(handle, out packet, MAXBUF, out addr, out packetLen))
                {
                    Console.WriteLine("Recv error:" + Marshal.GetLastWin32Error());
                    continue;
                }
                try
                {
                    managedPacket = new byte[(int)packetLen];
                    Marshal.Copy(packet, managedPacket, 0, (int)packetLen); // causes AccessViolationException

                    Console.WriteLine("---------------------------------");

                    /*for (int i = 0; i < packetLen; i++)
                    {
                        Console.Write("{0:X}", managedPacket[i]);
                    }*/
                    Console.WriteLine("---------------------------------");
                }
                catch(Exception ex)
                {
                    Console.WriteLine("copy error :" + ex.Message);
                }
                    if (!NativeMethods.WinDivertHelperParsePacket(packet, packetLen, out ip_header, out opt_param, out opt_param, out opt_param, out udp_header, out payload, out payload_len)) // causes AccessViolationException
                    {
                        Console.WriteLine("Parse error:" + Marshal.GetLastWin32Error());
                        //continue;
                    }

                if (!NativeMethods.WinDivertSend(handle, packet, packetLen, addr, out sendLen))
                {
                    Console.WriteLine("Send error:" + Marshal.GetLastWin32Error());
                    continue;
                }
            }
            /*if (!NativeMethods.WinDivertClose(handle))
                Console.WriteLine("close error:" + Marshal.GetLastWin32Error());*/
        }



        Console.ReadKey();
    }
以及:

有时在循环中,WinDivRecv也会失败,出现LastWin32Error:6=无效的\u句柄\u值是因为GC弄乱了句柄吗?我尝试了GC.KeepAlivehandle,但它没有改变任何东西

C++\CLI包装器:非托管C DLL和托管C代码之间的桥梁

[以下评论中的建议选项]

我遵循以下步骤:

创建C++/CLI库项目 创建一个封装C函数的本机C++类 创建一个托管C++/CLI类,其字段指向本机类实例,包装所有非托管方法并执行必要的封送处理。 尝试构建==>使用著名的LNK2019和LNK2028失败 我应该添加WinDivert DLL作为引用还是仅添加WinDivert.h?内核驱动程序.sys文件呢?
老实说,这并不比PInvoke简单,但更糟糕的是,我仍然需要对不可blittable的数据类型和结构/枚举定义进行同样的编组

你不想用C++写COM,相信我!另一种选择是C++/CLI Wrapper如果WINDIVERT_IPHDR定义错误,前两个参数被压缩到一个字节中,那么请删除这两个参数并添加一个字节长度的Dversion,要访问长度,可以使用var len=struct.LengthAndVersion&0x0F;要访问版本,可以使用var version=struct.LengthAndVersion>>4&0x0F@Gusman谢谢你的提示,我将编辑代码。@Matt在用谷歌搜索C++/CLI到C之后,结果表明,如果只对其进行管理是好的,但使用本机代码可能会有问题。也许我错了。@JohnTube,你调试代码了吗?如果是,那么WinDivertRecv之后的数据包和数据包的值在哪里?
 byte[] managedPacket = new byte[(int)packetLen];     
 NativeMethods.WINDIVERT_ADDRESS windivertAddr = new NativeMethods.WINDIVERT_ADDRESS();
 GCHandle managedPacketHandle = GCHandle.Alloc(managedPacket, GCHandleType.Pinned);
 IntPtr managedPacketPointer = managedPacketHandle.AddrOfPinnedObject();
 GCHandle windivertAddrHandle = GCHandle.Alloc(windivertAddr, GCHandleType.Pinned);
 IntPtr windivertAddrPointer = managedPacketHandle.AddrOfPinnedObject();
 NativeMethods.WinDivertRecv(handle, out managedPacketPointer, (uint)(packetLen * Marshal.SizeOf(typeof(System.Byte))), out windivertAddrPointer , out readLen);
 // output of managed array and struct fields = 0 and it still causes unhandled AccessViolationException even inside a try/catch
 managedPacketHandle.Free();
 windivertAddrPointer.Free(); 
IntPtr packet = Marshal.AllocHGlobal((int)packetLen * Marshal.SizeOf(typeof(System.Byte)));
IntPtr addr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.WINDIVERT_ADDRESS)));
NativeMethods.WinDivertRecv(handle, out packet, (uint)(packetLen * Marshal.SizeOf(typeof(System.Byte))), out addr, out readLen)
byte[] managedPacket = new byte[(int)packetLen];
Marshal.Copy(packet, managedPacket, 0, (int)readLen);
NativeMethods.WINDIVERT_ADDRESS windivertAddr = (NativeMethods.WINDIVERT_ADDRESS)Marshal.PtrToStructure(addr, typeof(NativeMethods.WINDIVERT_ADDRESS));
// no output of managed array and struct fields and the same unhandled AccessViolationException 
Marshal.FreeHGlobal(addr);
Marshal.FreeHGlobal(packet);