创建简单的Windows驱动程序并与应用程序通信

创建简单的Windows驱动程序并与应用程序通信

在本篇博客中,我们将创建一个简单的Windows驱动程序,并实现与用户模式应用程序的通信。我们将展示如何创建驱动程序,处理IRP请求,并在应用程序中使用CreateFileWriteFile函数与驱动程序通信。

驱动程序实现

  1. 首先,定义设备对象名称和符号链接名称。
//设备对象名称
#define DEVICE_NAME L"\\Device\\IRP_tx"
//符号链接名称
#define LINK_NAME L"\\DosDevices\\core_object"
  1. 创建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;
}
  1. 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);
}
  1. 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;
}

应用程序实现

  1. 定义符号链接名称。
#define LINK_NAME L"\\\\.\\core_object"
  1. 使用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;
}
  1. 使用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请求来响应应用程序的请求。应用程序可以使用CreateFileWriteFile函数与驱动程序通信。

在本教程中,我们已经展示了如何创建一个简单的Windows驱动程序并与应用程序通信。然而,在开发过程中,您可能会遇到一些问题。这里列举了之前碰到的一些问题以及相应的解决方案,以帮助您更顺利地进行开发。

问题1:IoCreateSymbolicLink错误,返回NTSTATUS错误码:C0000035

在某些情况下,您可能会在卸载驱动程序后再次安装时遇到IoCreateSymbolicLink错误。这是因为在卸载过程中,有时驱动程序无法立即删除符号链接。这会导致符号链接已存在的错误(C0000035)。

解决方案:

确保在DriverUnload函数中正确删除符号链接。在卸载驱动程序时,您可以使用FltUnloadFilter函数确保符号链接被删除。另外,您还可以考虑在DriverEntry函数中使用IoDeleteSymbolicLink来删除符号链接,以防止重复创建错误。

问题2:应用程序无法读取驱动程序信息,返回错误代码5

当您尝试使用CreateFile函数打开符号链接时,可能会遇到访问被拒绝的问题(错误代码5)。这通常是由于访问权限不正确或者驱动程序中的IRP处理程序不完整导致的。

解决方案:

确保在应用程序中使用正确的访问权限(如GENERIC_WRITE)。同时,在驱动程序中,为每个主要功能编写正确的IRP处理程序(如IRP_MJ_CREATEIRP_MJ_CLOSEIRP_MJ_READIRP_MJ_WRITE)。

问题3:驱动程序加载失败,返回错误代码0xC0000428

当您尝试加载驱动程序时,可能会遇到签名问题(错误代码0xC0000428)。这是因为Windows要求驱动程序必须通过微软认证签名。

解决方案:

为了解决此问题,您可以尝试以下方法:

  1. 在测试阶段,禁用驱动程序签名强制要求。在命令提示符下,以管理员身份运行以下命令,然后重新启动计算机:
bcdedit.exe /set nointegritychecks on
  1. 为您的驱动程序获取合适的数字签名。在产品发布阶段,请确保您的驱动程序已经通过了微软的签名认证。

请注意,禁用驱动程序签名强制要求会降低系统的安全性。仅在测试和开发阶段使用此方法,永远不要在生产环境中禁用驱动程序签名检查。

请注意,本教程提供的示例仅供学习和研究目的。在实际项目中使用时,请确保遵循适当的编程和安全实践。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【适合小白入门】深入掌握Windows操作系统原理,提升程序开发水平,为学习驱动开发,内核安全打下基础。学完本课程可以轻松的理解Windows内核,开阔思路,对没有底层开发基础的人起到有非常好的指导作用。在此基础上可以开发出有趣且功能强大的软件。 课程目录: 第1章windows驱动基础 第一课 认识windows驱动 第二课 在虚拟机里安装windows操作系统 第三课 windows操作系统基本概念 第四课 操作系统的分层结构 第2章windowsw驱动编译环境配置、安装及调试 第五课 安装驱动开发环境 第六课 安装驱动开发环境 第七课 实战:编写驱动程序加载器 第3章驱动程序的基本结构 第八课 复习c语言的指针和数据结构 第九课 windows驱动程序的基本结构 第十课 编程实战-创建设备对象 第4章windows内存管理 第十一课 内存管理操作 第十二课 驱动开发中使用链表 第十三课 驱动开发中使用快查表 第十四课 在驱动中使用c++中内存管理操作-newdelet 第十六课 驱动开发中宏与断言的使用 第5章应用程序驱动程序通信 第二十六课 irp与派遣函数 第二十七课 缓冲区读写操作 第十五课 在驱动中使用结构化异常处理 第二十八课 缓冲区读写操作 第二十九课 模拟文件 第三十课 直接方式与其它方式读写操作 第三十一课 io设备控制操作 第三十二课 io设备控制操作 第6章windows内核函数 第十七课 内核模式下的字符串操作1 第十八课 内核模式下的字符串操作 第十九课 内核模式下的字符串操作 第二十课 内核模式下的文件操作 第二十一课 内核模式下的文件操作 第二十二课 内核模式下注册表操作 第二十三课 内核模式下注册表操作 第二十四课 内核模式下注册表操作 第二十五课 内核模式下注册表操作 第7章驱动程序的同步处理 第三十三课 内核模式下的同步与异步操作 第三十四课 用户模式下的同步对象1_事件 第三十五课 用户模式下的同步对象2_线程信号量与互斥体 第三十六课 内核模式下的同步对象3_系统线程创建与普 第三十七课 内核模式下的同步对象4_信号量与互斥体 第三十八课 内核模式与用户模式间的同步操作 第三十九课 其它内核同步要素 第8章IRP的同步与异步 第四十课 应用程序的对文件同步与异步操作 第四十一课 irp异步完成 第四十二课 irp的取消与startio函数 第四十三课 自定义startio函数 第9章定时器54分钟3节 第四十四课 io定时器与dpc定时器 第四十五课 内核模式下的等待操作 第四十六课 时间函数与irp超时处理 第10章驱动程序调用驱动程序1小时3节 第四十七课 通过设备句柄调用驱动程序 第四十八课 设备指针调用驱动程序 第四十九课 自定义irp与ObReferenceObject 第11章分层过滤驱动 第五十课 分层驱动:枚举设备栈上的设备对象 第五十一课 编写过滤驱动程序 第五十二课 irp完成函数 第12章驱动程序开发高级技能 第五十三课 驱动程序的兼容性 第五十五课 驱动调试之windbg与vmware 第五十六课 驱动调试vs vmware 第五十四课 驱动签名证书原理及制作 第五十七课 驱动调试神器virtualkd 第五十八课 汇编语言编写驱动之环境搭建 第五十九课 用汇编语言开发32与64位驱动程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值