30、驱动程序调用驱动程序

       有两种方法,一种是以文件句柄的形式,另外一种是通过设备指针调用其它驱动程序。

1、以文件句柄形式调用

1)应用程序 调用 驱动A 调用 驱动B

这种方法类似于在应用程序中调用驱动程序。

在应用程序中用CreateFileReadFile,CloseHandle来操作相应文件,驱动中用ZwCreateFile,ZwReadFile,Irp结束操作。

要注意:

ZwCreateFile,如果是同步打开设备,则参数DesiredAccess,设为SYNCHRONIZE,参数CreateOptions设为FILE_SYNCHRONOUS_IO_ALERT或者是FILE_SYNCHRONOUS_IO_NONALERT。如果是异步打开设备,则参数DesiredAccess,不设为SYNCHRONIZE,且CreateOptions不能指定为上面两者中任何其一。

代码
 
   
1 // DriverA
2   typedef struct _DEVICE_EXTENSION {
3 PDEVICE_OBJECT pDevice;
4 UNICODE_STRING ustrDeviceName; // 设备名称
5   UNICODE_STRING ustrSymLinkName; // 符号链接名
6  
7 KDPC pollingDPC; // 存储DPC对象
8   KTIMER pollingTimer; // 存储计时器对象
9   PIRP currentPendingIRP; // 记录当前挂起的IRP
10   } DEVICE_EXTENSION, * PDEVICE_EXTENSION;
11
12   #pragma LOCKEDCODE
13 VOID OnTimerDpc( IN PKDPC pDpc,
14 IN PVOID pContext,
15 IN PVOID SysArg1,
16 IN PVOID SysArg2 )
17 {
18 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
19 PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
20
21 PIRP currentPendingIRP = pdx -> currentPendingIRP;
22
23 KdPrint(( " DriverA:complete the Driver A IRP_MJ_READ irp!\n " ));
24
25 // 设置完成状态为STATUS_CANCELLED
26   currentPendingIRP -> IoStatus.Status = STATUS_SUCCESS;
27 currentPendingIRP -> IoStatus.Information = 0 ; // bytes xfered
28   IoCompleteRequest( currentPendingIRP, IO_NO_INCREMENT );
29 }
30
31   /* ***********************************************************************
32 * 函数名称:CreateDevice
33 * 功能描述:初始化设备对象
34 * 参数列表:
35 pDriverObject:从I/O管理器中传进来的驱动对象
36 * 返回 值:返回初始化状态
37 ************************************************************************ */
38 #pragma INITCODE
39 NTSTATUS CreateDevice (
40 IN PDRIVER_OBJECT pDriverObject)
41 {
42 NTSTATUS status;
43 PDEVICE_OBJECT pDevObj;
44 PDEVICE_EXTENSION pDevExt;
45
46 // 创建设备名称
47 UNICODE_STRING devName;
48 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDeviceA " );
49
50 // 创建设备
51 status = IoCreateDevice( pDriverObject,
52 sizeof (DEVICE_EXTENSION),
53 & (UNICODE_STRING)devName,
54 FILE_DEVICE_UNKNOWN,
55 0 , TRUE,
56 & pDevObj );
57 if ( ! NT_SUCCESS(status))
58 return status;
59
60 pDevObj -> Flags |= DO_BUFFERED_IO;
61 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
62 pDevExt -> pDevice = pDevObj;
63 pDevExt -> ustrDeviceName = devName;
64
65 KeInitializeTimer( & pDevExt -> pollingTimer );
66
67 KeInitializeDpc( & pDevExt -> pollingDPC,
68 OnTimerDpc,
69 (PVOID) pDevObj );
70
71 // 创建符号链接
72 UNICODE_STRING symLinkName;
73 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDKA " );
74 pDevExt -> ustrSymLinkName = symLinkName;
75 status = IoCreateSymbolicLink( & symLinkName, & devName );
76 if ( ! NT_SUCCESS(status))
77 {
78 IoDeleteDevice( pDevObj );
79 return status;
80 }
81 return STATUS_SUCCESS;
82 }
83 /* ***********************************************************************
84 * 函数名称:HelloDDKRead
85 * 功能描述:对读IRP进行处理
86 * 参数列表:
87 pDevObj:功能设备对象
88 pIrp:从IO请求包
89 * 返回 值:返回状态
90 ************************************************************************ */
91 #pragma PAGEDCODE
92 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
93 IN PIRP pIrp)
94 {
95 KdPrint(( " DriverA:Enter A HelloDDKRead\n " ));
96
97 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
98 pDevObj -> DeviceExtension;
99
100 // 将IRP设置为挂起
101 IoMarkIrpPending(pIrp);
102
103 // 将挂起的IRP记录下来
104 pDevExt -> currentPendingIRP = pIrp;
105
106 // 定义3秒后将IRP_MJ_READ的IRP完成
107 ULONG ulMicroSecond = 3000000 ;
108
109 // 将32位整数转化成64位整数
110 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( - 10 * ulMicroSecond);
111
112 KeSetTimer(
113 & pDevExt -> pollingTimer,
114 timeout,
115 & pDevExt -> pollingDPC );
116
117 KdPrint(( " DriverA:Leave A HelloDDKRead\n " ));
118
119 // 返回pending状态
120 return STATUS_PENDING;
121 }
122

 

