Использование DeviceIoControl из кода C # всегда возвращает пустой выходной буфер

#c# #c #driver #marshalling #deviceiocontrol

#c# #c #драйвер #сортировка #deviceiocontrol

Вопрос:

У меня есть драйвер, который я хочу использовать из своего клиентского приложения на C #. Проблема здесь в том, что мой выходной буфер всегда пуст (0). Когда я использую этот драйвер из кода C — все работает как по маслу, поэтому я думаю, что проблема в моем клиентском коде C #.

Extern определяется следующим образом:

     [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 : defau<
    }
 

Я не уверен, почему, возвращаемые байты = 8, хотя должно быть 4. И, как я уже сказал, выходной буфер пуст.
Код Drver:

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

    if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, amp;process)))
    {
        DebugMessage("ReadRequest requestedn");

        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, amp;bytes);
    }
 

Возможно, это связано с выравниванием структуры, но я не уверен (в клиентском приложении C размер структуры составляет 18 байт, в C # 32 байта).

Пожалуйста, сообщите

Ответ №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 ?? defau<