15、Windows驱动开发技术详解笔记(11) 基本概念

简介: 9、Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern。 驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++的new函数都不能用,因为他们在VC中的实现都是调用了Win32 API了。

9Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern

驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++new函数都不能用,因为他们在VC中的实现都是调用了Win32 API了。要用的话,必须自己重载new等运算符。大部分运行时函数是通过Win32 API实现的。在内核模式下无法调用用户模式的程序,而用户模式下通过参数审核可以调用内核态程序。

内核态的运行时函数来替换用户态的运行时函数,一般形如RtlXXXX

设备名称用UNICODE字符串指定,且必须是“\Device\[设备名]”形式。用户模式下,通过两种方法找到设备:

1:符号连接

2:通过设备接口。

一般虚拟设备用FILE_DEVICE_UNKNOWN类型。

******************

"采用C++编程,所以需要用extern "C",因为我们导入的是C的函数的符号表",系统内核是有C语言编写的,连接时要调用相应的函数,所以应当把驱动头文件编译成C语言形式。

10、用build编译

Build首先设置环境变量,然后调用nmakenmake解析makefile,调用cl,link来编译程序。

Makefile中依赖关系如下声明:

ABC

Action

说明:A依赖于BC。如果A的最后修改时间早于BC任一个文件的最后修改时间,则执行actionAction前面是tab

VC编译,我们在另一篇中论述。

11、查看调试信息

法一:打印信息

尽量用KdPrint,free版本中不显示。同prrinf使用,双括号,宽字符用%ws%S

法二:用DriverStudio中的DriverMonitor。不过可以用免费的DbgView,下载地址是:

http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx

12、加载驱动

NT式驱动程序的加载,是基本服务的方式加载的。设备驱动程序的动态加载主要由服务控制管理程序(SCM)系统组件完成的。Windows服务应用程序遵循控制管理器。Driver ServiceWindows服务的一个特例,它遵守Windows服务的协议。

wps_clip_image-28690

图 加载 P72

wps_clip_image-15815

图 卸载驱动流程 P72

代码 加载和卸载驱动代码