代码
 
   
1 // DriverB
2 #pragma PAGEDCODE
3 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
4 IN PIRP pIrp)
5 {
6 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
7 NTSTATUS ntStatus = STATUS_SUCCESS;
8
9 UNICODE_STRING DeviceName;
10 RtlInitUnicodeString( & DeviceName, L " \\Device\\MyDDKDeviceA " );
11
12 // 初始化objectAttributes
13 OBJECT_ATTRIBUTES objectAttributes;
14 InitializeObjectAttributes( & objectAttributes,
15 & DeviceName,
16 OBJ_CASE_INSENSITIVE,
17 NULL,
18 NULL );
19
20 HANDLE hDevice;
21 IO_STATUS_BLOCK status_block;
22 // 同步打开设备
23 // 设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备
24 ntStatus = ZwCreateFile( & hDevice,
25 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
26 & objectAttributes,
27 & status_block,
28 NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,
29 FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL, 0 );
30
31 if (NT_SUCCESS(ntStatus))
32 {
33 ZwReadFile(hDevice,NULL,NULL,NULL, & status_block,NULL, 0 ,NULL,NULL);
34 }
35
36 ZwClose(hDevice);
37
38 // 完成IRP
39 pIrp -> IoStatus.Status = ntStatus;
40 pIrp -> IoStatus.Information = 0 ; // bytes xfered
41 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
42 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
43 return ntStatus;
44 }
45
46 /* ***********************************************************************
47 * 函数名称:HelloDDKDispatchRoutine
48 * 功能描述:对读IRP进行处理
49 * 参数列表:
50 pDevObj:功能设备对象
51 pIrp:从IO请求包
52 * 返回 值:返回状态
53 ************************************************************************ */
54 #pragma PAGEDCODE
55 NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
56 IN PIRP pIrp)
57 {
58 KdPrint(( " DriverB:Enter B HelloDDKDispatchRoutine\n " ));
59 NTSTATUS ntStatus = STATUS_SUCCESS;
60 // 完成IRP
61 pIrp -> IoStatus.Status = ntStatus;
62 pIrp -> IoStatus.Information = 0 ; // bytes xfered
63 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
64 KdPrint(( " DriverB:Leave B HelloDDKDispatchRoutine\n " ));
65 return ntStatus;
66 }
67
68 #pragma PAGEDCODE
69 NTSTATUS HelloDDKCreate(IN PDEVICE_OBJECT pDevObj,
70 IN PIRP pIrp)
71 {
72 KdPrint(( " DriverB:Enter B HelloDDKCreate\n " ));
73 NTSTATUS ntStatus = STATUS_SUCCESS;
74 // 完成IRP
75 pIrp -> IoStatus.Status = ntStatus;
76 pIrp -> IoStatus.Information = 0 ; // bytes xfered
77 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
78
79 KdPrint(( " DriverB:Leave B HelloDDKCreate\n " ));
80
81 return ntStatus;
82 }
83
84 #pragma PAGEDCODE
85 NTSTATUS HelloDDKClose(IN PDEVICE_OBJECT pDevObj,
86 IN PIRP pIrp)
87 {
88 KdPrint(( " DriverB:Enter B HelloDDKClose\n " ));
89 NTSTATUS ntStatus = STATUS_SUCCESS;
90
91 PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
92
93 // 完成IRP
94 pIrp -> IoStatus.Status = ntStatus;
95 pIrp -> IoStatus.Information = 0 ; // bytes xfered
96 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
97
98 KdPrint(( " DriverB:Leave B HelloDDKClose\n " ));
99
100 return ntStatus;
101 }

 

代码
 
   
1 // main
2 #include < windows.h >
3 #include < stdio.h >
4
5 int main()
6 {
7
8 HANDLE hDevice =
9 CreateFile( " \\\\.\\HelloDDKB " ,
10 GENERIC_READ | GENERIC_WRITE,
11 0 , // share mode none
12 NULL, // no security
13 OPEN_EXISTING,
14 FILE_ATTRIBUTE_NORMAL,
15 NULL ); // no template
16
17 if (hDevice == INVALID_HANDLE_VALUE)
18 {
19 printf( " Failed to obtain file handle to device "
20 " with Win32 error code: %d\n " ,
21 GetLastError() );
22 return 1 ;
23 }
24
25 DWORD dRet;
26 ReadFile(hDevice,NULL, 0 , & dRet,NULL);
27
28 CloseHandle(hDevice);
29
30 return 0 ;
31 }

 

同步 示例代码 P296

