创建简单的Windows驱动程序并与应用程序通信
在本篇博客中,我们将创建一个简单的Windows驱动程序,并实现与用户模式应用程序的通信。我们将展示如何创建驱动程序,处理IRP请求,并在应用程序中使用CreateFile
和WriteFile
函数与驱动程序通信。
驱动程序实现
- 首先,定义设备对象名称和符号链接名称。
//设备对象名称
#define DEVICE_NAME L"\\Device\\IRP_tx"
//符号链接名称
#define LINK_NAME L"\\DosDevices\\core_object"
- 创建IRP派遣函数
DispatchCommdn
以处理不同类型的IRP请求。
NTSTATUS DispatchCommdn(PDEVICE_OBJECT pObject, PIRP pIrp) {
UNREFERENCED_PARAMETER(pObject);
PIO_STACK_LOCATION pStackLocation = IoGetCurrentIrpStackLocation(pIrp);
ULONG majorFunction = pStackLocation->MajorFunction;
NTSTATUS status = STATUS_SUCCESS;
switch (majorFunction) {
case IRP_MJ_CREATE:
DbgPrint("IRP_MJ_CREATE");
// 处理IRP_MJ_CREATE请求
break;
case IRP_MJ_CLOSE:
DbgPrint("IRP_MJ_CLOSE");
// 处理IRP_MJ_CLOSE请求
break;
case IRP_MJ_READ:
DbgPrint("IRP_MJ_READ");
// 处理IRP_MJ_READ请求
break;
case IRP_MJ_WRITE:
DbgPrint("IRP_MJ_WRITE");
// 处理IRP_MJ_WRITE请求
break;
default:
DbgPrint("Unknown major function: %u", majorFunction);
break;
}
// 设置IRP处理成功
pIrp->IoStatus.Status = status;
// 设置返回的字节数
pIrp->IoStatus.Information = 0;
// 结束IRP处理流程
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
// 返回成功
return status;
}
- 在
DriverUnload
函数中删除符号链接和设备对象。
VOID DriverUnload(PDRIVER_OBJECT pDreverObject) {
UNREFERENCED_PARAMETER(pDreverObject);
DbgPrint("DriverUnload\r\n");
//声明符号链接名称
DECLARE_CONST_UNICODE_STRING(usLinkName, LINK_NAME);
//删除符号链接
IoDeleteSymbolicLink(&usLinkName);
//删除设备对象
IoDeleteDevice(pDreverObject->DeviceObject);
}
- 在
DriverEntry
函数中创建设备对象和符号链接,将所有IRP派遣处理函数设置为默认处理函数,并设置DriverUnload
函数。
NTSTATUS DriverEntry(PDRIVER_OBJECT pDreverObject, PUNICODE_STRING pRegPath) {
UNREFERENCED_PARAMETER(pRegPath);
//返回状态
NTSTATUS ntStatus = 0;
//声明设备对象名称
DECLARE_CONST_UNICODE_STRING(usDeviceName, DEVICE_NAME);
//声明符号链接名称
DECLARE_CONST_UNICODE_STRING(usLinkName, LINK_NAME);
//设备对象
PDEVICE_OBJECT pDeviceObject = NULL;
//创建设备对象
ntStatus = IoCreateDevice(pDreverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObject);
//判断是否创建成功
if (!NT_SUCCESS(ntStatus)) {
DbgPrint("IoCreateDevice Failed:%x\r\n",ntStatus);
return ntStatus;
}
//1.DO_BUFFERED_IO:基于缓存的IO方式
//2.DO_DIRECT_IO:直接读写的IO方式
//3.DO_FORCE_NEITHER_IO两者都不的IO方式
pDeviceObject->Flags |= DO_BUFFERED_IO;//安全
//创建符号链接
ntStatus = IoCreateSymbolicLink(&usLinkName, &usDeviceName);
if (!NT_SUCCESS(ntStatus)) {
//删除设备对象
IoDeleteDevice(pDeviceObject);
DbgPrint("IoCreateSymbolicLink Failed:%x\r\n", ntStatus);
return ntStatus;
}
/*将所有IRP派遣处理函数,设置默认处理函数*/
for (size_t i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++) {
pDreverObject->MajorFunction[i] = DispatchCommdn;
}
pDreverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
应用程序实现
- 定义符号链接名称。
#define LINK_NAME L"\\\\.\\core_object"
- 使用
CreateFile
函数打开符号链接,并使用GENERIC_WRITE
访问权限。
HANDLE hDevice = CreateFile(LINK_NAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//判断符号链接是否打开成功
if (hDevice == INVALID_HANDLE_VALUE) {
printf("ERROR:%d\r\n", GetLastError());
system("pause");
return false;
}
- 使用
WriteFile
函数将数据写入驱动程序。
ULONG ullRetWriteLength;
ULONG ullWriteLength = (wcslen(L"Hello World") + 1) * sizeof(wchar_t);
WriteFile(hDevice, L"Hello World", ullWriteLength, &ullRetWriteLength, NULL);
system("pause");
现在,您已经创建了一个简单的Windows驱动程序,并实现了与用户模式应用程序的通信。驱动程序通过处理不同类型的IRP请求来响应应用程序的请求。应用程序可以使用CreateFile
和WriteFile
函数与驱动程序通信。
在本教程中,我们已经展示了如何创建一个简单的Windows驱动程序并与应用程序通信。然而,在开发过程中,您可能会遇到一些问题。这里列举了之前碰到的一些问题以及相应的解决方案,以帮助您更顺利地进行开发。
问题1:IoCreateSymbolicLink错误,返回NTSTATUS错误码:C0000035
在某些情况下,您可能会在卸载驱动程序后再次安装时遇到IoCreateSymbolicLink
错误。这是因为在卸载过程中,有时驱动程序无法立即删除符号链接。这会导致符号链接已存在的错误(C0000035)。
解决方案:
确保在DriverUnload
函数中正确删除符号链接。在卸载驱动程序时,您可以使用FltUnloadFilter
函数确保符号链接被删除。另外,您还可以考虑在DriverEntry
函数中使用IoDeleteSymbolicLink
来删除符号链接,以防止重复创建错误。
问题2:应用程序无法读取驱动程序信息,返回错误代码5
当您尝试使用CreateFile
函数打开符号链接时,可能会遇到访问被拒绝的问题(错误代码5)。这通常是由于访问权限不正确或者驱动程序中的IRP处理程序不完整导致的。
解决方案:
确保在应用程序中使用正确的访问权限(如GENERIC_WRITE
)。同时,在驱动程序中,为每个主要功能编写正确的IRP处理程序(如IRP_MJ_CREATE
,IRP_MJ_CLOSE
,IRP_MJ_READ
和IRP_MJ_WRITE
)。
问题3:驱动程序加载失败,返回错误代码0xC0000428
当您尝试加载驱动程序时,可能会遇到签名问题(错误代码0xC0000428)。这是因为Windows要求驱动程序必须通过微软认证签名。
解决方案:
为了解决此问题,您可以尝试以下方法:
- 在测试阶段,禁用驱动程序签名强制要求。在命令提示符下,以管理员身份运行以下命令,然后重新启动计算机:
bcdedit.exe /set nointegritychecks on
- 为您的驱动程序获取合适的数字签名。在产品发布阶段,请确保您的驱动程序已经通过了微软的签名认证。
请注意,禁用驱动程序签名强制要求会降低系统的安全性。仅在测试和开发阶段使用此方法,永远不要在生产环境中禁用驱动程序签名检查。
请注意,本教程提供的示例仅供学习和研究目的。在实际项目中使用时,请确保遵循适当的编程和安全实践。