除了在Win32下面可以调用ReadFile, WriteFile之类的函数打开设备对象, 在内核中也是可以的, 而且方法比用户态这边更多. 首先这种方法就是Win32上面相同的方式了, 直接打开设备. 内核也有一套函数类似Win32下面的CreateFile, WriteFile, ReadFile.
下面代码那个写入设备基本就没有什么好说的. 和Win32上面的套路差不多, Win32上面其实也有一个WriteFileEx. 就是可以设置回调函数那个. 内核里面的函数就合二为一了, 都是ZwWriteFile,看心情, 如果喜欢用回调函数那就用回调函数. 如果不喜欢用回调函数那么就NULL, 就OK了..
在打开设备的时候不但可以使用设备名称来打开, 也可以利用符号链接名称来打开, 总之Win32下面有的, 内核里面都有了, 而且更暴力!很好很强大!
主要说说这个读取设备这块, 读取设备的时候, 也用了事件对象, 不过这里的事件对象用的是设备句柄的文件句柄, 我倒. 有点绕啊, 其实是这样的, 每打开一个文件句柄, 都会伴随着存在一个关联的文件对象(File_Object). 利用内核函数ObReferenceObjectByHandle可以获取设备相关的文件句柄的指针.当IRP_MJ_READ请求被结束的时候, 文件对象的Event会被设置, 因此可以利用这个Event对象来做同步.下面的代码正是这样做的. 当然, 这个要记得在后面调用ObDereferenceObject, 来解引用.
我在调用ObReferenceObjectByHandle的时候老是返回失败, 后来google一下, 发现第3个参数设置为NULL就没有问题了, 所以我也就这样做了. 不知为何. 这里先留下这个问题. 回头再倒腾!
现在这套打开设备, 读写的函数. 其实和Win32下面是差不多的, 所以不说了. 直接上代码:首先是测试驱动:
/* Windows 内核下驱动程序调用驱动程序 测试驱动 编译方法参见makefile. TAB = 8 */ #include <ntddk.h> #define DEVICE_NAME L"\Device\DevTestDriver" #define SYSLINK_NAME L"\??\SysLinkTestDriver" typedef struct tagDeviceExt { KDPC StDpc; PIRP pIrp; KTIMER StTimer; PVOID pBuf; PDEVICE_OBJECT pDeviceObj; UNICODE_STRING USzDeviceName; UNICODE_STRING USzSysLinkName; } DEVICE_EXT, *PDEVICE_EXT; //=========================================================================== //驱动卸载例程 //=========================================================================== #pragma code_seg( "PAGE" ) VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) { PDEVICE_EXT pDeviceExt = NULL; PDEVICE_OBJECT pNextDeviceObj = NULL; pNextDeviceObj = pDriverObj->DeviceObject; while ( pNextDeviceObj != NULL ) { pDeviceExt = pNextDeviceObj->DeviceExtension; IoDeleteDevice( pDeviceExt->pDeviceObj ); IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName ); if ( pDeviceExt->pBuf != NULL ) { ExFreePool( pDeviceExt->pBuf ); } KdPrint( ( "删除设备%wZ成功! ", &pDeviceExt->USzDeviceName ) ); pNextDeviceObj = pNextDeviceObj->NextDevice; } } //=========================================================================== //所有不关系的Irp处理 //=========================================================================== NTSTATUS DispathRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } //=========================================================================== //超时Dpc例程 //=========================================================================== #pragma code_seg() VOID OnTimerDpc( PKDPC pDpc, PVOID pContext, PVOID SysArg1, PVOID SysArg2 ) { PIRP pIrp = NULL; PCHAR pBuf = NULL; ULONG ulBufLen, i; NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL; PDEVICE_OBJECT pDeviceObj = NULL; PIO_STACK_LOCATION Stack = NULL; PAGED_CODE_LOCKED(); //--------------------------------------------------------------------------- pDeviceObj = ( PDEVICE_OBJECT )pContext; pDeviceExt = pDeviceObj->DeviceExtension; pIrp = pDeviceExt->pIrp; ASSERT ( pIrp != NULL ); Stack = IoGetCurrentIrpStackLocation( pIrp ); Status = STATUS_SUCCESS; do { pBuf = pIrp->AssociatedIrp.SystemBuffer; if ( pBuf == NULL ) { ulBufLen = 0; Status = STATUS_UNSUCCESSFUL; break; } //--------------------------------------------------------------------------- if ( Stack->MajorFunction == IRP_MJ_WRITE ) { ulBufLen = Stack->Parameters.Write.Length; for( i = 0; i < ulBufLen; i++ ) { KdPrint( ( "%c ", *( pBuf + i ) ) ); } KdPrint( ( " " ) ); pDeviceExt->pBuf = ExAllocatePool( NonPagedPool, ulBufLen ); ASSERT( pDeviceExt->pBuf ); RtlCopyMemory( pDeviceExt->pBuf, pBuf, ulBufLen ); KdPrint( ( "TestDriver: 超时Dpc例程IRP_MJ_WRITE离开! " ) ); //--------------------------------------------------------------------------- } else if( Stack->MajorFunction == IRP_MJ_READ ) { ulBufLen = Stack->Parameters.Read.Length; ASSERT( pDeviceExt->pBuf != NULL ); RtlCopyMemory( pBuf, pDeviceExt->pBuf, ulBufLen ); KdPrint( ( "TestDriver: 超时Dpc例程IRP_MJ_READ离开! " ) ); } } while ( FALSE ); pIrp->IoStatus.Information = ulBufLen; pIrp->IoStatus.Status = Status; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); } //=========================================================================== //写入请求 //=========================================================================== #pragma code_seg( "PAGE" ) NTSTATUS DispatchWrite ( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { LARGE_INTEGER liTimeOut; PDEVICE_EXT pDeviceExt = NULL; pDeviceExt = pDeviceObj->DeviceExtension; pDeviceExt->pIrp = pIrp; //挂起Irp IoMarkIrpPending( pIrp ); //设置超时时间为3S liTimeOut = RtlConvertLongToLargeInteger( -10 * 3000 * 1000 ); //开启定时器 KeSetTimer( &pDeviceExt->StTimer, liTimeOut, &pDeviceExt->StDpc ); KdPrint( ( "TestDriver: DispatchWrite挂起! " ) ); return STATUS_PENDING; } //=========================================================================== //读取请求 //=========================================================================== NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { LARGE_INTEGER liTimeOut; PDEVICE_EXT pDeviceExt = NULL; pDeviceExt = pDeviceObj->DeviceExtension; pDeviceExt->pIrp = pIrp; //挂起Irp IoMarkIrpPending( pIrp ); //设置超时时间为3S liTimeOut = RtlConvertLongToLargeInteger( -10 * 3000 * 1000 ); //开启定时器 KeSetTimer( &pDeviceExt->StTimer, liTimeOut, &pDeviceExt->StDpc ); KdPrint( ( "TestDriver: DispatchRead 挂起! " ) ); return STATUS_PENDING; } //=========================================================================== //驱动入口 //=========================================================================== #pragma code_seg( "INIT" ) NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) { NTSTATUS Status; ULONG i; PDEVICE_OBJECT pDeviceObj = NULL; PDEVICE_EXT pDeviceExt = NULL; UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME ); UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYSLINK_NAME ); Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObj ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "创建设备失败! " ) ); return Status; } // Status = IoCreateSymbolicLink( &USzSysLinkName, &USzDeviceName ); // if ( !NT_SUCCESS( Status ) ) { // KdPrint( ( "创建符号链接失败! " ) ); // IoDeleteDevice( pDeviceObj ); // } pDeviceObj->Flags |= DO_BUFFERED_IO; pDeviceExt = pDeviceObj->DeviceExtension; pDeviceExt->pDeviceObj = pDeviceObj; pDeviceExt->USzDeviceName = USzDeviceName; pDeviceExt->USzSysLinkName = USzSysLinkName; pDeviceExt->pBuf = NULL; //初始化Timer对象和定时器对象 KeInitializeTimer( &pDeviceExt->StTimer ); KeInitializeDpc( &pDeviceExt->StDpc, &OnTimerDpc, ( PVOID ) pDeviceObj ); for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) { pDriverObj->MajorFunction[i] = &DispathRoutine; } pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite; pDriverObj->MajorFunction[IRP_MJ_READ] = &DispatchRead; pDriverObj->DriverUnload = &DriverUnLoad; return Status; }
这边是调用这边的内核代码:
/* Windows 内核下驱动程序调用驱动程序 调用驱动 编译方法参见makefile. TAB = 8 */ #include <ntddk.h> #define SYSLINK_NAME L"\??\SysLinkTestDriver" #define MAX_PATH 260 //=========================================================================== //写入设备的回调例程 //=========================================================================== VOID Complete_Write( PVOID pContext, PIO_STATUS_BLOCK pStatus_block, ULONG Reserved ) { KdPrint( ( "InvokeDriver:写入请求现在返回了! " ) ); KeSetEvent( ( PKEVENT )pContext, IO_NO_INCREMENT, FALSE ); } //=========================================================================== //打开驱动 //=========================================================================== NTSTATUS OpenDriver() { HANDLE hDevice = NULL; HANDLE hSysLink = NULL; NTSTATUS Status; KEVENT Event; CHAR cBuf[10]; ULONG i, ulStrLen; LARGE_INTEGER liInteger; UNICODE_STRING USzDeviceName = {0}; OBJECT_ATTRIBUTES ObjAttr; PFILE_OBJECT pFileObj = NULL; IO_STATUS_BLOCK Status_Block; UNICODE_STRING USzDeviceLinkName = RTL_CONSTANT_STRING( SYSLINK_NAME ); InitializeObjectAttributes( &ObjAttr, &USzDeviceLinkName, OBJ_CASE_INSENSITIVE, NULL, NULL ); KeInitializeEvent( &Event, SynchronizationEvent, FALSE ); do { //这边是内核的对象, 加了个内核属性 InitializeObjectAttributes( &ObjAttr, &USzDeviceLinkName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); //获取符号链接句柄 Status = ZwOpenSymbolicLinkObject( &hSysLink, FILE_ALL_ACCESS, &ObjAttr ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "打开符号链接失败! " ) ); break; } USzDeviceName.Buffer = ExAllocatePool( PagedPool, MAX_PATH ); USzDeviceName.MaximumLength = MAX_PATH; ASSERT( USzDeviceName.Buffer ); //通过符号名称得到设备名称 Status = ZwQuerySymbolicLinkObject( hSysLink, &USzDeviceName, &ulStrLen ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "符号名称转换成链接名称失败! " ) ); break; } KdPrint( ( "设备名称%wZ ", &USzDeviceName ) ); InitializeObjectAttributes( &ObjAttr, &USzDeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); //--------------------------------------------------------------------------- //异步打开设备, 读写 //没有设定了FILE_SYNCHRONOUS_IO_NONALERT和 //FILE_SYNCHRONOUS_IO_ALERT为异步打开设备 Status = ZwCreateFile( &hDevice, GENERIC_ALL, &ObjAttr, &Status_Block, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, 0, NULL, 0 ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "打开设备失败! " ) ); break; } //--------------------------------------------------------------------------- //写入设备 //--------------------------------------------------------------------------- liInteger = RtlConvertLongToLargeInteger( 0 ); RtlFillMemory( cBuf, sizeof( cBuf ), 'a' ); //异步写入设备 Status = ZwWriteFile( hDevice, NULL, &Complete_Write, &Event, &Status_Block, cBuf, sizeof( cBuf ), &liInteger, NULL ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "写入设备失败! " ) ); break; } if ( Status == STATUS_PENDING ) { KdPrint( ( "InvokeDriver: ZwWriteFile 返回STATUS_PENDING! " ) ); KdPrint( ( "InvokeDriver: Waiting... " ) ); KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); } //--------------------------------------------------------------------------- //读取设备(这边没有用回调例程和事件对象) //--------------------------------------------------------------------------- liInteger = RtlConvertLongToLargeInteger( 0 ); //异步读取设备 Status = ZwReadFile( hDevice, NULL, NULL, NULL, &Status_Block, cBuf, sizeof( cBuf ), &liInteger, NULL ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "读取设备失败! " ) ); break; } if ( Status == STATUS_PENDING ) { KdPrint( ( "InvokeDriver:ZwReadFile 返回 STATUS_PENDING! " ) ); KdPrint( ( "InvokeDriver:Waiting... " ) ); Status = ObReferenceObjectByHandle( hDevice, EVENT_MODIFY_STATE, 0, KernelMode, &pFileObj, NULL ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "设备句柄转换成指针失败! " ) ); break; } KeWaitForSingleObject( &pFileObj->Event, Executive, KernelMode, FALSE, NULL ); for( i = 0; i < ( ULONG )Status_Block.Information; i++ ) { KdPrint( ( "%c ", cBuf[i] ) ); } KdPrint( ( " " ) ); } } while ( FALSE ); //--------------------------------------------------------------------------- if ( USzDeviceName.Buffer ) { ExFreePool(USzDeviceName.Buffer); } if ( hSysLink ) { ZwClose(hSysLink); } if ( pFileObj ) { ObDereferenceObject(pFileObj); } if ( hDevice ) { ZwClose( hDevice ); } return Status; } //=========================================================================== //驱动入口 //=========================================================================== NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) { NTSTATUS Status; Status = OpenDriver(); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "操作设备失败! " ) ); return STATUS_UNSUCCESSFUL; } return STATUS_UNSUCCESSFUL; }