代码
 
   
1 /* ***********************************************************************
2 * 函数名称:DriverEntry
3 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
4 * 参数列表:
5 pDriverObject:从I/O管理器中传进来的驱动对象
6 pRegistryPath:驱动程序在注册表的中的路径
7 * 返回 值:返回初始化驱动状态
8 ************************************************************************ */
9 #pragma INITCODE
10 extern " C " NTSTATUS DriverEntry (
11 IN PDRIVER_OBJECT pDriverObject,
12 IN PUNICODE_STRING pRegistryPath )
13 {
14 NTSTATUS ntStatus;
15 KdPrint(( " DriverB:Enter B DriverEntry\n " ));
16
17 // 注册其他驱动调用函数入口
18 pDriverObject -> DriverUnload = HelloDDKUnload;
19 pDriverObject -> MajorFunction[IRP_MJ_CREATE] = HelloDDKCreate;
20 pDriverObject -> MajorFunction[IRP_MJ_CLOSE] = HelloDDKClose;
21 pDriverObject -> MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
22 pDriverObject -> MajorFunction[IRP_MJ_READ] = HelloDDKRead;
23
24 // 创建驱动设备对象
25 ntStatus = CreateDevice(pDriverObject);
26
27 KdPrint(( " DriverB:Leave B DriverEntry\n " ));
28 return ntStatus;
29 }
30
31 /* ***********************************************************************
32 * 函数名称:CreateDevice
33 * 功能描述:初始化设备对象
34 * 参数列表:
35 pDriverObject:从I/O管理器中传进来的驱动对象
36 * 返回 值:返回初始化状态
37 ************************************************************************ */
38 #pragma INITCODE
39 NTSTATUS CreateDevice (
40 IN PDRIVER_OBJECT pDriverObject)
41 {
42 NTSTATUS ntStatus;
43 PDEVICE_OBJECT pDevObj;
44 PDEVICE_EXTENSION pDevExt;
45
46 // 创建设备名称
47 UNICODE_STRING devName;
48 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevicB " );
49
50 // 创建设备
51 ntStatus = IoCreateDevice( pDriverObject,
52 sizeof (DEVICE_EXTENSION),
53 & (UNICODE_STRING)devName,
54 FILE_DEVICE_UNKNOWN,
55 0 , TRUE,
56 & pDevObj );
57 if ( ! NT_SUCCESS(ntStatus))
58 return ntStatus;
59
60 pDevObj -> Flags |= DO_BUFFERED_IO;
61 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
62 pDevExt -> pDevice = pDevObj;
63 pDevExt -> ustrDeviceName = devName;
64
65 // 创建符号链接
66 UNICODE_STRING symLinkName;
67 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDKB " );
68 pDevExt -> ustrSymLinkName = symLinkName;
69 NTSTATUS status = IoCreateSymbolicLink( & symLinkName, & devName );
70 if ( ! NT_SUCCESS(status))
71 {
72 IoDeleteDevice( pDevObj );
73 return status;
74 }
75
76 return STATUS_SUCCESS;
77 }
78
79 /* ***********************************************************************
80 * 函数名称:HelloDDKUnload
81 * 功能描述:负责驱动程序的卸载操作
82 * 参数列表:
83 pDriverObject:驱动对象
84 * 返回 值:返回状态
85 ************************************************************************ */
86 #pragma PAGEDCODE
87 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
88 {
89 PDEVICE_OBJECT pNextObj;
90 KdPrint(( " DriverB:Enter B DriverUnload\n " ));
91 pNextObj = pDriverObject -> DeviceObject;
92
93 while (pNextObj != NULL)
94 {
95 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
96 pNextObj -> DeviceExtension;
97
98 // 删除符号链接
99 UNICODE_STRING pLinkName = pDevExt -> ustrSymLinkName;
100 IoDeleteSymbolicLink( & pLinkName);
101 pNextObj = pNextObj -> NextDevice;
102 IoDeleteDevice( pDevExt -> pDevice );
103 }
104 KdPrint(( " DriverB:Enter B DriverUnload\n " ));
105 }
106
107 VOID CompleteDriverA_Read(PVOID context,PIO_STATUS_BLOCK pStatus_block,ULONG)
108 {
109 KdPrint(( " DriverB:The Driver A Read completed now!\n " ));
110 KeSetEvent((PKEVENT)context,IO_NO_INCREMENT,FALSE);
111 }
112
113 #pragma PAGEDCODE
114 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
115 IN PIRP pIrp)
116 {
117 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
118 NTSTATUS ntStatus = STATUS_SUCCESS;
119
120 UNICODE_STRING DeviceName;
121 RtlInitUnicodeString( & DeviceName, L " \\Device\\MyDDKDeviceA " );
122
123 // 初始化objectAttributes
124 OBJECT_ATTRIBUTES objectAttributes;
125 InitializeObjectAttributes( & objectAttributes,
126 & DeviceName,
127 OBJ_CASE_INSENSITIVE,
128 NULL,
129 NULL );
130
131 HANDLE hDevice;
132 IO_STATUS_BLOCK status_block;
133 // 异步打开设备
134 // 没有设定了FILE_SYNCHRONOUS_IO_NONALERT和FILE_SYNCHRONOUS_IO_ALERT为异步打开设备
135 ntStatus = ZwCreateFile( & hDevice,
136 FILE_READ_ATTRIBUTES, // 没有设SYNCHRONIZE
137 & objectAttributes,
138 & status_block,
139 NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,
140 FILE_OPEN_IF, 0 ,NULL, 0 );
141
142 KEVENT event ;
143 // 初始化事件,用于异步读
144 KeInitializeEvent( & event ,SynchronizationEvent,FALSE);
145
146 LARGE_INTEGER offset = RtlConvertLongToLargeInteger( 0 );
147 if (NT_SUCCESS(ntStatus))
148 {
149 ntStatus = ZwReadFile(hDevice,NULL,CompleteDriverA_Read, & event , & status_block,NULL, 0 , & offset,NULL);
150 }
151
152 if (ntStatus == STATUS_PENDING)
153 {
154 KdPrint(( " DriverB:ZwReadFile return STATUS_PENDING!\n " ));
155 KdPrint(( " DriverB:Waiting... " ));
156 KeWaitForSingleObject( & event ,Executive,KernelMode,FALSE,NULL);
157 }
158 ZwClose(hDevice);
159
160 ntStatus = STATUS_SUCCESS;
161 // 完成IRP
162 pIrp -> IoStatus.Status = ntStatus;
163 pIrp -> IoStatus.Information = 0 ; // bytes xfered
164 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
165 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
166 return ntStatus;
167 }
168
169 /* ***********************************************************************
170 * 函数名称:HelloDDKDispatchRoutine
171 * 功能描述:对读IRP进行处理
172 * 参数列表:
173 pDevObj:功能设备对象
174 pIrp:从IO请求包
175 * 返回 值:返回状态
176 ************************************************************************ */
177 #pragma PAGEDCODE
178 NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
179 IN PIRP pIrp)
180 {
181 KdPrint(( " DriverB:Enter B HelloDDKDispatchRoutine\n " ));
182 NTSTATUS ntStatus = STATUS_SUCCESS;
183 // 完成IRP
184 pIrp -> IoStatus.Status = ntStatus;
185 pIrp -> IoStatus.Information = 0 ; // bytes xfered
186 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
187 KdPrint(( " DriverB:Leave B HelloDDKDispatchRoutine\n " ));
188 return ntStatus;
189 }
190
191 #pragma PAGEDCODE
192 NTSTATUS HelloDDKCreate(IN PDEVICE_OBJECT pDevObj,
193 IN PIRP pIrp)
194 {
195 KdPrint(( " DriverB:Enter B HelloDDKCreate\n " ));
196 NTSTATUS ntStatus = STATUS_SUCCESS;
197 // 完成IRP
198 pIrp -> IoStatus.Status = ntStatus;
199 pIrp -> IoStatus.Information = 0 ; // bytes xfered
200 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
201
202 KdPrint(( " DriverB:Leave B HelloDDKCreate\n " ));
203
204 return ntStatus;
205 }
206
207 #pragma PAGEDCODE
208 NTSTATUS HelloDDKClose(IN PDEVICE_OBJECT pDevObj,
209 IN PIRP pIrp)
210 {
211 KdPrint(( " DriverB:Enter B HelloDDKClose\n " ));
212 NTSTATUS ntStatus = STATUS_SUCCESS;
213
214 PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
215
216 // 完成IRP
217 pIrp -> IoStatus.Status = ntStatus;
218 pIrp -> IoStatus.Information = 0 ; // bytes xfered
219 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
220
221 KdPrint(( " DriverB:Leave B HelloDDKClose\n " ));
222
223 return ntStatus;
224 }

 

