在前几篇文章中给大家具体解释了驱动与应用层之间正向通信的一些经典案例 , 本章将继续学习驱动通信 , 不过这次我们学习的是通过运用Async异步模式实现的反向通信 , 反向通信机制在开发中时常被用到 , 例如一个杀毒软件如果监控到有异常进程运行或有异常注册表被改写后 , 该驱动需要主动的通知应用层进程让其知道 , 这就需要用到驱动反向通信的相关知识点 , 如下将循序渐进的实现一个反向通信案例 。
在开始学习Async反向通信之前先来研究一个Sync正向通信案例 , 不论是正向反向通信其在通信模式上与《驱动开发:通过ReadFile与内核层通信》所介绍的通信模式基本一致 , 都是通过ReadFile触发驱动中的IRP_MJ_READ读取派遣 , 唯一的区别是在传输数据时使用了MmGetSystemAddressForMdl方式 , 它将给定MDL描述的物理页面映射到系统空间 , 并调用RtlCopyMemory()将全局字符串复制到这个空间内 , 这样客户端就可以循环读取内核传出的数据 。
我们来看驱动端代码是如何实现的这个功能 , 代码并没有什么特殊的无法理解的点 , 只是需要注意我们在驱动入口调用IoCreateDevice()时传入了第二个参数FILE_DEVICE_EXTENSION , 该参数的作用是 , 创建设备时 , 指定设备扩展内存的大小 , 传一个值进去 , 就会给设备分配一块非页面内存 。
#include <ntddk.h>#include <stdio.h>// 保存一段非分页内存,用于给全局变量使用#define FILE_DEVICE_EXTENSION 4096// 定义全局字符串static int global_count = 0;static char global_char[5][128] = { 0 };// 驱动绑定默认派遣函数NTSTATUS _DefaultDispatch(PDEVICE_OBJECT _pDeviceObject, PIRP _pIrp){	_pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;	_pIrp->IoStatus.Information = 0;	IoCompleteRequest(_pIrp, IO_NO_INCREMENT);	return _pIrp->IoStatus.Status;}// 驱动创建后触发NTSTATUS _SyncCreateCloseDispatch(PDEVICE_OBJECT _pDevcieObject, PIRP _pIrp){	_pIrp->IoStatus.Status = STATUS_SUCCESS;	_pIrp->IoStatus.Information = 0;	IoCompleteRequest(_pIrp, IO_NO_INCREMENT);	return _pIrp->IoStatus.Status;}// 应用层读数据后触发NTSTATUS _SyncReadDispatch(PDEVICE_OBJECT _pDeviceObject, PIRP _pIrp){	NTSTATUS status = STATUS_SUCCESS;	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(_pIrp);	PVOID pBuffer = NULL;	ULONG uBufferLen = 0;	do	{// 读写请求使用的是直接I/O方式pBuffer = MmGetSystemAddressForMdl(_pIrp->MdlAddress);if (pBuffer == NULL){status = STATUS_UNSUCCESSFUL;break;}uBufferLen = pIrpStack->Parameters.Read.Length;DbgPrint("读字节长度: %d \n", uBufferLen);// 最大支持20字节读请求uBufferLen = uBufferLen >= 20 ? 20 : uBufferLen;// 输出五次字符串if (global_count < 5){RtlCopyMemory(pBuffer, global_char[global_count], uBufferLen);global_count = global_count + 1;}	} while (FALSE);	// 填写返回状态及返回大小	_pIrp->IoStatus.Status = status;	_pIrp->IoStatus.Information = uBufferLen;	// 完成IRP	IoCompleteRequest(_pIrp, IO_NO_INCREMENT);	return status;}// 卸载驱动VOID _UnloadDispatch(PDRIVER_OBJECT _pDriverObject){	// 删除创建的设备	UNICODE_STRING  Win32DeviceName;	RtlInitUnicodeString(&Win32DeviceName, L"\\DosDevices\\LySharkSync");	IoDeleteDevice(_pDriverObject->DeviceObject);}// 驱动入口NTSTATUS DriverEntry(PDRIVER_OBJECT _pDriverObject, PUNICODE_STRING _pRegistryPath){	UNICODE_STRING DeviceName, Win32DeivceName;	PDEVICE_OBJECT pDeviceObject = NULL;	NTSTATUS status;	HANDLE hThread;	OBJECT_ATTRIBUTES ObjectAttributes;	// 设置符号名	RtlInitUnicodeString(&DeviceName, L"\\Device\\LySharkSync");	RtlInitUnicodeString(&Win32DeivceName, L"\\DosDevices\\LySharkSync");	// 循环初始化IRP函数	for (ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)	{_pDriverObject->MajorFunction[i] = _DefaultDispatch;	}	// 再次覆盖派遣函数	_pDriverObject->MajorFunction[IRP_MJ_CREATE] = _SyncCreateCloseDispatch;	_pDriverObject->MajorFunction[IRP_MJ_CLOSE] = _SyncCreateCloseDispatch;	_pDriverObject->MajorFunction[IRP_MJ_READ] = _SyncReadDispatch;	_pDriverObject->DriverUnload = _UnloadDispatch;	// 分配一个自定义扩展 大小为sizeof(DEVEXT)	// By: LyShark.com	status = IoCreateDevice(_pDriverObject, sizeof(FILE_DEVICE_EXTENSION), &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);	if (!NT_SUCCESS(status))return status;	if (!pDeviceObject)return STATUS_UNEXPECTED_IO_ERROR;	// 为全局变量赋值	strcpy(global_char[0], "hi,lyshark A");	strcpy(global_char[1], "hi,lyshark B");	strcpy(global_char[2], "hi,lyshark C");	strcpy(global_char[3], "hi,lyshark D");	strcpy(global_char[4], "hi,lyshark E");	// 指定读写方式为 直接I/O MDL模式	pDeviceObject->Flags |= DO_DIRECT_IO;	// 数据传输时地址校验大小	pDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;	status = IoCreateSymbolicLink(&Win32DeivceName, &DeviceName);	pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;	return STATUS_SUCCESS;}
经验总结扩展阅读
- 什么是脾胃虚寒的症状
- 喝减肥咖啡为什么口干
- gRPC+Protocol Buffer Go微服务实战 - 用户服务开发
- 为什么Wish注册总是不通过
- WPF开发经验-实现自带触控键盘的TextBox
- 不同方式过减速带会影响通过性吗
- 驱动通信:通过PIPE管道与内核层通信
- mac通过docker一键部署Jenkins
- 如何通过执行SQL为低代码项目提速?
- 驱动开发:通过ReadFile与内核层通信

 
   
   
   
   
   
   
   
   
   
   
   
  