Windows驱动开发入门-应用与内核通信
Windows驱动开发入门-应用与内核通信
内核部分
生成CDO
IoCreateDevice
内核想要与应用通信时,必须生成控制设备对象CDO。
1 | NTSTATUS IoCreateDevice( |
IoCreateDeviceSecure
上面那个有默认安全属性,必须得管理员权限应用才能打开,所以改用这个不安全的来玩。设备GUID理论上要用CoCreateGuid
来生成,但有别的方法比如在线工具:https://www.gjk.cn/guid。
1 | NTSTATUS IoCreateDeviceSecure( |
IoDeleteDevice
删除控制设备。
符号链接
IoCreateSymbolicLink
设备对象DO可以没名字,但控制设备对象CDO需要个名字,这样才可以被暴露出来。暴露给应用层需要建立符号链接。最稳妥的方法还是用GUID比较好,符号链接很容易冲突。当然有一种粗暴的方法就是删除已存在的符号链接再生成一个自己的。
1 | NTSTATUS IoCreateSymbolicLink( |
IoDeleteSymbolicLink
删除符号链接。
分发函数
处理发送给设备对象请求的函数,入口在DriverEntry
中对PDRIVER_OBJECT的MajorFunction中设置。这个MajorFunction记录多个不同请求的处理函数,但我们把它全都设置成该分发函数,然后在分发函数中处理各种请求。标准的分发函数原型:
1 | NTSTATUS DriverDispatcher( |
请求的处理
在分发函数中,需要用IoGetCurrentIrpStackLocation
先获取请求的当前栈空间,然后判断请求是不是发给自己这个驱动的,是的话对请求种类判断,不是的话返回错误即可。最后设置返回输出需要的空间和请求完成状态,最后用IoCompleteRequest
结束请求。
例子
1 |
|
应用部分
应用层一般直接用CreateFile
打开设备,然后用DeviceIoControl
发送请求,发送的请求宏为CTL_CODE,像上面内核部分例子一样使用即可,该宏的使用方法为:
1 | CTL_CODE( |
不讲了直接上例子:
1 |
|
阻塞、等待、安全设计
在这个例子中,限定字符串最大长度为$511$字节,再加一个结束符。输入缓冲区超长的一律返回失败,输出缓冲区最小长度为$512$字节,小于这个长度的一律返回失败即使实际字符串小于这个长度。缓冲区用LIST_ENTRY实现,每次应用层来轮循时卸下一个链表,每个节点为$512$字节,还要用自旋锁来通知应用程序缓冲区有内容可取。
函数KdBreakPoint
和宏ASSERT
千万不要在发行版中使用,否则直接唤起蓝屏。函数strlen
也不要使用,为了寻找结束符而没有限度,搜索到无效空间后唤起蓝屏,应使用strnlen
,同理使用strncpy
。
输出的话如果还使用等待事件则特别繁琐,这里直接用死循环轮循,但为了防止处理器占用率过高,搞个进程休眠使。
内核部分例子:
1 |
|
用户部分例子:
1 |
|