异步方式一 示例代码 P298

说明 MSDNApcRoutine是保留参数,应当设为NULL。本例中,直接可将Event参数设置即可,不需要再整一个函数,就可达到目的。由于本例只是说明问题,摘自别人的代码,也就没有改动。

代码
 
   
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
6 NTSTATUS ntStatus = STATUS_SUCCESS;
7
8 UNICODE_STRING DeviceName;
9 RtlInitUnicodeString( & DeviceName, L " \\Device\\MyDDKDeviceA " );
10
11 // 初始化objectAttributes
12 OBJECT_ATTRIBUTES objectAttributes;
13 InitializeObjectAttributes( & objectAttributes,
14 & DeviceName,
15 OBJ_CASE_INSENSITIVE,
16 NULL,
17 NULL );
18
19 HANDLE hDevice;
20 IO_STATUS_BLOCK status_block;
21
22 // 异步打开设备
23 ntStatus = ZwCreateFile( & hDevice,
24 FILE_READ_ATTRIBUTES, // 没有设SYNCHRONIZE
25 & objectAttributes,
26 & status_block,
27 NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,
28 FILE_OPEN_IF, 0 ,NULL, 0 );
29
30 LARGE_INTEGER offset = RtlConvertLongToLargeInteger( 0 );
31 if (NT_SUCCESS(ntStatus))
32 {
33 ntStatus = ZwReadFile(hDevice,NULL,NULL,NULL, & status_block,NULL, 0 , & offset,NULL);
34 }
35
36 if (ntStatus == STATUS_PENDING)
37 {
38 KdPrint(( " DriverB:ZwReadFile return STATUS_PENDING!\n " ));
39
40 PFILE_OBJECT FileObject;
41 ntStatus = ObReferenceObjectByHandle(hDevice, EVENT_MODIFY_STATE, * ExEventObjectType,
42 KernelMode, (PVOID * ) & FileObject, NULL);
43 if (NT_SUCCESS(ntStatus))
44 {
45 KdPrint(( " DriverB:Waiting... " ));
46 KeWaitForSingleObject( & FileObject -> Event,Executive,KernelMode,FALSE,NULL);
47 KdPrint(( " DriverB:Driver A Read IRP completed now!\n " ));
48 ObDereferenceObject(FileObject);
49 }
50 }
51 ZwClose(hDevice);
52
53 ntStatus = STATUS_SUCCESS;
54 // 完成IRP
55 pIrp -> IoStatus.Status = ntStatus;
56 pIrp -> IoStatus.Information = 0 ; // bytes xfered
57 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
58 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
59 return ntStatus;
60 }

 

