带 DWORD 的 DeviceIoControl
DeviceIoControl with DWORD
我的 OS 是 Win7 64 位。我正在尝试通过 DeviceIoControl 将变量的值而不是它的地址(进程 ID,DWORD)传递给我的驱动程序。试了好几次,都是蓝屏或者错误码998。
在用户模式方面,我确保 hDevice 有效,CTL_CODE 看起来像这样:
#define SENDPID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
然后我这样做:
DWORD pID = FindProcessName("someprocess.exe");
if (!pID) return false;
if (!DeviceIoControl(hDevice, SENDPID, &pID, sizeof(pID), NULL, 0, &BytesIO, 0))
{
cout << GetLastError() << endl;
return false;
}
在内核模式下(DriverEntry):
NTSTATUS DriverEntry(PDRIVER_OBJECT Object, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING dNUS = { 0 };
RtlInitUnicodeString(&dNUS, L"\Device\testdriver");
UNICODE_STRING dSLU = { 0 };
RtlInitUnicodeString(&dSLU, L"\DosDevices\testdriver");
IoCreateDevice(Object, 0, &dNUS, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObj);
IoCreateSymbolicLink(&dSLU, &dNUS);
Object->MajorFunction[IRP_MJ_CREATE] = CCreate;
Object->MajorFunction[IRP_MJ_CLOSE] = CClose;
Object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOCTL;
Object->DriverUnload = Unload;
return(STATUS_SUCCESS);
}
和我的 IOCTL 函数:
NTSTATUS IOCTL(PDEVICE_OBJECT Object, PIRP IRP)
{
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(IRP);
size_t size = 0;
DWORD pID = 0;
if (StackLocation->Parameters.DeviceIoControl.IoControlCode == SENDPID)
{
pID = IRP->AssociatedIrp.SystemBuffer;
size = sizeof(pID);
}
IRP->IoStatus.Status = STATUS_SUCCESS;
IRP->IoStatus.Information = size;
IofCompleteRequest(IRP, IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
如果有人能告诉我要更改什么,请告诉我:)
在应用端,为什么 FindProcessName()
return 使用 DWORD*
指针而不是 DWORD
值?或者,它真的是 return 一个 DWORD
值,而你只是错误地将其类型转换为 DWORD*
指针?
通过将 pID
定义为 DWORD*
指针,sizeof(pID)
是传递给 DeviceIoControl()
的错误值。它传递的是指针本身的大小(32 位为 4,64 位为 8),而不是所指向的 DWORD
值的大小(sizeof(DWORD)
始终为 4)。
如果 pID
是指向内存中 DWORD
的真实指针,则需要使用 sizeof(*pID)
而不是 sizeof(pID)
。但是如果 FindProcessName()
returns 0 呢?然后你最终会传递一个 NULL 指针到 DeviceIoControl()
,即使你告诉 DeviceIoControl()
你正在传递它 4 个字节。
您应该将 FindProcessName()
更改为 return 一个 DWORD
值(如果还没有)而不是 DWORD*
指针,然后使用 &
运算符将 DWORD
的地址传递给 DeviceIoControl()
,例如:
DWORD pID = FindProcessName("DayZ.exe");
if (!DeviceIoControl(hDevice, SENDPID, &pID, sizeof(pID), NULL, 0, &BytesIO, 0))
然后在内核端,只需对 SystemBuffer
进行类型转换即可访问该值(当然,在验证 SystemBuffer
至少包含 4 个字节之后):
NTSTATUS IOCTL(PDEVICE_OBJECT Object, PIRP IRP)
{
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(IRP);
size_t size = 0;
DWORD pID = 0;
if ((StackLocation->Parameters.DeviceIoControl.IoControlCode == SENDPID) &&
(StackLocation->Parameters.DeviceIoControl.InputBufferLength >= sizeof(pID)))
{
pID = *(DWORD*)(IRP->AssociatedIrp.SystemBuffer);
size = sizeof(pID);
}
IRP->IoStatus.Status = STATUS_SUCCESS;
IRP->IoStatus.Information = size;
IofCompleteRequest(IRP, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
我的 OS 是 Win7 64 位。我正在尝试通过 DeviceIoControl 将变量的值而不是它的地址(进程 ID,DWORD)传递给我的驱动程序。试了好几次,都是蓝屏或者错误码998。
在用户模式方面,我确保 hDevice 有效,CTL_CODE 看起来像这样:
#define SENDPID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
然后我这样做:
DWORD pID = FindProcessName("someprocess.exe");
if (!pID) return false;
if (!DeviceIoControl(hDevice, SENDPID, &pID, sizeof(pID), NULL, 0, &BytesIO, 0))
{
cout << GetLastError() << endl;
return false;
}
在内核模式下(DriverEntry):
NTSTATUS DriverEntry(PDRIVER_OBJECT Object, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING dNUS = { 0 };
RtlInitUnicodeString(&dNUS, L"\Device\testdriver");
UNICODE_STRING dSLU = { 0 };
RtlInitUnicodeString(&dSLU, L"\DosDevices\testdriver");
IoCreateDevice(Object, 0, &dNUS, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObj);
IoCreateSymbolicLink(&dSLU, &dNUS);
Object->MajorFunction[IRP_MJ_CREATE] = CCreate;
Object->MajorFunction[IRP_MJ_CLOSE] = CClose;
Object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOCTL;
Object->DriverUnload = Unload;
return(STATUS_SUCCESS);
}
和我的 IOCTL 函数:
NTSTATUS IOCTL(PDEVICE_OBJECT Object, PIRP IRP)
{
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(IRP);
size_t size = 0;
DWORD pID = 0;
if (StackLocation->Parameters.DeviceIoControl.IoControlCode == SENDPID)
{
pID = IRP->AssociatedIrp.SystemBuffer;
size = sizeof(pID);
}
IRP->IoStatus.Status = STATUS_SUCCESS;
IRP->IoStatus.Information = size;
IofCompleteRequest(IRP, IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
如果有人能告诉我要更改什么,请告诉我:)
在应用端,为什么 FindProcessName()
return 使用 DWORD*
指针而不是 DWORD
值?或者,它真的是 return 一个 DWORD
值,而你只是错误地将其类型转换为 DWORD*
指针?
通过将 pID
定义为 DWORD*
指针,sizeof(pID)
是传递给 DeviceIoControl()
的错误值。它传递的是指针本身的大小(32 位为 4,64 位为 8),而不是所指向的 DWORD
值的大小(sizeof(DWORD)
始终为 4)。
如果 pID
是指向内存中 DWORD
的真实指针,则需要使用 sizeof(*pID)
而不是 sizeof(pID)
。但是如果 FindProcessName()
returns 0 呢?然后你最终会传递一个 NULL 指针到 DeviceIoControl()
,即使你告诉 DeviceIoControl()
你正在传递它 4 个字节。
您应该将 FindProcessName()
更改为 return 一个 DWORD
值(如果还没有)而不是 DWORD*
指针,然后使用 &
运算符将 DWORD
的地址传递给 DeviceIoControl()
,例如:
DWORD pID = FindProcessName("DayZ.exe");
if (!DeviceIoControl(hDevice, SENDPID, &pID, sizeof(pID), NULL, 0, &BytesIO, 0))
然后在内核端,只需对 SystemBuffer
进行类型转换即可访问该值(当然,在验证 SystemBuffer
至少包含 4 个字节之后):
NTSTATUS IOCTL(PDEVICE_OBJECT Object, PIRP IRP)
{
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(IRP);
size_t size = 0;
DWORD pID = 0;
if ((StackLocation->Parameters.DeviceIoControl.IoControlCode == SENDPID) &&
(StackLocation->Parameters.DeviceIoControl.InputBufferLength >= sizeof(pID)))
{
pID = *(DWORD*)(IRP->AssociatedIrp.SystemBuffer);
size = sizeof(pID);
}
IRP->IoStatus.Status = STATUS_SUCCESS;
IRP->IoStatus.Information = size;
IofCompleteRequest(IRP, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}