我有一个设备驱动程序,用于从内核空间读取其他进程虚拟内存,因此我不必使用ReadProcessMemory
或WriteProcessMemory
等函数。
当我使用结构作为媒介通过DeviceIoControl
将参数传递给内核时,这种方法很好,但是当我使用普通变量(如unsigned long)时,驱动程序会崩溃我的计算机。
(适用驱动程序):
#define IO_KERNEL_READ_REQUEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0701, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
typedef struct _KERNEL_READ_REQUEST
{
ULONG ProcessId;
ULONG Address;
ULONG Response;
ULONG Size;
} KERNEL_READ_REQUEST, *PKERNEL_READ_REQUEST;
if (ControlCode == IO_KERNEL_READ_REQUEST)
{
PKERNEL_READ_REQUEST ReadInput = (PKERNEL_READ_REQUEST)Irp->AssociatedIrp.SystemBuffer;
PKERNEL_READ_REQUEST ReadOutput = (PKERNEL_READ_REQUEST)Irp->AssociatedIrp.SystemBuffer;
PEPROCESS Process;
PsLookupProcessByProcessId(ReadInput->ProcessId, &Process);
KeReadVirtualMemory(Process, ReadInput->Address, &ReadOutput->Response, ReadInput->Size);
DbgPrintEx(0, 0, "Read Params: %lu, %#010x \n", ReadInput->ProcessId, ReadInput->Address);
DbgPrintEx(0, 0, "Value: %lu \n", ReadOutput->Response);
status = STATUS_SUCCESS;
bytesIO = sizeof(KERNEL_READ_REQUEST);
}
(程序):
template <typename type>
type KernelRead(HANDLE hDriver, ULONG ProcessId, ULONG ReadAddress, SIZE_T ReadSize)
{
if (hDriver == INVALID_HANDLE_VALUE)
return (type)false;
DWORD Return;
DWORD Bytes;
KERNEL_READ_REQUEST ReadRequest;
ReadRequest.ProcessId = ProcessId;
ReadRequest.Address = ReadAddress;
ReadRequest.Size = ReadSize;
if (DeviceIoControl(hDriver, IO_KERNEL_READ_REQUEST, &ReadRequest, sizeof(ReadRequest),
&ReadRequest, sizeof(ReadRequest), &Bytes, NULL)) {
return (type)ReadRequest.Response;
}
else
return (type)false;
}
#define IO_KERNEL_GET_ID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0703, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
else if (ControlCode == IO_KERNEL_GET_ID)
{
// ProcessId is an ULONG initialized at the driver entry
PULONG OutPut = (PULONG)Irp->AssociatedIrp.SystemBuffer;
OutPut = &ProcessId;
DbgPrintEx(0, 0, "Kernel Get Id: %d \n", *OutPut);
status = STATUS_SUCCESS;
bytesIO = sizeof(OutPut);
}
DWORD KernelGetProcessId(HANDLE hDriver)
{
if (hDriver == INVALID_HANDLE_VALUE)
return false;
ULONG Id;
if (DeviceIoControl(hDriver, IO_KERNEL_GET_ID, &, sizeof(Id),
&Id, sizeof(Id), 0, NULL))
return Id;
else
return false;
}
调用KernelGetProcessId
会崩溃我的驱动程序和整台计算机,如何解决?我在这里做错了什么?
答案 0 :(得分:0)
检查DeviceIoControl。如果lpOverlapped为NULL,则lpBytesReturned不能为NULL。即使操作没有返回输出数据且lpOutBuffer为NULL,DeviceIoControl也会使用lpBytesReturned。在这样的操作之后,lpBytesReturned的值是没有意义的。
也许这可能是其中一个原因。 我看到的其他问题只是通过&amp;,你应该传递ULONG变量。
检查一下这样的事情
DWORD KernelGetProcessId(HANDLE hDriver)
{
if (hDriver == INVALID_HANDLE_VALUE)
return false;
ULONG Id;
DWORD Bytes;
if (DeviceIoControl(hDriver, IO_KERNEL_GET_ID, &Id, sizeof(Id),
&Id, sizeof(Id), &Bytes, NULL))
return Id;
else
return false;
}
答案 1 :(得分:-1)
显然,IOCTL通过使用两者的堆栈来工作 司机&amp;用户程序。我理解堆栈了 函数调用DeviceIoControl()被复制到内核空间 然后使用DeviceIoControl()的参数进行剖析 知道我们正在使用哪些堆栈变量&amp;缓冲区是 最后设置为Irp-&gt; AssociatedIrp.SystemBuffer。
在内核端完成IOCTL操作后, 制作IoCompleteRequest(),复制堆栈 内核模块到用户空间然后被再次解析 我们想要它的形式。
(如果我错了,请纠正我)
崩溃是由内核模块中的代码引起的:
PULONG OutPut = (PULONG)Irp->AssociatedIrp.SystemBuffer;
OutPut = &ProcessId;
其中全局变量的地址被设置为输出数据的值。 现在,当复制堆栈时,地址显然不会指向任何地方 “ProcessId”变量驻留在64位内核空间中。这是我对这个问题的理解。
这解决了问题:
PULONG OutPut = (PULONG)Irp->AssociatedIrp.SystemBuffer;
*OutPut = ProcessId;
DbgPrintEx(0, 0, "Kernel Get Id: %d \n", *OutPut);
status = STATUS_SUCCESS;
bytesIO = sizeof(OutPut);