异步方式二 示例代码 P298

说明:方式一通过将一个事件句柄传递给ZwReadFile,这个事件用来通知读取操作何时完成。方式二原理是:通过文件对象判断读取是否完毕;每打开一个设备,都会伴随存在一个关联的文件对象,利用ObReferenceObjectByHandle获取文件对象指针;当IRP_MJ_READ请求被结束后,文件对象的子域Event会被设备,因此可以用文件对象的子域进行判断。

2)通过符号链接打开设备

       如何由符号链接得到设备名?

通过ZwOpenSymbolicLinkObject来得到符号链接的句柄,再通过ZwQuerySymbolicLinkObject来得到设备名。

代码
 
   
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
6 NTSTATUS ntStatus = STATUS_SUCCESS;
7
8 UNICODE_STRING DeviceSymbolicLinkName;
9 RtlInitUnicodeString( & DeviceSymbolicLinkName, L " \\??\\HelloDDKA " );
10
11 // 初始化objectAttributes
12 OBJECT_ATTRIBUTES objectAttributes;
13 InitializeObjectAttributes( & objectAttributes,
14 & DeviceSymbolicLinkName,
15 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
16 NULL,
17 NULL );
18
19 HANDLE hSymbolic;
20 // 设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备
21 ntStatus = ZwOpenSymbolicLinkObject( & hSymbolic,FILE_ALL_ACCESS, & objectAttributes);
22 #define UNICODE_SIZE 50
23 UNICODE_STRING LinkTarget;
24 LinkTarget.Buffer = (PWSTR)ExAllocatePool(PagedPool,UNICODE_SIZE);
25 LinkTarget.Length = 0 ;
26 LinkTarget.MaximumLength = UNICODE_SIZE;
27
28 ULONG unicode_length;
29 ntStatus = ZwQuerySymbolicLinkObject(hSymbolic, & LinkTarget, & unicode_length);
30
31 KdPrint(( " DriverB:The device name is %wZ\n " , & LinkTarget));
32
33 InitializeObjectAttributes( & objectAttributes,
34 & LinkTarget,
35 OBJ_CASE_INSENSITIVE,
36 NULL,
37 NULL );
38
39 HANDLE hDevice;
40 IO_STATUS_BLOCK status_block;
41 // 设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备
42 ntStatus = ZwCreateFile( & hDevice,
43 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
44 & objectAttributes,
45 & status_block,
46 NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,
47 FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL, 0 );
48
49 if (NT_SUCCESS(ntStatus))
50 {
51 ZwReadFile(hDevice,NULL,NULL,NULL, & status_block,NULL, 0 ,NULL,NULL);
52 }
53
54 ZwClose(hDevice);
55 ZwClose(hSymbolic);
56 ExFreePool(LinkTarget.Buffer);
57
58 ntStatus = STATUS_SUCCESS;
59 // 完成IRP
60 pIrp -> IoStatus.Status = ntStatus;
61 pIrp -> IoStatus.Information = 0 ; // bytes xfered
62 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
63 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
64 return ntStatus;
65 }

 

示例代码 P302

2、通过设备指针调用其他驱动程序

调用驱动程序

ZwReadFile内核函数内部会创建IRP_MJ_READ类型的IRP,然后把这个IRP传递到相应的派遣函数中。这一小节中,我们是通过自己“手动”构造各个IRP,然后将IRP传递到相应的驱动程序的派遣函数中。

2、通过IoGetDeviceObjectPointer 来获得设备指针。

1)每个内核中的句柄都会和一个内核对象的指针联系起来。如ZwCreateFile内核函数可以通过设备名打开设备句柄,这个句柄和一个文件对象的指针关联。IoGetDeviceObjectPointer 可以通过设备名获得文件对象指针。

