除了在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下面是差不多的, 所以不说了. 直接上代码:首先是测试驱动:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
	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成功!\n", &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\t", *( pBuf + i ) ) );
			}
			KdPrint( ( "\n" ) );

			pDeviceExt->pBuf = ExAllocatePool( NonPagedPool, ulBufLen );
			ASSERT( pDeviceExt->pBuf );

			RtlCopyMemory( pDeviceExt->pBuf, pBuf, ulBufLen );

			KdPrint( ( "TestDriver: 超时Dpc例程IRP_MJ_WRITE离开!\n" ) );
//---------------------------------------------------------------------------
		} 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离开!\n" ) );
		}

	} 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挂起!\n" ) );
	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 挂起!\n" ) );
	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( ( "创建设备失败!\n" ) );
		return Status;
	}

//	Status = IoCreateSymbolicLink( &USzSysLinkName, &USzDeviceName );
//	if ( !NT_SUCCESS( Status ) ) {
//		KdPrint( ( "创建符号链接失败!\n" ) );
//		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;
}

这边是调用这边的内核代码:

```c++ /* Windows 内核下驱动程序调用驱动程序 调用驱动 编译方法参见makefile. TAB = 8 */ #include ;

#define SYSLINK_NAME L”\??\SysLinkTestDriver” #define MAX_PATH 260 //=========================================================================== //写入设备的回调例程 //=========================================================================== VOID Complete_Write( PVOID pContext, PIO_STATUS_BLOCK pStatus_block, ULONG Reserved ) {

1
2
KdPrint( ( "InvokeDriver:写入请求现在返回了!\n" ) );
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 );

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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( ( "打开符号链接失败!\n" ) );
        break;
    }

    USzDeviceName.Buffer = ExAllocatePool( PagedPool, MAX_PATH );
    USzDeviceName.MaximumLength = MAX_PATH;
    ASSERT( USzDeviceName.Buffer );

    //通过符号名称得到设备名称
    Status = ZwQuerySymbolicLinkObject( hSysLink, &USzDeviceName, &ulStrLen );
    if ( !NT_SUCCESS( Status ) ) {
        KdPrint( ( "符号名称转换成链接名称失败!\n" ) );
        break;
    }

    KdPrint( ( "设备名称%wZ\n", &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( ( “打开设备失败!\n” ) ); break; } //————————————————————————— //写入设备 //————————————————————————— liInteger = RtlConvertLongToLargeInteger( 0 ); RtlFillMemory( cBuf, sizeof( cBuf ), ‘a’ );

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    //异步写入设备
    Status = ZwWriteFile( hDevice, NULL, &Complete_Write, &Event, &Status_Block,
                  cBuf, sizeof( cBuf ), &liInteger, NULL  );
    if ( !NT_SUCCESS( Status ) ) {
        KdPrint( ( "写入设备失败!\n" ) );
        break;
    }

    if ( Status == STATUS_PENDING ) {
        KdPrint( ( "InvokeDriver: ZwWriteFile 返回STATUS_PENDING!\n" ) );
        KdPrint( ( "InvokeDriver: Waiting...\n" ) );

        KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
    }

//————————————————————————— //读取设备(这边没有用回调例程和事件对象) //————————————————————————— liInteger = RtlConvertLongToLargeInteger( 0 );

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    //异步读取设备
    Status = ZwReadFile( hDevice, NULL, NULL, NULL, &Status_Block,
                 cBuf, sizeof( cBuf ), &liInteger, NULL );
    if ( !NT_SUCCESS( Status ) ) {
        KdPrint( ( "读取设备失败!\n" ) );
        break;
    }

    if ( Status == STATUS_PENDING ) {
        KdPrint( ( "InvokeDriver:ZwReadFile 返回 STATUS_PENDING!\n" ) );
        KdPrint( ( "InvokeDriver:Waiting...\n" ) );

        Status = ObReferenceObjectByHandle( hDevice, EVENT_MODIFY_STATE,
                            0, KernelMode,
                            &pFileObj, NULL );
        if ( !NT_SUCCESS( Status ) ) {
            KdPrint( ( "设备句柄转换成指针失败!\n" ) );
            break;
        }

        KeWaitForSingleObject( &pFileObj-&gt;Event, Executive,
                       KernelMode, FALSE, NULL );

        for( i = 0; i &lt; ( ULONG )Status_Block.Information; i++ ) {
            KdPrint( ( "%c\t", cBuf[i] ) );
        }
        KdPrint( ( "\n" ) );

    }
} 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;

1
2
3
4
5
6
Status = OpenDriver();
if ( !NT_SUCCESS( Status ) ) {
    KdPrint( ( "操作设备失败!\n" ) );
    return STATUS_UNSUCCESSFUL;
}
return STATUS_UNSUCCESSFUL;

}