windows
设备对象名称(内核对象必须命名才能被用户层访问产生句柄)
- \Driver\ 内核模式下访问
- \.\ 用户模式下访问
winObj(symbollink设备名称的别名,各个节点查看)和devicetree等工具可查看,下载地址:http://www.osronline.com/
- 设备节点driverNode,对应不同的设备资源PCI、USB等
- 设备树,pnp管理的设备内部维护一个动态树
- 设备堆栈driverStack,fdo、pdo、do组成设备栈(devtree的单个分支),irp从设备栈的顶层向底层传递,iocompelete从底层向顶层返回状态
- 设备对象driverdeObject,一个设备至少一个设备对象,设备对象用户io请求响应,IoCreateDevice创建(需要指定devicetype,例如 FILE_DEVICE_UNKNOWN ),IoAttachDeviceToDeviceStack加入堆栈,DEVICE_EXTENSION用户自定义
分层模型
- driver_object(结构未开放)和device_object,driver包含多个device对象的链表
- device包含多个文件对象file_object
- file_object接收多个irp数据包(内核和应用层隔离通过磁盘交互,需要文件对象)
不同设备的驱动使用不同结构,显卡设备函数地址存储在VIDEO_HW_INITIALIZATION_DATA中,修改函数地址即可自定义设备驱动
三种驱动程序
- 总线驱动程序(负责和具体的硬件设备交互),单个 I/O 总线设备,并提供与设备无关的单槽功能,创建设备对象=>PDO
- 功能驱动程序(设备功能的具体实现),驱动单个设备,创建设备对象=>FDO
- 筛选器驱动,筛选设备的 I/O 请求、设备类或总线(使用ObReferenceObjectByHandle打开设备修改驱动关联的函数),创建设备对象=>DO
API
- Io,IO管理
- Ex,内存分配
- Ke,内核对象调用函数,不能分页
- Rtl,字符串内存操作
- Zw、NT,文件和注册表操作
- Ps,进程、线程
内核用户层数据交换
- DO_BUFFERED_IO,内存小,效率低
- DO_DIRECT_IO,内存大(浪费多),效率高
内核执行级别
- CPU有0~3级的4个执行级别,ring0和ring3是操作系统使用的级别
- wdm里面的代码不都是Kernel、有的运行在管理模块Executive中,内核代码不支持分页,管理成的代码都应加上PAGED_CODE
- PAGED_CODE()只有check版本有效,当前函数执行级别>=DISPATCH_LEVAL只能使用非分页内存,使用分页内存assert中断,避免free版本蓝屏
- #pragma alloc_text()允许函数页面回退
内核对象
- 对象名称
- 对象管理器ObReferenceObject引用+1
IRP
- irp的目标是driverObject的成员FileObject,指向各个设备文件
- startio(设备忙排队等待)和多线程
- irp状态决定了io状态,同步io、异步io、延迟io,IoCompleteRequest调用IoComplete函数
- 内存指针MdlAddress 、AssociatedIrp、SystemBuffer
- IoStartPacket、IoStartNextPacket遍历irp调用startio
- fastio,文件系统专用
- 用户层请求通过服务管理器做api映射后,传入io管理器,查询指定设备
工具:https://github.com/MartinDrab/IRPMon/releases/tag/v1.0-rc
注释
参考:https://docs.microsoft.com/zh-cn/windows-hardware/drivers/devtest/sal-2-annotations-for-windows-drivers
锁
- 自旋锁,线程不睡眠高效,占用CPU一般用于代码量较少情况
- 删除锁,避免处理过程中设备被删除,IoAcquireRemoveLock、IoReleaseRemoveLock释放
内核交互
- mmap(linux的方式,内核物理内存,应用层虚拟内存,通过共享内存映射内核到文件上(磁盘交互的方式),实现应用层对内核的快速访问),windows可以参考wdm安装包sample中的video,mirror模块disp
- deviceIoControl
- createfile、deletefile、openfile、createdc(参考video的mirror示例)
其他
- CONTAINING_RECORD已知成员地址,求首地址,(&(struct *)0)->member不会报错
- isr中断服务函数,irql level中断处理级别
- irql中断最高级别dirql处理中断
- DISPATCH_LEVEL级别处理dpc队列
- APC_LEVEL处理回调apc
- PASSIVE_LEVEL处理driverentry等分发函数
- umdf的接口IDriverEntry
- hardware id 标识inf文件
- 每个线程都有一个APC队列,用户线程在唤醒和睡眠前(可警醒状态未真正睡眠)都会先执行apc队列中的函数
- 驱动安装setupapi或者cmapi(pnp安装)
WDM
WDM、WDF(WDM基础上架构的开发框架)
- NT驱动通过服务安装(服务通过sc命令查询)
- WDM驱动inf、cat、cer文件安装
windows ssdt hook技术
InstallSysServiceHook函数在driverentry中替换原有的函数地址
https://www.cnblogs.com/BoyXiao/archive/2011/09/04/2166596.html
linux
- 字符设备,能够像字节流(类似文件)一样被访问的设备
- 块设备,设备每次只能传输一个或多个完整的块,而每块包含512字节
- 网络设备
- driver注册和注销,int driver_register(struct device_driver *drv)
- bus注册和注销,bus_register(struct bus_type *bus)
- device注册和注销,int device_register(struct device *dev)
驱动安装
- 静态加载,把驱动程序直接编译进内核,系统启动后可以直接调用,重新下载(源码下载地址:https://www.kernel.org/)和编译内核,效率较低
- 动态加载,下载linux内核源码,使用内核工具编译成模块,系统启动后用insmod命令添加模块(.ko),在不需要的时候用rmmod命令卸载模块
linux的三个基本构件是:引导系统(boot loader), linux内核,根文件系统,包含3个基本构件可以生成镜像img文件,busybox可以生成最小文件系统
参考
micosoft:https://docs.microsoft.com/zh-cn/windows-hardware/drivers/kernel/
linux:https://www.cnblogs.com/Bright-Ho/p/5497481.html