Windows内核会为每一个对象指针保存一个“引用计数”,对象被创建时引用计数为1。引用这个对象,引用计数加1。只有引用对象为0时,对象才能被真正删除。ObDereferenceObject 来使引用计数减一。

第一次调用IoGetDeviceObjectPointer 时,会根据设备名打开设备,计数为1,相当于对对象发送IRP_MJ_CREATE。使用完后调用ObDereferenceObject最终关闭设备时,相当于发送IRP_MJ_CLOSE

2)共有如下几种方法,IoBuildSynchronousFsdRequest IoBuildAsynchronousFsdRequest IoBuildDeviceIoControlRequest IoAllocateIrp 来创建IRP。前3种都是通过IoAllocateIrp 实现的。创建完IRP后,还有构建IRPI/O堆栈,每层I/O堆栈对应一个设备对象。最后通过IoCallDriver 调用相应的驱动。

总结一下,步骤为:

先得到设备的指针-》通过设备指针创建RIP-》构造I/O堆栈-》调用IoCallDriver

1IoBuildSynchronousFsdRequest

IoBuildSynchronousFsdRequest IoBuildAsynchronousFsdRequest 的区别就是是否提供同步对象。事件会和IRP请求相关联,当IRP请求结束时该事件被触发。

Intermediate or highest-level drivers can call IoBuildSynchronousFsdRequest to set up IRPs for requests sent to lower-level drivers, only if the caller is running in a nonarbitrary thread context and at IRQL = PASSIVE_LEVEL.

IoBuildSynchronousFsdRequest allocates and sets up an IRP that can be sent to a device driver to perform a synchronous read, write, flush, or shutdown operation. The IRP contains only enough information to get the operation started.

IoBuildSynchronousFsdRequest returns a pointer to the IRP, or NULL if an IRP cannot be allocated.

代码
 
   
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
6 NTSTATUS ntStatus = STATUS_SUCCESS;
7
8 UNICODE_STRING DeviceName;
9 RtlInitUnicodeString( & DeviceName, L " \\Device\\MyDDKDeviceA " );
10
11 PDEVICE_OBJECT DeviceObject = NULL;
12 PFILE_OBJECT FileObject = NULL;
13 // 得到设备对象句柄,计数器加1
14 // 如果是第一次调用IoGetDeviceObjectPointer,会打开设备,相当于调用ZwCreateFile
15 ntStatus = IoGetDeviceObjectPointer( & DeviceName,FILE_ALL_ACCESS, & FileObject, & DeviceObject);
16
17 KdPrint(( " DriverB:FileObject:%x\n " ,FileObject));
18 KdPrint(( " DriverB:DeviceObject:%x\n " ,DeviceObject));
19
20 if ( ! NT_SUCCESS(ntStatus))
21 {
22 KdPrint(( " DriverB:IoGetDeviceObjectPointer() 0x%x\n " , ntStatus ));
23
24 ntStatus = STATUS_UNSUCCESSFUL;
25 // 完成IRP
26 pIrp -> IoStatus.Status = ntStatus;
27 pIrp -> IoStatus.Information = 0 ; // bytes xfered
28 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
29 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
30
31 return ntStatus;
32 }
33
34 KEVENT event ;
35 KeInitializeEvent( & event ,NotificationEvent,FALSE);
36 IO_STATUS_BLOCK status_block;
37 LARGE_INTEGER offsert = RtlConvertLongToLargeInteger( 0 );
38
39 // 创建同步IRP
40 PIRP pNewIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
41 DeviceObject,
42 NULL, 0 ,
43 & offsert, & event , & status_block);
44 KdPrint(( " DriverB:pNewIrp:%x\n " ,pNewIrp));
45
46 PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
47 stack -> FileObject = FileObject;
48
49 // 调用DriverA,会一直调用到DriverA的派遣函数
50 NTSTATUS status = IoCallDriver(DeviceObject,pNewIrp);
51
52 if (status == STATUS_PENDING) {
53
54 // 如果DriverA的派遣函数没有完成IRP,则等待IRP完成
55 status = KeWaitForSingleObject(
56 & event ,
57 Executive,
58 KernelMode,
59 FALSE, // Not alertable
60 NULL);
61 status = status_block.Status;
62 }
63
64 // 将引用计数减1,如果此时计数器减为0,
65 // 则将关闭设备,相当于调用ZwClose
66 ObDereferenceObject( FileObject );
67
68
69 ntStatus = STATUS_SUCCESS;
70 // 完成IRP
71 pIrp -> IoStatus.Status = ntStatus;
72 pIrp -> IoStatus.Information = 0 ; // bytes xfered
73 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
74 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
75 return ntStatus;
76 }

 

示例代码 P306

另外,The IoGetCurrentIrpStackLocation routine returns a pointer to the callers stack location in the given IRPIoGetNextIrpStackLocation returns a pointer to the next-lower-level driver's I/O stack location in the given IRP

2IoBuildAsynchronousFsdRequest

