简单的管道实现
这个工程的实现非常简单,在这部分,我们要看看这个驱动是怎样运作的?并且思考下我们怎样来提高它的执行效率?另外还会包括如何使用这个样本驱动?
安全
很简单,这里没有!驱动本身完全没设置安全,所以我们不需要关心谁被允许从缓冲区中读写数据。既然我们不关心,这个IPC(进程间的通讯)可以被用在任何进程之间,不管用户和他们的权限。
环形缓冲区
环形缓冲是一种简单的实现,它永远不会阻塞读或者写。缓冲区的大小是不可配置的,因此我们在应用程序中使用硬编码。我们也可以创建我们自己的IOCTL来发送请求给驱动。在IOCTL中可以实现一些配置,例如设置缓冲区的大小等等。
示例流程图
这是一个简单的流程图,CreateFile() API会使用符号连接"Example"来引用这个对象。 I/O管理器映射 DOS设备名为NT设备"\Device\Example",并且会追加上我们放在后面的字符串"\TestPipe"。我们得到由I/O管理器创建的IRP, 首先用这个设备字符串查询是否已经创建了资源上下文。如果是,我们使用栈单元中的FileObject,在增加其引用后,来放置我们的资源上下文。如果没有创建资源上下文,我们需要首先来创建它。
在FILE_OBJECT的FileName中 实际上仅仅包含了额外的"\TestPipe",例如下面的例子:
dt _FILE_OBJECT ff6f3ac0
+0x000 Type : 5
+0x002 Size : 112
+0x004 DeviceObject : 0x80deea48
+0x008 Vpb : (null)
+0x00c FsContext : (null)
+0x010 FsContext2 : (null)
+0x014 SectionObjectPointer : (null)
+0x018 PrivateCacheMap : (null)
+0x01c FinalStatus : 0
+0x020 RelatedFileObject : (null)
+0x024 LockOperation : 0 ''
+0x025 DeletePending : 0 ''
+0x026 ReadAccess : 0 ''
+0x027 WriteAccess : 0 ''
+0x028 DeleteAccess : 0 ''
+0x029 SharedRead : 0 ''
+0x02a SharedWrite : 0 ''
+0x02b SharedDelete : 0 ''
+0x02c Flags : 2
+0x030 FileName : _UNICODE_STRING "\HELLO"
+0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
+0x040 Waiters : 0
+0x044 Busy : 0
+0x048 LastLock : (null)
+0x04c Lock : _KEVENT
+0x05c Event : _KEVENT
+0x06c CompletionContext : (null)
下图是关于ReadFile的操作流程,既然我们在 FILE_OBJECT中分配了我们的上下文,当我们读数据的时候,我们可以直接访问环形缓冲区。
下图是关于WrteFile 的操作流程,既然我们在 FILE_OBJECT中分配了我们的上下文,当我们写数据的时候,我们可以直接访问环形缓冲区。
关 闭时,我们释放资源上下文的引用。如果上下文引用计数为0,我们就从全局链中将它删除。如果不是0,我们就不需要做什么。这里是一个简单的流程,我们正在 处理的是IRP_MJ_CLOSE而不是 IRP_MJ_CLEANUP。这个代码可以放在任何一个不与用户模式应用程序交互的地方。然而,如果我们需要 在应用程序的上下文中释放资源,我们就需要把这个放到IRP_MJ_CLEANUP中。由于IRP_MJ_CLOSE不保证运行在进程上下文中,这个流程更像是处理IRP_MJ_CLEANUP发生的事情。
使用例子
本 例中分为两个用户进程,usedriver2 和usedriver3。userdriver2 允许你输入数据,并将他发送到驱动。 userdriver3 输入回车并且从驱动中读取数据。很明显,目前的实现方式,如果他读了多个字符串,你只会看到只有第一个字符串显示出来。
需 要提供一个参数,即: 要打开的资源的名字。这是个任意的名字,用来允许驱动将两个实例句柄绑定在一起,这样,多个应用可以在同一时间共享数据。 “usedriver 2 HELLO” “usedriver3 HELLO” “userdriver2 Temp” “usedriver3 Temp” 会打开\Device\Example\HELLO和
“\Device\Example\Temp” 。当前的实现创建资源是大小写无关的。RtlCompareUnicodeString 的最后一个参数指明了是大小写敏感还是大小写无关。
本篇,我们学习了一些关于用户模式与内核模式的交互,了解了怎样实现一个简单的进程间通讯。我们学习了在设备驱动中创建上下文以及怎样分配内存和怎样在内核中使用同步对象。