代码
 
   
1 #include < windows.h >
2 #include < winsvc.h >
3 #include < conio.h >
4 #include < stdio.h >
5
6   #define DRIVER_NAME "HelloDDK"
7   #define DRIVER_PATH "..\\MyDriver\\MyDriver_Check\\HelloDDK.sys"
8
9 // 装载NT驱动程序
10 BOOL LoadNTDriver( char * lpszDriverName, char * lpszDriverPath)
11 {
12 char szDriverImagePath[ 256 ];
13 // 得到完整的驱动路径
14 GetFullPathName(lpszDriverPath, 256 , szDriverImagePath, NULL);
15
16 BOOL bRet = FALSE;
17
18 SC_HANDLE hServiceMgr = NULL; // SCM管理器的句柄
19 SC_HANDLE hServiceDDK = NULL; // NT驱动程序的服务句柄
20
21 // 打开服务控制管理器
22 hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
23
24 if ( hServiceMgr == NULL )
25 {
26 // OpenSCManager失败
27 printf( " OpenSCManager() Faild %d ! \n " , GetLastError() );
28 bRet = FALSE;
29 goto BeforeLeave;
30 }
31 else
32 {
33 /// /OpenSCManager成功
34 printf( " OpenSCManager() ok ! \n " );
35 }
36
37 // 创建驱动所对应的服务
38 hServiceDDK = CreateService( hServiceMgr,
39 lpszDriverName, // 驱动程序的在注册表中的名字
40 lpszDriverName, // 注册表驱动程序的 DisplayName 值
41 SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
42 SERVICE_KERNEL_DRIVER, // 表示加载的服务是驱动程序
43 SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
44 SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
45 szDriverImagePath, // 注册表驱动程序的 ImagePath 值
46 NULL,
47 NULL,
48 NULL,
49 NULL,
50 NULL);
51
52 DWORD dwRtn;
53 // 判断服务是否失败
54 if ( hServiceDDK == NULL )
55 {
56 dwRtn = GetLastError();
57 if ( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
58 {
59 // 由于其他原因创建服务失败
60 printf( " CrateService() Faild %d ! \n " , dwRtn );
61 bRet = FALSE;
62 goto BeforeLeave;
63 }
64 else
65 {
66 // 服务创建失败,是由于服务已经创立过
67 printf( " CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n " );
68 }
69
70 // 驱动程序已经加载,只需要打开
71 hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );
72 if ( hServiceDDK == NULL )
73 {
74 // 如果打开服务也失败,则意味错误
75 dwRtn = GetLastError();
76 printf( " OpenService() Faild %d ! \n " , dwRtn );
77 bRet = FALSE;
78 goto BeforeLeave;
79 }
80 else
81 {
82 printf( " OpenService() ok ! \n " );
83 }
84 }
85 else
86 {
87 printf( " CrateService() ok ! \n " );
88 }
89
90 // 开启此项服务
91 bRet = StartService( hServiceDDK, NULL, NULL );
92 if ( ! bRet )
93 {
94 DWORD dwRtn = GetLastError();
95 if ( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )
96 {
97 printf( " StartService() Faild %d ! \n " , dwRtn );
98 bRet = FALSE;
99 goto BeforeLeave;
100 }
101 else
102 {
103 if ( dwRtn == ERROR_IO_PENDING )
104 {
105 // 设备被挂住
106 printf( " StartService() Faild ERROR_IO_PENDING ! \n " );
107 bRet = FALSE;
108 goto BeforeLeave;
109 }
110 else
111 {
112 // 服务已经开启
113 printf( " StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! \n " );
114 bRet = TRUE;
115 goto BeforeLeave;
116 }
117 }
118 }
119 bRet = TRUE;
120 // 离开前关闭句柄
121 BeforeLeave:
122 if (hServiceDDK)
123 {
124 CloseServiceHandle(hServiceDDK);
125 }
126 if (hServiceMgr)
127 {
128 CloseServiceHandle(hServiceMgr);
129 }
130 return bRet;
131 }
132
133 // 卸载驱动程序
134 BOOL UnloadNTDriver( char * szSvrName )
135 {
136 BOOL bRet = FALSE;
137 SC_HANDLE hServiceMgr = NULL; // SCM管理器的句柄
138 SC_HANDLE hServiceDDK = NULL; // NT驱动程序的服务句柄
139 SERVICE_STATUS SvrSta;
140 // 打开SCM管理器
141 hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
142 if ( hServiceMgr == NULL )
143 {
144 // 带开SCM管理器失败
145 printf( " OpenSCManager() Faild %d ! \n " , GetLastError() );
146 bRet = FALSE;
147 goto BeforeLeave;
148 }
149 else
150 {
151 // 带开SCM管理器失败成功
152 printf( " OpenSCManager() ok ! \n " );
153 }
154 // 打开驱动所对应的服务
155 hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );
156
157 if ( hServiceDDK == NULL )
158 {
159 // 打开驱动所对应的服务失败
160 printf( " OpenService() Faild %d ! \n " , GetLastError() );
161 bRet = FALSE;
162 goto BeforeLeave;
163 }
164 else
165 {
166 printf( " OpenService() ok ! \n " );
167 }
168 // 停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
169 if ( ! ControlService( hServiceDDK, SERVICE_CONTROL_STOP , & SvrSta ) )
170 {
171 printf( " ControlService() Faild %d !\n " , GetLastError() );
172 }
173 else
174 {
175 // 打开驱动所对应的失败
176 printf( " ControlService() ok !\n " );
177 }
178 // 动态卸载驱动程序。
179 if ( ! DeleteService( hServiceDDK ) )
180 {
181 // 卸载失败
182 printf( " DeleteSrevice() Faild %d !\n " , GetLastError() );
183 }
184 else
185 {
186 // 卸载成功
187 printf( " DelServer:eleteSrevice() ok !\n " );
188 }
189 bRet = TRUE;
190 BeforeLeave:
191 // 离开前关闭打开的句柄
192 if (hServiceDDK)
193 {
194 CloseServiceHandle(hServiceDDK);
195 }
196 if (hServiceMgr)
197 {
198 CloseServiceHandle(hServiceMgr);
199 }
200 return bRet;
201 }
202
203 void TestDriver()
204 {
205 // 测试驱动程序
206 HANDLE hDevice = CreateFile( " \\\\.\\HelloDDK " ,
207 GENERIC_WRITE | GENERIC_READ,
208 0 ,
209 NULL,
210 OPEN_EXISTING,
211 0 ,
212 NULL);
213 if ( hDevice != INVALID_HANDLE_VALUE )
214 {
215 printf( " Create Device ok ! \n " );
216 }
217 else
218 {
219 printf( " Create Device faild %d ! \n " , GetLastError() );
220 }
221 CloseHandle( hDevice );
222 }
223
224 int main( int argc, char * argv[])
225 {
226 // 加载驱动
227 BOOL bRet = LoadNTDriver(DRIVER_NAME,DRIVER_PATH);
228 if ( ! bRet)
229 {
230 printf( " LoadNTDriver error\n " );
231 return 0 ;
232 }
233 // 加载成功
234
235 printf( " press any to create device!\n " );
236 getch();
237
238 TestDriver();
239
240 // 这时候你可以通过注册表,或其他查看符号连接的软件验证。
241 printf( " press any to unload the driver!\n " );
242 getch();
243
244 // 卸载驱动
245 UnloadNTDriver(DRIVER_NAME);
246 if ( ! bRet)
247 {
248 printf( " UnloadNTDriver error\n " );
249 return 0 ;
250 }
251
252 return 0 ;
253 }
254
255

 

