除了在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;
}