记录下在公司开发驱动的一些注意事项, 驱动当前仅针对win10x64.
常识:
最早的驱动开发sdk是 ntddk, 类似于用户层的win32 api, 后面为了增加对pnp(Plug-and-Play, 即插即用)的支持, 迭代为 wdm. 后面因为wdm开发过于繁琐, 微软发布了 WDF 框架, 类似于 用户层的 MFC.
ddk和后面2种驱动的最大区别是 : ddk 创建设备是主动的, 而wdm和wdf之后, 创建设备是被动的, 通过设置一个回调函数来创建设备. 所以通常一些安全软件(非驱动类), 通常会选择ddk模板来开发, 而一些硬件或者模拟类的软件会选择wdm和wdf来开发.
ddk开发的驱动, 其实可以简单想象为一个服务, 只是这个服务不是运行在用户层, 而在内核层, 所以通常通过scmanager创建服务即可, 只是服务类型改为驱动.
而wdm和wdf是当设备状态发生变化(系统检测到设备插入, 或模拟强制创建)时, 系统才会回调驱动的create device函数. 并且驱动的安装是需要通过inf文件的, 而inf是比较繁琐的. so....
其实驱动开发并不是什么异常复杂和高深的知识, 只是使用人数少, 并且系统版本的迭代导致要注意的事项比较多. 导致入手比较烦.
sys文件其实跟dll是没什么区别的, 都是pe文件, 都是一个个section段. dll编译的代码和数据段的地址空间都是基于ring3的, 而驱动的地址空间是基于ring0. 内存申请不能使用常见的malloc或者virtualalloc等用户态, 必须用内核态而已. 内核函数运行在哪个进程通常是不能确定的, 理解为HTTP的基于会话方式就行了.
开发环境:
visual studio 2019 + wdk, vs2019 安装常规的C++开发环境即可, WDK安装 [适用于 Windows 10 版本 2004 的 WDK]
工程创建步骤:
新项目类型, 若是kmdf, 建议选下面这个模板
若是wdm, 建议选:
INF文件:
inf文件比较繁琐, 这里就没有粘贴inf文件了, 但是inf的示例注释我已提交到GitHub上 https://github.com/ChinaCCF/devcon, 可自行下载查看.
这里有个要主要的事项是, inf文件中不要保存非ascii编码的字符, 否则安装会失败.
测试环境:
编译好的驱动是不能安装的, 因为没有签名(32驱动不用签名, 随便折腾). 要安装没有签名的驱动也是可以的, 就是配置测试环境, 有2种方式:
一: 强制禁用系统检测
1)Windows设置
2)更新和安全
3)恢复
4)高级启动->立即重新启动
5)疑难解答
6)高级选项
7)启动设置->重启
重启中选择 7 禁用驱动签名
二: 测试模式
管理员权限cmd, 运行命令 : bcdedit /set testsigning on
项目生成的目录 x64\release中, 会包含***.sys, 然后也包含一个工程名的文件夹, 里面也包含一个***.sys, 其区别是, 工程名文件夹里面的***.sys是经过测试签名的, 可以在测试模式下加载, 而 x64\release中的是没有测试签名, 只能在禁用测试环境下加载.
驱动开发的调试比较麻烦, 因为是基于内核的, 不能像普通用户层那样中断, 因为一旦中断, 整个系统都会中断的, 所以需要2台机器来调试, 通常一台是本机, 一台是VMware.
而更为简单的开发方式是通过dbgview查看log. 这软件是微软的.
dbgview 的capture 选择 capture kernel 和 enable verbose kernel output 和 capture events
当显示的日志过多时候, 可以使用filter.
在exclude中输入你要过滤的信息即可. 或者反之也行.
至于双机调试以后有时间补充.
驱动安装:
ntddk的驱动, 自己搜索scmanager 来安装, 或者使用 DriverMonitor.exe 软件来安装
wdm及之后的驱动安装用devcon这个工具, 这工具可以自己编译, 在微软的
Windows-driver-samples\setup\devcon 目录中
注意编译后, 要区分系统是否是64位, 64位系统只能用64位编译的devcon来安装, 否则会报错的
安装命令为 devcon install xyz.inf root\xyz
重复安装的话, 需要先卸载之前安装的实例, 否则会出现很多驱动实例的
卸载命令为 devcon remove root\xyz
但是 devcon 的卸载有个bug, 可能会出现无法卸载驱动的情况, 我自己重写了devcon的卸载, 下载地址 GitHub - ChinaCCF/devcon: 重写了devcon的卸载部分代码
其实到了这一步, 个人开发者参考一些例子和开源代码基本可以随便折腾了.
驱动签名:
把生成好的.cat和.sys文件 用 ev证书 (abc.pfx) 签名. 例如 驱动文件为 xyz.sys
signtool sign /f abc.pfx /p 密码 xyz.sys
signtool 是开发环境附带的, 更详细的使用说明, 可以网上搜索或者参考help.
HXXX公司的签名流程可以查看 公司文档 <<手动签名指引>>.
把签名好的cat和sys和inf文件通过makecab这个工具打包, 这个工具也是开发环境附带的.
makecab所需的ddf文件例子如下:
.OPTION EXPLICIT
.Set CabinetFileCountThreshold=0
.Set FolderFileCountThreshold=0
.Set FolderSizeThreshold=0
.Set MaxCabinetSize=0
.Set MaxDiskFileCount=0
.Set MaxDiskSize=0
.Set CompressionType=MSZIP
.Set Cabinet=on
.Set Compress=on
.Set CabinetNameTemplate=ScpVBus.cab
.Set DestinationDir=abc_dir
C:\learn_driver\build\xyz.inf
C:\learn_driver\build\xyz.sys
C:\learn_driver\build\xyz.cat
####################################################
执行命令:
MakeCab /f "C:\learn_driver\1.ddf"
就会生成一个xxx.cab包. 然后继续用signtool 工具对这个包签名
HXXX公司签名网页是无法对xxx.cab包签名的, 修改后缀名, 把xxx.cab改为xxx.sys, 再签名
到这个时候, 提交到微软的合作伙伴网页, 硬件签名就可以了
避坑注意, 最好不要附带 协注册器的dll, (WdfCoinstaller01009.dll) inf中去掉与这个dll相关的项, 例如 [xxx.NT.CoInstallers], 否则微软的检测时间长不说, 而且在一些Windows10的机器上会安装驱动失败.
附带 一篇知乎上 驱动签名 文章
我都如此慷慨大方把教程和坑点写出来了, 各位大哥来点赞赏吧, 这可是节约了你们大量时间啊.
也让我有动力继续分享好文章