关于WDM驱动的手工加载,见[1]

13NT驱动程序的基本结构

1)数据结构

DEVICE_OBJECT

The DEVICE_OBJECT structure is used by the operating system to represent a device object. A device object represents a logical, virtual, or physical device for which a driver handles I/O requests.

http://msdn.microsoft.com/en-us/library/ff543147%28VS.85%29.aspx

每个设备对象指针指向向一个设备对象,最后一个设备对象指向空。

wps_clip_image-28693

图 设备对象布局图 P92

设备扩展对象定义自己定义的结构体,驱动程序中尽是避免使用全局变量,因为会影响同步,而把全局变量存在设备扩展里。

driver object

Each driver object represents the image of a loaded kernel-mode driver. A pointer to the driver object is an input parameter to a driver's DriverEntry, AddDevice, and optional Reinitialize routines and to its Unload routine, if any.

每个驱动程序与唯一的驱动对象相对应,这个驱动对象是在驱动加载时候,被内核中的对象管理器创建。驱动对象为驱动和个实例被内核加载,并且一个驱动只能加载一个实例。

wps_clip_image-26564

图 驱动对象布局图 P88

其它参见:

http://www.cnblogs.com/mydomain/archive/2010/10/16/1853235.html

14DriverEntry主要是对系统进程创建的驱动对象进行初始化。

15WDM程序的基本结构

一般都是基于分层的,完成一个设备的操作,至少要由两个驱动设备共同完成。一个是PDO(物理设备对象),一个是FDO(功能设备对象),其关系是附加与被附加关系。当PC中插入某个设备时,总线驱动自动创建PDO,由PDO引出FDO

wps_clip_image-5558

FDOPDO P103

过滤驱动不是必须的。

NT的不同:

· 增加了对AddDevice函数的设备。操作系统加载PDO后,调用驱动的AddDevice例程,AddDevice例程负责创建FDO,并且附加到PDO之上。

·设备对象在AddDevice例程中创建。

