C++ Windows驱动程序IOCTL代码蓝屏/使计算机崩溃
我有一个设备驱动程序,可以用来从内核空间读取其他进程虚拟内存,因此我不必使用C++ Windows驱动程序IOCTL代码蓝屏/使计算机崩溃,c++,c,windows,kernel,driver,C++,C,Windows,Kernel,Driver,我有一个设备驱动程序,可以用来从内核空间读取其他进程虚拟内存,因此我不必使用ReadProcessMemory或WriteProcessMemory之类的函数 当我使用结构作为媒介,通过DeviceIoControl将参数传递给内核时,这种方法可以很好地工作,但是当我使用无符号long之类的普通变量时,驱动程序会使我的计算机崩溃 下面是一个完美工作的代码示例 (驱动程序): #define IO_KERNEL_READ_REQUEST CTL_CODE(FILE_DEVICE_UNKNOW
ReadProcessMemory
或WriteProcessMemory
之类的函数
当我使用结构作为媒介,通过DeviceIoControl
将参数传递给内核时,这种方法可以很好地工作,但是当我使用无符号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_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;
}
调用KernelGetProcessId
会使我的驱动程序和整个计算机崩溃,如何解决这个问题?我做错了什么?检查。如果lpOverlapped为NULL,则lpBytesReturned不能为NULL。即使操作不返回任何输出数据且LPEXBUFFER为NULL,DeviceIoControl也会使用lpBytesReturned。在这样的操作之后,返回的lpbytes的值没有意义
也许这是原因之一。
我看到的另一个问题是只传递&,您应该在其中传递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;
}
问题是:
显然,IOCTL通过使用两个
驱动程序&用户程序。据我所知
调用DeviceIoControl()的函数被复制到内核空间
然后使用DeviceIoControl()的参数进行剖析
要知道我们正在使用哪些堆栈变量&缓冲区是
最后设置为Irp->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);
据我所知,从驱动程序到用户模式的通信是通过将堆栈(?)或堆栈的某些项复制到用户空间,然后进行处理来实现的。一个全局变量持有该值,而我只是做了一个指向该值的指针&使用它会导致这种情况,因为全局变量不在堆栈上?1)您没有从
IrpSp->Parameters.DeviceIoControl
检查InputBufferLength
和OutputBufferLength
PsLookupProcessByProcessId
3)您没有调用ObfDereferenceObject(Process)
4)ULONG地址
必须是PVOID
或ULONG\u PTR
,是否检查地址
?5) 您必须分析memory.dmp
(或pagefile.sys
)以查看确切位置crash@RbMm这是一个愚蠢的错误,已经找到了修复方法。请检查我的回答你做了什么-不确定你没有张贴足够的代码。例如,您设置了一个名为OutPut
的变量,但我们从未看到它的用途。这是如何编译的?这也不起作用,以前试过。我认为问题在于内核模块代码。不再导致蓝屏,只需将处理器设置为关机状态(在虚拟和物理CPU上尝试)。必须是bytesIO=sizeof(ULONG)代码>。你的代码完全是噩梦——从内核模式堆栈复制的东西。