30、驱动程序调用驱动程序
?????? 有兩種方法,一種是以文件句柄的形式,另外一種是通過設備指針調用其它驅動程序。
1、以文件句柄形式調用
1)應用程序 調用 驅動A 調用 驅動B
這種方法類似于在應用程序中調用驅動程序。
在應用程序中用CreateFile,ReadFile,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 //DriverB2 #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 //main2 #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說明 MSDN中ApcRoutine是保留參數,應當設為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 }
?
示例代碼 P3022、通過設備指針調用其他驅動程序
調用驅動程序
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后,還有構建IRP的I/O堆棧,每層I/O堆棧對應一個設備對象。最后通過IoCallDriver 調用相應的驅動。
總結一下,步驟為:
先得到設備的指針-》通過設備指針創建RIP-》構造I/O堆棧-》調用IoCallDriver 。
(1)IoBuildSynchronousFsdRequest
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 caller’s stack location in the given IRP,IoGetNextIrpStackLocation returns a pointer to the next-lower-level driver's I/O stack location in the given IRP。
(2)IoBuildAsynchronousFsdRequest
可以通過IRP的 UserEvent子域來通知IRP請求的結束。調用IoBuildAsynchronousFsdRequest 創建IRP后,如果希望同步,即希望得到IRP被結束的通知,則需要設備UserEvent。當執行IoCompleteRequest時,OS會檢查 IRP的UserEvent子域,如果非空,則它代表一個事件指針,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(3)IoAllocateIrp
CreateFile,ZwCreateFile 等,都直接或間接的調用了IoAllocateIrp 。所以對設備的操作都會轉化一個IRP,IRP會在驅動中被處理;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 }
?
示例代碼 P3143、其他方法獲得設備指針
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轉載于:https://www.cnblogs.com/mydomain/archive/2010/11/16/1878905.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的30、驱动程序调用驱动程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 冬季巧食生姜可提高免疫力
- 下一篇: C/C++ 位操作 总结