当前位置: 首页 > article >正文

Windows驱动开发(三)—— 驱动和应用层通信的几种方式

目的

在Windows系统中,驱动程序想要正常工作,往往离不开和用户态进程间的交互。因此,驱动和用户态进程的通信就成为了必不可少的手段。

方式

1. 进程间通信

由于Windows 操作系统中,内核线程运行于某个进程的地址空间中。因此,内核线程和用户进程的通信可以通过进程间通信的方式实现,例如文件映射、共享内存、管道等方式。这里就不一一展开了。

2. I/O请求

通过实现IRP_MJ_READIRP_MJ_WRITE的请求,用户态进程直接通过设备读写的方式与驱动程序通信。

// 应用层读写事件
HANDLE hDevice = ::CreateFile(DRIVER_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FALSE == ReadFile(hDevice, buffer, sizeof(buffer), &dwOutput, NULL)) {
    if (GetLastError() == ERROR_IO_PENDING) {
        WaitForSingleObject(hDevice, INFINITE);
    }
}
WriteFile(hDevice, buffer, sizeof(buffer), &dwOutput, NULL);
CloseHandle(hDevice);

驱动程序在接收到IRP时,根据具体需求选择直接返回数据;或者通过IoMarkIrpPending设置挂起状态,异步处理请求。

// 异步IRP处理
VOID ThreadProc(PVOID StartContext)
{
	PIRP pIrp = (PIRP)StartContext;
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	PsTerminateSystemThread(STATUS_SUCCESS);
}

// 挂起IRP
PsCreateSystemThread(&hThread, 0, NULL, NtCurrentProcess(), NULL, ThreadProc, pIrp);
IoMarkIrpPending(pIrp);
pIrp->IoStatus.Status = STATUS_PENDING;
return STATUS_PENDING;
3. I/O 控制

通过调用DeviceIoControl发送设备控制代码,等待驱动层返回。
从本质上来说,这种方式与通过IRP_MJ_READIRP_MJ_WRITE类似,都是通过封装IRP来实现。
但是,DeviceIoControl允许用户自定义设备控制代码,使用上更加灵活。

// 定义设备控制代码
#define IOCTL_HELLOWORLD_TEST CTL_CODE(0x8000, 0x01, METHOD_BUFFERED, FILE_ANY_ACCESS)
// 执行设备控制
DeviceIoControl(hDevice, IOCTL_HELLOWORLD_TEST, buffer, sizeof(buffer), buffer, sizeof(buffer), &dwOutput, NULL);
4. MiniFilter通信服务端口

在微软的文件过滤器框架MiniFilter中,提供了一种独立的通信方式——CommunicationPort

// 驱动
// 创建通信端口
FltCreateCommunicationPort(pFilter, &pServerPort, &oa, NULL, ConnectNotifyCb, DisconnectNotifyCb, MessageNotifyCb, 1);
// 发送消息
FltSendMessage(pFilter, &pClientPort,inbuffer, inlength, outbuffer, outlength, &liTimeout);
// 接收消息回调
NTSTATUS MessageNotifyCb(
  PVOID PortCookie,
  PVOID InputBuffer,
  ULONG InputBufferLength,
  PVOID OutputBuffer,
  ULONG OutputBufferLength,
  PULONG ReturnOutputBufferLength
)
{...}
// 关闭客户端连接
FltCloseClientPort(pFilter, &pClientPort);
// 关闭端口
FltCloseCommunicationPort(pServerPort);

// 应用态
// 连接通信端口
FilterConnectCommunicationPort(c_sPortName, 0, NULL, 0, NULL, &m_pConnectionPort);
// 接收消息
FilterGetMessage(m_pConnectionPort,lpMessageBuffer, dwMessageBufferSize, NULL);
// 回复消息
FilterReplyMessage(m_pConnectionPort, lpReplyBuffer, dwReplyBufferSize);
// 发送消息
FilterSendMessage(m_pConnectionPort, inbuffer, inlength, outbuffer, outlength, &outlength);
5. 本地过程调用(LPC, Local Procedure Call)

LPC 是 Windows 中的一种轻量级的进程间通信机制,允许在同一台计算机上的不同进程之间进行高效的消息传递。它主要用于用户模式与内核模式之间的交互。
由于LPC是Windows系统内部使用的一种通信机制,微软没有提供任何的公开文档,因此在实际使用中可能存在一定风险。
但是,相比于其他方式而言,LPC可以从驱动连接应用层创建的通信端口,使用上更为灵活。

// 服务端
// 创建端口
ZwCreatePort(&hPort, &objectAttributes, sizeof(PORT_MESSAGE), MAX_LPC_MESSAGE_LENGTH, 0);
// 等待客户端连接
ZwReplyWaitReceivePort(hPort, &lpc_client, NULL, (PPORT_MESSAGE)pRequest);
// 接收客户端连接
ZwAcceptConnectPort(&hConnectionPort, NULL,(PPORT_MESSAGE)pRequest, TRUE, &ServerView, &ClientView);
// 完成客户端连接
ZwCompleteConnectPort(hConnectionPort);
// 响应消息
ZwReplyPort(hConnectionPort, (PPORT_MESSAGE)replyBuffer);
// 关闭端口
ZwClose(hConnectionPort);
ZwClose(hPort);

// 客户端
// 连接端口
ZwConnectPort(&hConnectionPort, &LpcPortName, &sqos, &ClientView, &ServerView, (PULONG)&MaxMessageLength, NULL,NULL);
// 发送消息等待响应
ZwRequestWaitReplyPort(hConnectionPort, (PPORT_MESSAGE)pRequest, (PPORT_MESSAGE)pResponse);
// 关闭端口
ZwClose(hConnectionPort);


http://www.kler.cn/a/370034.html

相关文章:

  • QT:控件属性及常用控件(3)-----输入类控件(正则表达式)
  • AIGC视频生成模型:ByteDance的PixelDance模型
  • 使用Redis缓解数据库压力+三种常见问题
  • NewStar CTF week1 web wp
  • 小型分布式发电项目优化设计方案
  • qml Timer详解
  • Openpyxl--学习记录
  • 【文心智能体 | AI大师工坊】如何使用智能体插件,完成一款旅游类智能体的开发,来体验一下我的智能体『​​​​​​​背包客』
  • 如何将 Excel 数据转换为 SQL 脚本:基于 Java 的全面解析
  • 问:数据库SQL优化实践整理?
  • python 相关
  • Android--简易计算器实现
  • Redis中Lua脚本的使用场景
  • 深度学习领域如何正确地读取视频
  • java OOP 对象操作
  • 关于<a-upload-dragger>实现选择文件夹,上传文件夹中符合要求的文件,并在所有符合要求文件上传完成后统一进行提示。这里面文件是直接上传到七牛云
  • 利用ChatGPT完成2024年MathorCup大数据挑战赛-赛道A初赛:台风预测与分析
  • springMVC中的请求拦截器
  • 【杂谈】城市规划教育的危与机
  • 力扣中等题——顺次数
  • ES6 运算符的扩展
  • mysql 8.0.20 winx64安装配置
  • 我的编程之旅——从新手到大神的蜕变
  • 算法日记 11 day 二叉树
  • 全视通惊艳亮相印度尼西亚国际医疗器械及用品展Hospital Expo
  • RS485、RS232、RS422的区别