天天看点

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