再毕设的压力下,学习了一下驱动开发,下文部分为微软官方文档的翻译,仅当成驱动开发小白摸索。。大佬可绕路
Windows驱动开发初探
开发背景
主要是为了实现一个 当创建新的进程的时候,获取其创建时的函数调用链 这个方案。(迫于时间,最后直接HOOK函数CreateProcess
,然后利用了AppCertDLLS的简单思路。。。 。然后就开始自己瞎找,找到了一个利用驱动实现检测的思路。
关键函数
驱动中有一个函数叫做:PsSetCreateProcessNotifyRoutine
。这个函数原型
1 | NTSTATUS PsSetCreateProcessNotifyRoutine( |
这个函数能够再我们创建进程/删除进程的时候,调用回调函数NotifyRoutine
:
1 | PCREATE_PROCESS_NOTIFY_ROUTINE PcreateProcessNotifyRoutine; |
- ParentId: 父进程ID
- ProcessId: 子进程ID
- Create: 当前进行的是创建还是删除工作
利用这个函数,我们就能够直接检测每一个进程的创建过程,感觉简单了很多。
开发准备
- Visual Studio 2017
- 驱动开发的库不是自带的,得自己去官网上下:WDK
安装好 WDK 之后,我们就能够在VS里面直接看到开发界面找到驱动开发界面:
!()[Windows-Driver-初探/driver00.png]
驱动主要分为两种:
- Kernel-Mode Driver
- User-Mode Driver
由于教程上Kernel-Mode Driver
的教程比较多,这里选择用这个进行入门。
PS:驱动起名字的时候注意,不要超过32个字符,这个是规定
简单入门
首先选择对应版本:
之后,我们修改当前的项目属性,在配置中的Driver Settings -> General
中可以配置我们要发布的驱动对应的平台。
然后再项目处添加一个叫做Driver.c
的文件
这个位置的 Driver.c 注意不要用cpp做后缀,似乎和编译器有关
然后键入下列代码:
1 | // 原先使用的是MSDN上提供的源代码,但是编译后运行的时候,一直提示说“找不到设备”,所以只能够 |
编写完成后,我们修改一下我们工程的配置(为了准备发布),求改模式为DEBUG,并且发布设置为x64
并且不使用Wpp Tracing
之后来到对应文件目录下(x64\Debug\KmdfHelloWorld
)能够找到以下文件
- KmdfHelloWorld.sys: 这个就是
kernel-mode
的驱动文件 - KmdfHelloWorld.inf: 里面记录当sys文件安装的时候需要的信息
- KmdfHelloWorld.cat: 这是一个目录文件,记录了安装程序用来验证驱动程序包的测试签名
测试入门
驱动要运行起来没有别的程序那么简单,得需要另一台独立的机子才能够运行。我们一般把运行调试器的机子叫做host computer,用于运行驱动的机子叫做target computer。
配置流程
这里我们用Vmware
来辅助测试。首先我们装好了一个64bit 的 Windows7。为了实现联机调试,我们要给当前虚拟机添加串口设备:
- 右键当前虚拟机,点击设备,然后位置添加
串口设备
- 在串口设备中,选择使用命名的管道,添加管道
\\.\pipe\DriverDbgPipe
- 注意将命名管道下面的内容选择为:该端为服务器,另一端为应用程序
最终配置情况如下:
Windows中管道的命名规则必须为: \\.\pipe\
然后在管理员权限下,执行以下语句:
1 | bcdedit /set {current} debug yes |
这里的debugport用于指定我们的COM口。我们创建设备的时候,写作串口设备2
,所以这里设置为2。
之后使用windbg
,加上下列参数即可进行调试
1 | .\windbg.exe -b -k com:pipe,port=\\.\pipe\DriverWinDbg,resets=0,reconnect |
Visual Studio 配置
这里使用的是VS2017(后来改成VS2015,配置一致)
- 首先在 host computer 上找到文件
WDK Test Target Setup x86-x86_en-us.msi
- 然后 target computer 中安装这个文件。
- 在 Visual Studio 中打开
Driver->Test->Configure Devices
- Add New Device 添加测试主机,由于我们之前填写debug用的是Serial(串口),那么这里我们也继续使用串口作为调试。首先我们配置主机的IP等如下:
我这边自动安装总是失败,所以这边打算利用VS单纯来调试,安装驱动的时候使用InstDrv - 下一个界面确认如下:
- 最后,如果我们看到这个画面,就说明我们配置成功:
之后我们就能够拿VS来调试啦!
动态调试
- 首先在调试中找到附加到进程
- 连接类型调整成
Windows Kernel Mode Debugger
,连接目标调整成我们的主机,然后选择内核进程:
- 连接之后,会进入如下画面,此时我们按
全部中断
,让整个内核进程停下来
- 如果之前配置没错误的话,就能够挂载进行内核调试。(找不到成功的图了)
然后我们利用工具InstDrv
进行驱动安装,安装好之后启动服务,就能够下调试驱动啦!
PS:用VS调试的时候,可以直接在源代码中下断点进行调试,不过要保证
- 发布的是DEBUG版本的
- 当我们修改了任何源代的内容,都要重新发布并且重新安装。
动态调试 - 网络
这个是最近发现的新的调试方法,好用的一笔
- 首先保证宿主机和虚拟机之间能够ping通
- 在虚拟机中安装winsdk-选择windbg(option)
- 在虚拟机中输入
1 | bcdedit /debug on |
其中ip替换成宿主机IP(非虚拟机)端口替换成空闲端口即可
此时会打印一段key
1 | Key=1xxxxxxxxxxxxxxxx |
- 在宿主机使用windbg,选择kernel debug后选择
Net
,之后端口填写指定的端口,key填写之前给出的key - 重启目标机器,之后即可开始调试
踩坑
- 如果要实现VS远程调试的话,一定要打开
1 | bcdedit /debug on |
设置完之后,一定要重启,最好是关闭虚拟机再打开。
(上面也提过别的打开方式,但是一定要打开,否则windbg会一直处于reconnect wait...
的状态)
-
同样,为了实现VS远程调试,一定要安装:
WDK Test Target Setup x86-x86_en-us.msi
或者
WDK Test Target Setup x64-x64_en-us.msi
否则的话配置HOST那部分无法通过。 -
调试的时候,对于驱动,调试的时候如果要替换当前的驱动,一定要记得卸载,不然的话会卡死
-
之前用VS2017的时候,不知原因一直爆炸。。改成VS2015之后突然可以了。。。理解不能
-
如果要用VS下断点,则此时的调试顺序为:
- 使用VS连接上target 主机
- 当前 Target 载入驱动
如果先载入了驱动,再让VS连上target,此时下载vs里面的断点(指下在代码上的那种)会断不下来。(估计原因是因为载入了驱动后,VS会找不到符号所以无法调试)
- 如果调试内核的时候下了断点(包括用了windbg的那个暂停按钮),需要再调试结束的时候将断点删除,否则的话会造成电脑重新启动的时候显示驱动损坏。原因是因为下断点的时候,一般用的是软中断,也就是会将当前指令替换成0xcc的一种断点。因为内核调试的时候一般退出调试会直接关闭调试模式等,导致此断点的软中断中的指令没有被替换会原来的指令,导致驱动加载错误。
- 有时候,如果target computer打开了防火墙,也会导致无法连接(显示
waiting to reconnect
)