·必须加入IRP_MJ_PNP的派遣回调函数。

PDO会通过AttachedDevice子域知道它上面的设备是FDO或过滤驱动,但是不知道下面的,可以通过定制自己的设备扩展来记录地址。

16、设备的层次结构

wps_clip_image-24338

图 设备对象堆栈 P104

wps_clip_image-4820

图 垂直结构 P111,P113

参考

1Windows 驱动开发技术详解

2http://msdn.microsoft.com/en-us/library/ff565757%28VS.85%29.aspx
3Windows驱动学习笔记,灰狐

目录
相关文章
|
9天前
|
IDE 关系型数据库 开发工具
使用Visual Basic进行Windows窗体开发
【4月更文挑战第27天】本文介绍了使用Visual Basic进行Windows窗体(WinForms)开发的步骤,从搭建开发环境到创建、设计用户界面,再到编写事件驱动的代码和数据绑定。Visual Basic结合WinForms提供了一种易学易用的桌面应用开发方案。通过调试、优化、部署和维护,开发者可以构建专业应用程序。随着技术发展,掌握最新UI设计和开发工具对于保持竞争力至关重要。本文为初学者提供了基础指导,鼓励进一步探索和学习。
|
6天前
|
前端开发 Linux iOS开发
【Flutter前端技术开发专栏】Flutter在桌面应用(Windows/macOS/Linux)的开发实践
【4月更文挑战第30天】Flutter扩展至桌面应用开发,允许开发者用同一代码库构建Windows、macOS和Linux应用,提高效率并保持平台一致性。创建桌面应用需指定目标平台,如`flutter create -t windows my_desktop_app`。开发中注意UI适配、性能优化、系统交互及测试部署。UI适配利用布局组件和`MediaQuery`,性能优化借助`PerformanceLogging`、`Isolate`和`compute`。
【Flutter前端技术开发专栏】Flutter在桌面应用(Windows/macOS/Linux)的开发实践
|
8天前
|
编解码 Linux Windows
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
本文档介绍了在Windows环境下如何为FFmpeg集成libopus和libvpx库。首先,详细阐述了安装libopus的步骤,包括下载源码、配置、编译和安装,并更新环境变量。接着,同样详细说明了libvpx的安装过程,注意需启用--enable-pic选项以避免编译错误。最后,介绍了重新配置并编译FFmpeg以启用这两个库,通过`ffmpeg -version`检查是否成功集成。整个过程参照了《FFmpeg开发实战:从零基础到短视频上线》一书的相关章节。
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
|
9天前
|
编解码 Linux Windows
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
在Windows环境下,为FFmpeg集成音频编解码库,包括libogg、libvorbis和opencore-amr,涉及下载源码、配置、编译和安装步骤。首先,安装libogg,通过配置、make和make install命令完成,并更新PKG_CONFIG_PATH。接着,安装libvorbis,同样配置、编译和安装,并修改pkgconfig文件。之后,安装opencore-amr。最后,重新配置并编译FFmpeg,启用ogg和amr支持,通过ffmpeg -version检查是否成功。整个过程需确保环境变量设置正确,并根据路径添加相应库。
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
|
27天前
|
Linux Windows
Windows Server 下文件同步
Windows Server 下文件同步
17 0
|
2月前
|
安全 数据安全/隐私保护 Windows
解锁安全之门,Windows Server 2019密码修改攻略大揭秘
解锁安全之门,Windows Server 2019密码修改攻略大揭秘
108 0
|
2月前
|
存储 安全 网络安全
铁壁如墙-WINDOWS SERVER 2019勒索病毒终极防御指南
铁壁如墙-WINDOWS SERVER 2019勒索病毒终极防御指南
|
2月前
|
网络协议 数据安全/隐私保护 Windows
Windows Server 各版本搭建域控制器实现通过域管理用户(03~19)
Windows Server 各版本搭建域控制器实现通过域管理用户(03~19)

热门文章

最新文章