
Windows驱动与用户态程序通信机制总结IOCTL用户态程序使用DeviceIoControlIO管理器创建一个IRP_MJ_DEVICE_CONTROL请求发送给驱动程序驱动程序在对应的派遣函数中进行处理。根据缓冲区传递的方式的不同由CTL_CODE的参数决定又可以细分为三种类型1. METHOD_BUFFERED如果指定了该参数IO管理器会根据用户态程序提供的缓冲区长度分配内核缓冲区并复制用户缓冲区到内核非分页池驱动通过Irp-AssociatedIrp.SystemBuffer访问。2. METHOD_IN_DIRECT / METHOD_OUT_DIRECT用户缓冲区被锁定驱动通过 Irp-MdlAddress获取 MDL 来访问物理内存。3. METHOD_NEITHER直接传递用户模式地址驱动需在发起线程上下文中谨慎访问。ReadFile/WriteFile用户态程序通过 ReadFile和 WriteFile与驱动通信分别对应驱动的 IRP_MJ_READ和 IRP_MJ_WRITE分发例程。通过在创建设备时指定Flag属性又可以将该种通信方式细分为三种DO_BUFFERED_IO以缓冲区方式写设备时操作系统将WriteFile提供的用户模式的缓冲区复制到内核模式地址下。这个地址由WriteFile创建的IRP的AssociatedIrp.SystemBuffer子域记录。DO_DIRECT_IO除了“缓冲区”方式读写设备外另外一种方式是直接方式读写设备。这种方式需要创建完设备对象后在设置设备属性的时候设置为DO_DIRECT_IO。直接方式读写设备操作系统会将用户模式下的缓冲区锁住。然后操作系统将这段缓冲区在内核模式地址再次映射一遍。这样用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存。无论操作系统如何切换进程内核模式地址都保持不变。操作系统先将用户模式的地址锁定后操作系统用内存描述符表MDL数据结构记录这段内存。其他方式读写操作在调用IoCreateDevice创建设备后对pDevObj-Flags既不设置DO_BUFFERED_IO也不设置DO_DIRECT_IO此时采用的读写方式就是其他读写方式。在使用其他方式读写设备时派遣函数直接读写应用程序提供的缓冲区地址。在驱动程序中直接操作应用程序的缓冲区地址是很危险的。只有驱动程序与应用程序运行在相同线程上下文的情况下才能使用这种方式。用其他方式读写时ReadFile或者WriteFile提供的缓冲区内存地址可以在派遣函数中通过IRP的pIrp-UserBuffer字段得到。读取的字节数可以从I/O堆栈中的stack-Parameters.Read.Length字段中得到。使用用户模式的内存时要格外小心因为ReadFile有可能把空指针地址或者非法地址传递给驱动程序。因此驱动程序使用用户模式地址。Shared Memeory共享内存通常结合事件Event 或信号量实现同步。应用程序创建事件对象将句柄传递给驱动驱动在数据就绪后设置事件状态。有两种实现方式驱动分配并映射驱动调用 MmAllocatePagesForMdl或 ExAllocatePool分配非分页内存创建 MDL然后通过 MmMapLockedPagesSpecifyCache将其映射到用户进程地址空间。用户态程序提供缓冲区应用程序分配内存将其地址和长度通过IOCTL发送给驱动驱动通过MDL锁定并访问。总结除了上面提到的方式还可以WMI、pipe、邮槽、RPC等通信方式。