全文使用Markdown编写,具体请看Markdown 菜鸟教程
一些天天看的概念:WDM / NT 驱动(都是老驱动,淘汰掉了)KMDF/UMDF才是现代化的驱动,本文讲述的是NT或者WDM
这本书阅读宗旨:《竹林蹊径》代码和工具全部已过时,WDM已经过时,KMDF才是现代精髓。
1.1 从Helloworld开始
- P2
- 看一下代码示例1-1
- 重点关注两个入参DriverObject以及RegistryPath
- P3
- 驱动程序编译后是.sys文件,属于PE文件格式的一种。延伸:.dll、.exe 也属于微软PE文件格式
- NTDDK.h是NT驱动的头文件,延伸:Windows驱动开发(一)序言
- DriverEntry是入口函数,类似于Win32编程的WinMain函数或者Dll编程的DllMain函数
- DriverObject是驱动对象的指针,RegisteryPath是注册表子键的字符串指针
- __in和__out只是宏定义,没有任何有效的含义。
- P4
- DbgPrint是C语言的printf函数,需要借助别的工具才能看到
- 如何编译?需要微软的WDK,详情请看第二章
1.1.1 HelloDRIVER
- P4
- HelloDriver 头文件
- 注意结构体DEVICE_EXTENSION有三个成员,设备对象+设备名称+符号链接名称(这个不知道干嘛的)
- 还有几个函数DriverEntry DriverUnload DefaultDispatch
- P5 P6 P7 P8
- 这4页是源代码文件,每个函数,每一行代码都要自问自答解释一遍,看不懂的往后面翻有解释
1.1.2 代码解释
- P9
- 提到一本书编程匠艺--编写卓越代码和代码大全
- 这里提到 P4-helloDriver.h中的结构体DEVICE_EXTENSION是自定义的,不是官方的
- 有用的是016-018行的解释。这里有点晦涩,举三个具体的实例秒懂。
#pragma alloc_text(INIT, DriverEntry) // DriverEntry 只在初始化时调用 → INIT #pragma alloc_text(PAGE, DispatchCreate) // 普通派遣函数 → PAGE(可省略,就是可以完全不用加#pragma) #pragma alloc_text(NONPAGED, MyIsr) // 中断服务例程 → NONPAGED- 027行 DriverEntry是由操作系统内核的I/O管理器调用
- P10
- 039行KdPrint是对DbgPrint的宏封装,在Release中自动移除
- Debug和Release在驱动中被称为:Check和Free版
- 041行 UNREFERENCED_PARAMETER是一个宏,避免警告,这在内核开发中是个好习惯
- 043行 RtlInitUnicodeString(&deviceName, L"\Device\HelloDriver");微软内核采用UnicodeUnicode/UTF-8科普
- 046-049行 遍历所有派遣函数,max=IRP_MJ_MAXIMUM_FUNCTION 指定默认派遣函数
- 051行 卸载函数,如果你不卸载可以不提供
- 052-055行 提供的创建、关闭、读、写函数
- P11
- 058行 IoCreateDevice创建设备对象,重点关注设备类型FILE_DEVICE_UNKNOWN独占设备
- 070行 BUFFERED_IO和DO_DIRECT_IO代表了两种缓冲区处理方式
- 079-085使用IoCreateSymbolicLink创建了设备符号链接,这个符号连接是用来和应用程序通信
- 驱动设备的设备名称,应用程序不知道,只能用符号链接和驱动通信
- 098行 在DriverUnload中要释放哪些资源,设备对象是一个链表,需要遍历释放符号链接和设备对象
- 031行 在DefaultDispatch中直接完成输入输出请求包,IRP
小结 以后这种对代码的说明看代码即可,上面的这一堆就凑合看看,算是踩坑