C++第四十篇 -- 研究一下Windows驱动开发(三)-- NT式驱动的基本结构
对于NT式驱动来说,主要的函数是DriverEntry例程、卸载例程及各个IRP的派遣例程。
一、驱动加载过程与驱动入口函数(DriverEntry)
和编写普通应用程序一样,驱动程序有个入口函数,也就是首先被执行的函数。这个函数通常被命名为DriverEntry。该函数的原型为:
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
DriverEntry主要是对驱动程序进行初始化工作,它是由系统进程所调用的。在Windows中有个特殊的进程叫做系统进程,打开进程管理器,里面有个名为System的进程就是系统进程。系统进程在系统启动的时候,就已经被创建了。
驱动加载的时候,系统进程启动新的线程,调用执行体组件中的对象管理器,创建一个驱动对象。这个驱动对象是一个DRIVER_OBJECT的结构体。另外,系统进程调用执行体组件中的配置管理程序,查询此驱动程序对应的注册表中的项。
系统线程调用驱动程序的DriverEntry例程时,同时传进两个参数,分别是DriverObject和RegisreyPath。其中,一个是指向刚才被创建驱动对象的指针,另外一个是指向设备服务键的键名字符串的指针。在DriverEntry中,主要功能是对系统进程创建的驱动对象进行初始化。另外,设备服务键的键名有时候需要保存下来,因为这个字符串不是长期存在的(函数返回后可能消失)。如果以后想使用这个UNICODE字符串就必须先把它复制到安全的地方。
这个字符串的内容一般是Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\服务名。在驱动程序中,字符串用INICODE字符串来表示。UNICODE是宽字符集,每个字符用16位表示。
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
}
》Length:记录这个字符串用多少字节记录。如果字符串有N个字符,那么Length将会是N的2倍。
》MaximumLength:记录buffer的大小,也就是这个结构最大能记录的字节数。MaximumLength要大于或等于Length。
》Buffer:记录字符串的指针。与ASCII字符串不同,这里的字符串每个字符否是16位。
在驱动中可以使用KdPrint打印UNICODE的信息。其语法是:
KdPrint(("%S\n", RegistryPath->Buffer));
或
KdPrint(("%ws", RegistryPath->Buffer));
DriverEntry返回值是NTSTATUS的数据,NTSTATUS是被定义为32位的无符号长整形。在驱动程序开发中,人们习惯用NTSTATUS返回状态。其中0~0X7FFFFFFF,被认为是正确的状态,而0X80000000~0XFFFFFFFF,被认为是错误的状态。有个非常有用的宏——NT_SUCCESS,被用来检测状态是否正确。常用的NTSTATUS值有STATUS_SUCCESS。
DriverEntry的返回值如果表示成功,则意味着加载驱动成功,否则意味着加载驱动失败,调用对象管理程序销毁驱动对象。
最后需要说明的是DriverEntry参数的修饰“IN”。“IN”、“OUT”、“INOUT”在DDK中被定义成空串,它们的功能类似于程序注释,当看到一个“IN”参数时,应该认定该参数是纯粹用于输入目的。“OUT”参数代表这个参数仅用于函数的输出函数。“INOUT”用于既可以输入又可以输出的参数。例如DriverEntry例程,它的DriverObject指针是IN参数,即使用者不能改变这个指针本身,但完全可以改变它指向的对象。
二、创建设备对象
在NT式的驱动中,创建设备对象是由IoCreateDevice内核函数完成的。
NTSTATUS IoCreateDevice{
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
};
》DriverObject:输入参数,每个驱动程序中。会有唯一的驱动对象与之对应,但每个驱动对象会有若干个设备对象。DriverObject指向的就是驱动对象的指针。
》DeviceExtensionSize:输入参数,指定设备扩展的大小,I/O管理器会根据这个大小,在内存中创建设备扩展,并与驱动对象关联。
》DeviceName:输入参数,设置设备对象的特征。
》Exclusive:输入参数,设置设备对象是否为内核模式下使用,一般设置为TRUE。
》DeviceObject:输出参数,I/O管理器负责创建这个设备对象,并返回设备对象的地址。
》返回值:返回此函数的调用状态。
设备名称用UNICODE字符串指定,并且字符串必须是“\Device\[设备名]”的形式。在Windows下的所有设备都是以类似名字命名的,例如,磁盘分区的C盘、D盘、E盘、F盘就是被命名为“\Device\Harddisk Volume1”、“\Device\HarddiskVolume2”、“\Device\HarddiskVolume3”、“\Device\HarddiskVolume4”.
当然也可以不指定设备名字,如果在IoCreateDevice中没有指定设备对象的名字,I/O管理器会自动分配一个数字作为设备的设备名,例如,“\Device\00000001”、“\Device\00000002”、“\Device\00000003”.
如果指定了设备名,只能被内核模式下的其他驱动所识别。但是在用户模式下的应用程序无法识别这个设备。让用户模式下的应用程序能识别设备有两种办法,第一种是通过符号链接找到设备,第二种是通过设备接口找到设备。设备接口的办法在NT驱动中很少使用。
符号链接可以理解为设备对象起了一个“别名”。设备对象的名称只能被内核模式的驱动识别,而别名也可以被用户模式下的应用程序十倍。例如,常说的C盘、D盘就是符号链接。所谓的C盘,指的是名为“C:”的符号链接,其真正的设备对象是“\Device\HarddiskVolume1”,创建符号链接的函数是IoCreateSymbolicLink,其函数声明如下。
121页。
C++第四十篇 -- 研究一下Windows驱动开发(三)-- NT式驱动的基本结构的更多相关文章
- 用Visual Studio 2015 编译张帆的第一个NT式驱动,并且成功安装到Windows XP里面!!!
开发工具:Visual Studio 2015 企业版 目 标 机:Windows XP X86 前提:我们已经成功安装了Visual Studio 2015以及WDK,而且更重要一点是一定要SDK版 ...
- C++第三十八篇 -- 研究一下Windows驱动开发(二)--WDM式驱动的加载
基于Windows驱动开发技术详解这本书 一.简单的INF文件剖析 INF文件是一个文本文件,由若干个节(Section)组成.每个节的名称用一个方括号指示,紧接着方括号后面的就是节内容.每一行就是一 ...
- C++第三十三篇 -- 研究一下Windows驱动开发(一)内部构造介绍
因为工作原因,需要做一些与网卡有关的测试,其中涉及到了驱动这一块的知识,虽然程序可以运行,但是不搞清楚,心里总是不安,觉得没理解清楚.因此想看一下驱动开发.查了很多资料,看到有人推荐Windows驱动 ...
- C++第三十九篇 -- 研究一下Windows驱动开发(二)-- 驱动程序中重要的数据结构
数据结构是计算机程序的核心,I/O管理器定义了一些数据结构,这些数据结构是编写驱动程序时所必须掌握的.驱动程序经常要创建和维护这些数据结构的实例. 一.驱动对象(DRIVER_OBJECT) 每个驱动 ...
- Python之路(第四十篇)进程池
一.进程池 进程池也是通过事先划分一块系统资源区域,这组资源区域在服务器启动时就已经创建和初始化,用户如果想创建新的进程,可以直接取得资源,从而避免了动态分配资源(这是很耗时的). 线程池内子进程的数 ...
- 第四十篇:Vue的生命周期(一)
好家伙,军训结束了,回归 Vue实例的生命周期 1.什么是生命周期? 从Vue实例创建,运行到销毁期间总是伴随着各种各样的事件,这些事件,统称为生命周期. 2.什么是生命周期钩子? 生命周期函数的别称 ...
- Android UI开发第四十篇——ScrollTricks介绍
ScrollTricks是一个开源控件,实现了两个简单功能: 1.Quick Return:向上滑动时,View也向上滑动并且消失,当向下滑动时,View马上出现.例如Google Now的搜索功能. ...
- 第四十篇-private,public,protected的区别
1.public: public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private: private表示私有,私有的意思就是除了class自己之外,任何人都不可 ...
- 第四十篇 Python之设计模式总结-简单工厂、工厂方法、抽象工厂、单例模式
一. 简单工厂 简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 简单工厂的用处不大,主要就是一个if... ...
随机推荐
- OpenCV开发实战1——抖音哈哈镜效果
前言 在抖音中,我们经常看到各种抖音玩家都喜欢使用哈哈镜效果.那么什么是哈哈镜呢? 在现实生活中,哈哈镜是指一种表面凹凸不平的镜子,可以反应出人像及物体的扭曲面貌.简单点来说就是拉伸人脸(物件),或者 ...
- HR面试:过五关斩六将后,小心阴沟翻船!(史上最全、避坑宝典)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- 剖析虚幻渲染体系(06)- UE5特辑Part 1(特性和Nanite)
目录 6.1 本篇概述 6.1.1 本篇内容 6.1.2 基础概念 6.2 UE5新特性 6.2.1 UE5编辑器 6.2.1.1 下载编辑器及资源 6.2.1.2 启动示例工程 6.2.1.3 编辑 ...
- Room-数据持久化存储(入门)
@ 目录 一.简单使用 1.Entity 2.Dao 3.DataBase 4.使用 二.参数解析 1.Entity 2.Dao 3.查询方式 总结 # 前言 官方简介: Room 持久性库在 SQL ...
- Centos7安装配置jenkins(Tomcat)
Centos7安装配置jenkins(Tomcat) 一.准备工作 1.1 安装JDK1.8 具体安装过程不在赘述. 1.2 下载jenkins的war包 jenkins官网下载地址:https:// ...
- windows下Docker Desktop安装管理
检查要求 Windows 10 企业版.专业版或教育版 (必须windows10 1903版本以上)版本号 18362.1049+ 或 18363.1049+ ,次版本#大于.1049.最好是最新版( ...
- 17、linux root用户密码找回
17.1.救援模式: 光盘模式启动(第一启动项) 删除/mnt/sysimage/etc/passwd root的密码,halt重启. 改为硬盘启动模式,无密码进入root,为root新建密码 17. ...
- 使用Oracle SQL Developer报错:Unable to find a Java Virtual Machine
1.环境 win7 x64,oracle 11g r2,jdk6 x64 2.问题 第一次启动Oracle SQL Developer的时候会让我们填写java.exe的路径,我在jdk安装目录下的b ...
- Gym - 101128E Wooden Signs DP
题目大意: 一共n块木板,前两个数给出最底下木块的两个端点,后面n-1个数给出第i层的一个固定端点,问你木块的所有放置情况. 分析: 状态: d[i][j]表示第i个木块,第i-1块木板的未固定端点为 ...
- 为什么使用 LSTM 训练速度远大于 SimpleRNN?
今天试验 TensorFlow 2.x , Keras 的 SimpleRNN 和 LSTM,发现同样的输入.同样的超参数设置.同样的参数规模,LSTM 的训练时长竟然远少于 SimpleRNN. 模 ...