天天看點

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不能指定為上面兩者中任何其一。

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

代碼

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

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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 }

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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參數設定即可,不需要再整一個函數,就可達到目的。由于本例隻是說明問題,摘自别人的代碼,也就沒有改動。

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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來得到裝置名。

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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.

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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會裝置這個事件。

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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對象。

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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來使引用計數減一。

30、驅動程式調用驅動程式
30、驅動程式調用驅動程式

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