【问题标题】:Using DeviceIoControl from C# code always returns empty output buffer在 C# 代码中使用 DeviceIoControl 总是返回空的输出缓冲区
【发布时间】:2021-03-13 06:36:30
【问题描述】:

我有一个驱动程序,我想从我的 C# 客户端应用程序中使用它。这里的问题是我的输出缓冲区总是空的(0)。当我从 C 代码中使用这个驱动程序时 - 一切都像魅力一样,所以我认为问题出在我的客户端 C# 代码中。

外部定义如下:

    [DllImport(kernel, EntryPoint = "DeviceIoControl", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeviceIoControl(
        SafeFileHandle hDevice,
        UInt32 dwIoControlCode,
        IntPtr lpInBuffer,
        UInt32 nInBufferSize,
        IntPtr lpOutBuffer,
        UInt32 nOutBufferSize,
        ref UInt32 lpBytesReturned,
        [In] ref NativeOverlapped lpOverlapped);

我将它用作:

    public static T ReadVirtualMemory<T>(SafeFileHandle driverHandle, int offset) where T : unmanaged
    {
        var inBuffer = (object)new T();
        var nInBufferSize = Marshal.SizeOf(typeof(T));

        var outBuffer = (object)new T();
        var nOutBufferSize = Marshal.SizeOf(typeof(T));

        var data = new KERNEL_READ_REQUEST
        {
            Address = (ulong)offset,
            Size = (ulong)nInBufferSize,
            pBuffer = (IntPtr)inBuffer
        };

        IntPtr lpInBuffer = IntPtr.Zero;
        IntPtr lpOutBuffer = IntPtr.Zero;

        nInBufferSize = Marshal.SizeOf(data);
        lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
        Marshal.StructureToPtr(data, lpInBuffer, true);

        lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
        Marshal.StructureToPtr(outBuffer, lpOutBuffer, true);

        UInt32 lpBytesReturned = 0;
        NativeOverlapped lpOverlapped = new NativeOverlapped();

        Kernel32.DeviceIoControl(
            driverHandle,
            (uint)DriverMethod.ReadMemory,
            lpInBuffer,
            (uint)nInBufferSize,
            lpOutBuffer,
            (uint)nOutBufferSize,
            ref lpBytesReturned,
            ref lpOverlapped);

        outBuffer = (T)Marshal.PtrToStructure(lpOutBuffer, typeof(T));

        return lpBytesReturned == nOutBufferSize ? (T)outBuffer : default;
    }

我不知道为什么,返回的字节数 = 8,虽然它应该是 4。正如我所说的 - 输出缓冲区是空的。 司机代号:

    PKERNEL_READ_REQUEST readRequest = (PKERNEL_READ_REQUEST)pIrp->AssociatedIrp.SystemBuffer;
    PEPROCESS process;

    if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &process)))
    {
        DebugMessage("ReadRequest requested\n");

        KernelReadVirtualMemory(process, readRequest->Address, readRequest->pBuffer, readRequest->Size);

        byteIo = sizeof(PKERNEL_READ_REQUEST);
        status = STATUS_SUCCESS;
    }

    NTSTATUS NTAPI MmCopyVirtualMemory
    (
        PEPROCESS SourceProcess,
        PVOID SourceAddress,
        PEPROCESS TargetProcess,
        PVOID TargetAddress,
        SIZE_T BufferSize,
        KPROCESSOR_MODE PreviousMode,
        PSIZE_T ReturnSize
    );

    NTSTATUS KernelReadVirtualMemory(PEPROCESS process, PVOID sourceAddress, PVOID targetAddress, SIZE_T size)
    {
        PSIZE_T bytes;

        return MmCopyVirtualMemory(process, sourceAddress, PsGetCurrentProcess(), targetAddress, size, KernelMode, &bytes);
    }

这可能是结构对齐的问题,但我不确定(在 C 客户端应用程序中,sizeof 结构为 18 字节,在 C# 中为 32 字节)。

请指教

【问题讨论】:

    标签: c# c driver marshalling deviceiocontrol


    【解决方案1】:

    首先 - 我必须在 x64 中编译。 第二 - 必须为 pBuffer 分配内存

    下面是一个工作示例

            var nInBufferSize = Marshal.SizeOf(typeof(T));
            var inBuffer = Marshal.AllocHGlobal(nInBufferSize);
    
            var data = new KERNEL_READ_REQUEST
            {
                Address = offset,
                Size = nInBufferSize,
                pBuffer = inBuffer
            };
    
            var requestSize = Marshal.SizeOf(data);
            var requestBuffer = Marshal.AllocHGlobal(requestSize);
            Marshal.StructureToPtr(data, requestBuffer, true);
    
            uint bytesReturned = 0;
            var overlapped = new NativeOverlapped();
    
            Kernel32.DeviceIoControl(
                driverHandle,
                (uint)DriverMethod.ReadMemory,
                requestBuffer,
                (uint)requestSize,
                requestBuffer,
                (uint)requestSize,
                ref bytesReturned,
                ref overlapped);
    
            var result = Marshal.PtrToStructure(data.pBuffer, typeof(T));
    
            return (T?)result ?? default;
    

    【讨论】:

      猜你喜欢
      • 2014-09-26
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 2019-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多