Windows驱动开发:利用ReadFile与WriteFile实现应用层通信

橘子海
橘子海
发布时间:2026-10-15| 3人浏览过
原创

在Windows驱动开发中,内核态与应用层处于不同的地址空间,必须借助特定的I/O机制进行数据交换。微软提供了三种主要的缓冲模式,其中缓冲区方式(DO_BUFFERED_IO)是最常用的标准做法。通过实现IRP_MJ_READ与IRP_MJ_WRITE派遣函数,配合应用层的ReadFile和WriteFile API,即可实现稳定、高效的内核数据交互。

通信模式与原理概述

驱动程序与应用程序的交互主要依赖I/O管理器中转数据,常见通信模式包括:

  • 缓冲区读写(DO_BUFFERED_IO):系统将用户缓冲区的内容复制到内核分配的SystemBuffer中,操作完成后由系统负责复制回用户缓冲区。安全且常用,对应应用层的ReadFile/WriteFile。
  • 直接读写(DO_DIRECT_IO):通过锁页内存(Mdl)直接访问物理内存,减少一次拷贝,适合大数据量传输。
  • 其他方式(NOT_SUPPORTED):通常用于未定义的特殊处理。

本文将详细演示基于缓冲区模式(DO_BUFFERED_IO)的开发流程。

第一步:驱动框架初始化

首先构建标准的驱动入口,完成设备对象的创建、符号链接的建立以及默认派遣函数的配置。务必将标志位设为DO_BUFFERED_IO,这是后续使用ReadFile系列函数的基础。

#include <ntifs.h>

// 卸载驱动执行
VOID UnDriver(PDRIVER_OBJECT pDriver)
{
	PDEVICE_OBJECT pDev = pDriver->DeviceObject;
	UNICODE_STRING SymLinkName;
	IoDeleteDevice(pDev);
	RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver");
	IoDeleteSymbolicLink(&SymLinkName);
}

// 创建设备连接
NTSTATUS 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;
}

第二步:注册读写派遣函数

在DriverEntry中,除了默认的CREATE和CLOSE处理外,必须显式绑定IRP_MJ_READ和IRP_MJ_WRITE。对于其他未使用的功能号,应指向一个默认处理函数以防止非法访问导致蓝屏。

NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
	// ... 省略设备创建部分 ...

	// 统一设置默认处理
	for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		pDriver->MajorFunction[i] = DriverDefaultHandle;
	}

	pDriver->DriverUnload = UnDriver;
	pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
	pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;

	// 增加核心读写派遣处理
	pDriver->MajorFunction[IRP_MJ_READ] = DispatchRead;
	pDriver->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;

	return STATUS_SUCCESS;
}

第三步:实现读写逻辑

在缓冲区模式下,pIrp->AssociatedIrp.SystemBuffer是驱动程序读写数据的唯一入口。读取时,需向此缓冲区填充数据;写入时,可从该缓冲区读取用户传入的数据。

  • 读取请求:操作系统已准备好SystemBuffer,开发者负责向其填入数据,并通过IoStatus.Information返回实际字节数。
  • 写入请求:操作系统已将应用层数据从用户缓冲区复制到SystemBuffer,开发者可直接读取并使用。
// 读取回调函数
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(pIrp);
	ULONG ulReadLength = Stack->Parameters.Read.Length;
	char szBuf[128] = "hello lyshark";

	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = ulReadLength; // 告知IO管理器传输的字节数

	// 安全起见,限制拷贝长度不超过字符串实际长度或缓冲区大小
	ULONG copyLen = (ulReadLength > 5) ? 5 : ulReadLength;
	memcpy(pIrp->AssociatedIrp.SystemBuffer, szBuf, copyLen);

	DbgPrint("读取长度:%d\n", ulReadLength);
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

// 接收传入回调函数
NTSTATUS DispatchWrite(struct _DEVICE_OBJECT *DeviceObject, struct _IRP *Irp)
{
	PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
	ULONG ulWriteLength = Stack->Parameters.Write.Length;
	PVOID ulWriteData = Irp->AssociatedIrp.SystemBuffer;

	DbgPrint("传入长度: %d 传入数据: %s\n", ulWriteLength, (char*)ulWriteData);

	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = ulWriteLength;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

第四步:应用层调用验证

应用层通过CreateFile打开符号链接获取句柄,随后直接使用标准的Win32 API ReadFile和WriteFile进行交互。当调用这些API时,线程进入内核态触发对应的派遣函数。

#include <iostream>
#include <Windows.h>

int main(int argc, char *argv[])
{
  HANDLE hDevice = CreateFileA("\\\\.\\LySharkDriver", GENERIC_READ | GENERIC_WRITE, 0,
    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hDevice == INVALID_HANDLE_VALUE)
  {
    CloseHandle(hDevice);
    return -1;
  }

  // 1. 读取数据
  char buffer[128] = { 0 };
  ULONG length;
  ReadFile(hDevice, buffer, 5, &length, 0); 
  printf("读取字节:");
  for (int i = 0; i < (int)length; i++)
  {
    printf("%c", buffer[i]);
  }
  printf("\n");

  // 2. 写入数据
  char write_buffer[] = "hello lyshark";
  ULONG write_length;
  WriteFile(hDevice, write_buffer, strlen(write_buffer), &write_length, 0);

  system("pause");
  CloseHandle(hDevice);
  return 0;
}

以上就是通过ReadFile与内核层通信的详细内容,更多关于C语言驱动开发及系统级数据交换的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。