有兩種方法,一種是以檔案句柄的形式,另外一種是通過裝置指針調用其它驅動程式。
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 //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" );
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);
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 }
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;
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"));
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 }
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"));
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;
31 /************************************************************************
42 NTSTATUS ntStatus;
48 RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevicB");
51 ntStatus = IoCreateDevice( pDriverObject,
57 if (!NT_SUCCESS(ntStatus))
58 return ntStatus;
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 }
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;
93 while (pNextObj != NULL)
94 {
95 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
96 pNextObj->DeviceExtension;
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" );
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;
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);
30 LARGE_INTEGER offset = RtlConvertLongToLargeInteger(0);
33 ntStatus = ZwReadFile(hDevice,NULL,NULL,NULL,&status_block,NULL,0,&offset,NULL);
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來得到裝置名。

8 UNICODE_STRING DeviceSymbolicLinkName;
9 RtlInitUnicodeString( &DeviceSymbolicLinkName, L"\\??\\HelloDDKA" );
14 &DeviceSymbolicLinkName,
15 OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
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;
28 ULONG unicode_length;
29 ntStatus = ZwQuerySymbolicLinkObject(hSymbolic,&LinkTarget,&unicode_length);
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後,還有建構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.

11 PDEVICE_OBJECT DeviceObject = NULL;
12 PFILE_OBJECT FileObject = NULL;
13 //得到裝置對象句柄,計數器加1
14 //如果是第一次調用IoGetDeviceObjectPointer,會打開裝置,相當于調用ZwCreateFile
15 ntStatus = IoGetDeviceObjectPointer(&DeviceName,FILE_ALL_ACCESS,&FileObject,&DeviceObject);
17 KdPrint(("DriverB:FileObject:%x\n",FileObject));
18 KdPrint(("DriverB:DeviceObject:%x\n",DeviceObject));
20 if (!NT_SUCCESS(ntStatus))
21 {
22 KdPrint(("DriverB:IoGetDeviceObjectPointer() 0x%x\n", ntStatus ));
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"));
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);
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));
46 PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
47 stack->FileObject = FileObject;
49 //調用DriverA,會一直調用到DriverA的派遣函數
50 NTSTATUS status = IoCallDriver(DeviceObject,pNewIrp);
51
52 if (status == STATUS_PENDING) {
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 );
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會裝置這個事件。

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));
19 if (!NT_SUCCESS(ntStatus))
20 {
21 KdPrint(("DriverB:IoGetDeviceObjectPointer() 0x%x\n", ntStatus ));
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"));
30 return ntStatus;
31 }
33 KEVENT event;
34 KeInitializeEvent(&event,NotificationEvent,FALSE);
35 IO_STATUS_BLOCK status_block;
36 LARGE_INTEGER offsert = RtlConvertLongToLargeInteger(0);
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));
49 PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
50 stack->FileObject = FileObject;
52 NTSTATUS status = IoCallDriver(DeviceObject,pNewIrp);
54 if (status == STATUS_PENDING) {
64 ZwClose(FileObject);
65
66 //關閉裝置句柄
67 ObDereferenceObject( FileObject );
示例代碼 P309
(3)IoAllocateIrp
CreateFile,ZwCreateFile 等,都直接或間接的調用了IoAllocateIrp 。是以對裝置的操作都會轉化一個IRP,IRP會在驅動中被處理;IRP請求被結束,代表操作結束,IRP的完成狀态就是操作的完成狀态。所有的IRP最終都是由IoAllocateIrp 核心函數建立的。
整個Windows是個異步的架構,同步隻是異步的一個特例;就像靜止隻是運作的一個特例一樣。
IoAllocateIrp 建立IRP後,許多參數,如緩沖區等,使用者自己填寫。最終需要用IoFreeIrp删除IRP對象。

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;
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;
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;
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 }
67 IoFreeIrp(pNewIrp);
示例代碼 P314
3、其他方法獲得裝置指針
ObReferenceObjectByName 是一個未公開的函數。ObReferenceObjectByName通過名字得到指針,而操作類型可以是裝置對象,核心對象,互斥事件等;而 IoGetDeviceObjectPointer 隻能得到裝置對象指針。同樣,ObReferenceObjectByName也維護了一個裝置對象的引用計數,使用完後,也需要調用 ObDereferenceObject來使引用計數減一。

9 RtlInitUnicodeString( &DeviceName, L"\\??\\HelloDDKA" );
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);
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