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


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

    1、以文件句柄形式调用

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

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

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

    要注意:

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

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

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

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

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

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

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

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

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

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

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

    调用驱动程序

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

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

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

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

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

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

    总结一下,步骤为:

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

    1IoBuildSynchronousFsdRequest

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

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

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

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

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

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

    2IoBuildAsynchronousFsdRequest

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

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

    3IoAllocateIrp

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

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

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

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

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

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

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

  • 相关阅读:
    Element ui表单验证结束后再次打开清空验证信息
    oracle 新建用户 给用户设定权限
    oracle时间问题
    ORACLE 创建作业JOB例子
    ORACLE SQL PLUSE 创建作业 执行作业
    VS发布,签名出错 试图加载该页时出错,路径的形式不合法。
    Oracle 系统权限
    PL/SQL Developer 8.0 创建 Oracle Jobs 的疑惑
    信息系统系项目管理考试技巧
    水晶报表分组统计中如何让字段值居中显示
  • 原文地址:https://www.cnblogs.com/mydomain/p/1878905.html
Copyright © 2020-2023  润新知