驱动开发:通过ReadFile与内核层通信

驱动与应用程序的通信是非常有必要的,内核中执行代码后需要将其动态显示给应用层,但驱动程序与应用层毕竟不在一个地址空间内,为了实现内核与应用层数据交互则必须有通信的方法,微软为我们提供了三种通信方式,如下先来介绍通过ReadFile系列函数实现的通信模式 。
长话短说,不说没用的概念,首先系统中支持的通信模式可以总结为三种 。

  • 缓冲区方式读写(DO_BUFFERED_IO)
  • 直接方式读写(DO_DIRECT_IO)
  • 其他方式读写
而通过ReadFile,WriteFile系列函数实现的通信机制则属于缓冲区通信模式,在该模式下操作系统会将应用层中的数据复制到内核中,此时应用层调用ReadFile,WriteFile函数进行读写时,在驱动内会自动触发 IRP_MJ_READ 与 IRP_MJ_WRITE这两个派遣函数,在派遣函数内则可以对收到的数据进行各类处理 。
首先需要实现初始化各类派遣函数这么一个案例,如下代码则是通用的一种初始化派遣函数的基本框架,分别处理了IRP_MJ_CREATE创建派遣,以及IRP_MJ_CLOSE关闭的派遣,此外函数DriverDefaultHandle的作用时初始化其他派遣用的,也就是将除去CREATE/CLOSE这两个派遣之外,其他的全部赋值成初始值的意思,当然不增加此段代码也是无妨,并不影响代码的实际执行 。
#include <ntifs.h>// 卸载驱动执行VOID UnDriver(PDRIVER_OBJECT pDriver){ PDEVICE_OBJECT pDev;                                        // 用来取得要删除设备对象 UNICODE_STRING SymLinkName;                                 // 局部变量symLinkName pDev = pDriver->DeviceObject; IoDeleteDevice(pDev);                                           // 调用IoDeleteDevice用于删除设备 RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver");     // 初始化字符串将symLinkName定义成需要删除的符号链接名称 IoDeleteSymbolicLink(&SymLinkName);                             // 调用IoDeleteSymbolicLink删除符号链接 DbgPrint("驱动卸载完毕...");}// 创建设备连接// LyShark.comNTSTATUS CreateDriverObject(IN PDRIVER_OBJECT pDriver){ NTSTATUS Status; PDEVICE_OBJECT pDevObj; UNICODE_STRING DriverName; UNICODE_STRING SymLinkName; // 创建设备名称字符串 RtlInitUnicodeString(&DriverName, L"\\Device\\LySharkDriver"); Status = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj); // 指定通信方式为缓冲区 pDevObj->Flags |= DO_BUFFERED_IO; // 创建符号链接 RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver"); Status = IoCreateSymbolicLink(&SymLinkName, &DriverName); return STATUS_SUCCESS;}// 创建回调函数NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp){ pIrp->IoStatus.Status = STATUS_SUCCESS;          // 返回成功 DbgPrint("派遣函数 IRP_MJ_CREATE 执行 \n"); IoCompleteRequest(pIrp, IO_NO_INCREMENT);        // 指示完成此IRP return STATUS_SUCCESS;                           // 返回成功}// 关闭回调函数NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp){ pIrp->IoStatus.Status = STATUS_SUCCESS;          // 返回成功 DbgPrint("派遣函数 IRP_MJ_CLOSE 执行 \n"); IoCompleteRequest(pIrp, IO_NO_INCREMENT);        // 指示完成此IRP return STATUS_SUCCESS;                           // 返回成功}// 默认派遣函数NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp){ NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status;}// 入口函数// By: LySharkNTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath){ DbgPrint("hello lyshark \n"); // 调用创建设备 CreateDriverObject(pDriver); pDriver->DriverUnload = UnDriver;                          // 卸载函数 pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;    // 创建派遣函数 pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;      // 关闭派遣函数 // 初始化其他派遣 for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {DbgPrint("初始化派遣: %d \n", i);pDriver->MajorFunction[i] = DriverDefaultHandle; } DbgPrint("驱动加载完成..."); return STATUS_SUCCESS;}

经验总结扩展阅读