从 C# 代码使用 DeviceIoControl 总是 returns 清空输出缓冲区
Using DeviceIoControl from C# code always returns empty output buffer
我有一个 driver,我想从我的 C# 客户端应用程序中使用它。这里的问题是我的输出缓冲区总是空的 (0)。当我在 C 代码中使用此 driver 时 - 一切正常,所以我认为问题出在我的客户端 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 字节)。
请指教
首先 - 我必须在 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;
我有一个 driver,我想从我的 C# 客户端应用程序中使用它。这里的问题是我的输出缓冲区总是空的 (0)。当我在 C 代码中使用此 driver 时 - 一切正常,所以我认为问题出在我的客户端 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 字节)。
请指教
首先 - 我必须在 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;