可以通过IRP UserEvent子域来通知IRP请求的结束。调用IoBuildAsynchronousFsdRequest 创建IRP后,如果希望同步,即希望得到IRP被结束的通知,则需要设备UserEvent。当执行IoCompleteRequest时,OS会检查 IRPUserEvent子域,如果非空,则它代表一个事件指针,IoCompleteRequest会设备这个事件。

代码
 
   
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
6 NTSTATUS ntStatus = STATUS_SUCCESS;
7
8 UNICODE_STRING DeviceName;
9 RtlInitUnicodeString( & DeviceName, L " \\Device\\MyDDKDeviceA " );
10
11 PDEVICE_OBJECT DeviceObject = NULL;
12 PFILE_OBJECT FileObject = NULL;
13 // 得到设备对象指针
14 ntStatus = IoGetDeviceObjectPointer( & DeviceName,FILE_ALL_ACCESS, & FileObject, & DeviceObject);
15
16 KdPrint(( " DriverB:FileObject:%x\n " ,FileObject));
17 KdPrint(( " DriverB:DeviceObject:%x\n " ,DeviceObject));
18
19 if ( ! NT_SUCCESS(ntStatus))
20 {
21 KdPrint(( " DriverB:IoGetDeviceObjectPointer() 0x%x\n " , ntStatus ));
22
23 ntStatus = STATUS_UNSUCCESSFUL;
24 // 完成IRP
25 pIrp -> IoStatus.Status = ntStatus;
26 pIrp -> IoStatus.Information = 0 ; // bytes xfered
27 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
28 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
29
30 return ntStatus;
31 }
32
33 KEVENT event ;
34 KeInitializeEvent( & event ,NotificationEvent,FALSE);
35 IO_STATUS_BLOCK status_block;
36 LARGE_INTEGER offsert = RtlConvertLongToLargeInteger( 0 );
37
38 // 创建异步IRP
39 PIRP pNewIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
40 DeviceObject,
41 NULL, 0 ,
42 & offsert, & status_block);
43 KdPrint(( " pNewIrp->UserEvent :%x\n " ,pNewIrp -> UserEvent));
44 // 设置pNewIrp->UserEvent,这样在IRP完成后可以通知该事件
45 pNewIrp -> UserEvent = & event ;
46
47 KdPrint(( " DriverB:pNewIrp:%x\n " ,pNewIrp));
48
49 PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
50 stack -> FileObject = FileObject;
51
52 NTSTATUS status = IoCallDriver(DeviceObject,pNewIrp);
53
54 if (status == STATUS_PENDING) {
55 status = KeWaitForSingleObject(
56 & event ,
57 Executive,
58 KernelMode,
59 FALSE, // Not alertable
60 NULL);
61 status = status_block.Status;
62 }
63
64 ZwClose(FileObject);
65
66 // 关闭设备句柄
67 ObDereferenceObject( FileObject );
68
69 ntStatus = STATUS_SUCCESS;
70 // 完成IRP
71 pIrp -> IoStatus.Status = ntStatus;
72 pIrp -> IoStatus.Information = 0 ; // bytes xfered
73 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
74 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
75 return ntStatus;
76 }

 

示例代码 P309

3IoAllocateIrp

CreateFile,ZwCreateFile 等,都直接或间接的调用了IoAllocateIrp 。所以对设备的操作都会转化一个IRPIRP会在驱动中被处理;IRP请求被结束,代表操作结束,IRP的完成状态就是操作的完成状态。所有的IRP最终都是由IoAllocateIrp 内核函数创建的。

整个Windows是个异步的框架,同步只是异步的一个特例;就像静止只是运行的一个特例一样。

IoAllocateIrp 创建IRP后,许多参数,如缓冲区等,用户自己填写。最终需要用IoFreeIrp删除IRP对象。

代码
 
   
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
6 NTSTATUS ntStatus = STATUS_SUCCESS;
7
8 UNICODE_STRING DeviceName;
9 RtlInitUnicodeString( & DeviceName, L " \\Device\\MyDDKDeviceA " );
10
11 PDEVICE_OBJECT DeviceObject = NULL;
12 PFILE_OBJECT FileObject = NULL;
13 // 得到设备对象指针
14 ntStatus = IoGetDeviceObjectPointer( & DeviceName,FILE_ALL_ACCESS, & FileObject, & DeviceObject);
15
16 KdPrint(( " DriverB:FileObject:%x\n " ,FileObject));
17 KdPrint(( " DriverB:DeviceObject:%x\n " ,DeviceObject));
18
19 if ( ! NT_SUCCESS(ntStatus))
20 {
21 KdPrint(( " DriverB:IoGetDeviceObjectPointer() 0x%x\n " , ntStatus ));
22 ntStatus = STATUS_UNSUCCESSFUL;
23 // 完成IRP
24 pIrp -> IoStatus.Status = ntStatus;
25 pIrp -> IoStatus.Information = 0 ; // bytes xfered
26 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
27 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
28
29 return ntStatus;
30 }
31
32 KEVENT event ;
33 KeInitializeEvent( & event ,NotificationEvent,FALSE);
34
35 PIRP pNewIrp = IoAllocateIrp(DeviceObject -> StackSize,FALSE);
36 KdPrint(( " pNewIrp->UserEvent :%x\n " ,pNewIrp -> UserEvent));
37 pNewIrp -> UserEvent = & event ;
38
39 IO_STATUS_BLOCK status_block;
40 pNewIrp -> UserIosb = & status_block;
41 pNewIrp -> Tail.Overlay.Thread = PsGetCurrentThread();
42
43 // 因为DriverA是BUFFER IO设备
44 pNewIrp -> AssociatedIrp.SystemBuffer = NULL;
45
46 KdPrint(( " DriverB:pNewIrp:%x\n " ,pNewIrp));
47
48 PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
49 stack -> MajorFunction = IRP_MJ_READ;
50 stack -> MinorFunction = IRP_MN_NORMAL; // 0
51 stack -> FileObject = FileObject;
52
53 // 调用DriverA驱动
54 NTSTATUS status = IoCallDriver(DeviceObject,pNewIrp);
55
56 if (status == STATUS_PENDING) {
57 status = KeWaitForSingleObject(
58 & event ,
59 Executive,
60 KernelMode,
61 FALSE, // Not alertable
62 NULL);
63 KdPrint(( " STATUS_PENDING\n " ));
64 }
65
66 ObDereferenceObject( FileObject );
67 IoFreeIrp(pNewIrp);
68
69 ntStatus = STATUS_SUCCESS;
70 // 完成IRP
71 pIrp -> IoStatus.Status = ntStatus;
72 pIrp -> IoStatus.Information = 0 ; // bytes xfered
73 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
74 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
75 return ntStatus;
76 }

 

示例代码 P314

3、其他方法获得设备指针

ObReferenceObjectByName 是一个未公开的函数。ObReferenceObjectByName通过名字得到指针,而操作类型可以是设备对象,内核对象,互斥事件等;而 IoGetDeviceObjectPointer 只能得到设备对象指针。同样,ObReferenceObjectByName也维护了一个设备对象的引用计数,使用完后,也需要调用 ObDereferenceObject来使引用计数减一。

代码
 
   
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 KdPrint(( " DriverB:Enter B HelloDDKRead\n " ));
6 NTSTATUS ntStatus = STATUS_SUCCESS;
7
8 UNICODE_STRING DeviceName;
9 RtlInitUnicodeString( & DeviceName, L " \\??\\HelloDDKA " );
10
11 PDEVICE_OBJECT DeviceObject = NULL;
12 PFILE_OBJECT FileObject = NULL;
13 ntStatus = MyIoGetDeviceObjectPointer( & DeviceName,FILE_ALL_ACCESS, & FileObject, & DeviceObject);
14 // ntStatus = ObReferenceObjectByName(&DeviceName,OBJ_CASE_INSENSITIVE,NULL,FILE_ALL_ACCESS,IoDeviceObjectType,KernelMode,NULL,(PVOID*)&DeviceObject);
15
16 KdPrint(( " ntStatus %x\n " ,ntStatus));
17 KdPrint(( " DeviceObject %x\n " ,DeviceObject));
18 ObDereferenceObject( FileObject );
19 ntStatus = STATUS_SUCCESS;
20 // 完成IRP
21 pIrp -> IoStatus.Status = ntStatus;
22 pIrp -> IoStatus.Information = 0 ; // bytes xfered
23 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
24 KdPrint(( " DriverB:Leave B HelloDDKRead\n " ));
25 return ntStatus;
26 }

 

示例代码 P316
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
驱动程序调用应用层API是指系统的驱动程序通过调用应用层API来完成特定功能。驱动程序是一种软件,用于控制硬件设备的操作和管理。而应用层API(Application Programming Interface,应用程序接口)则是一组预先定义好的函数和方法,用于提供给开发者使用的接口。 驱动程序通过调用应用层API来实现与应用程序的交互。通过调用API中的函数或方法,驱动程序可以向上层应用程序提供各种操作硬件设备的功能。比如,一个打印机驱动程序可以通过调用应用层API中的打印函数,将应用程序中的打印任务发送给打印机设备进行打印。驱动程序可以通过调用API中的函数来控制设备的开关、设置设备参数、读取传感器数据等操作。 驱动程序调用应用层API的好处是实现了驱动程序与应用程序的分离。应用层API封装了底层硬件设备的具体操作细节,使得驱动程序能够以一种统一的接口与应用程序进行交互。这样,应用程序开发者无需了解底层硬件设备的具体细节,只需调用API提供函数即可完成相应的操作。同时,驱动程序的开发者也无需考虑具体的应用场景和应用程序的实现,只需提供对应的API接口即可。 总之,驱动程序通过调用应用层API实现了与应用程序的交互,提供了与硬件设备进行通信和控制的能力。这种方式能够简化应用程序和驱动程序的开发,提高了系统的可维护性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值