忆杰的博客

忆杰的博客

DeviceIoControl与驱动交互

DeviceIoControl的其实和ReadFile和WriteFile是一样的, 不过这个功能更强, 一次交互能够输入数据, 也可以输出数据. 更加暴力. DeviceIoControl内部创建的IRP是IRP_MJ_DEVICE_CONTROL类型的IRP, 然后操作系统会将这个IRP转发给驱动程序的分发函数中. 就是类似Win32下面的发送自定义消息了.. 但是又有点区别, 如果发送自定义消息, 如果跨进程, 那是不可以传递指针的, 但是和驱动那就无所谓了, 可以传递一块缓冲区过去, 多舒服.

其实这个也没有什么好说的,前面几篇已经试验过了ReadFile, 和WriteFile. 所以这个没有什么区别了.就是多了个定义I/O控制码的流程. I/O控制码也是非常简单的, 使用CTL_CODE宏来创建, 第一个参数是设备类型, 第二个参数就是控制码, 随便选一个大于0x800就可以. 然后就是缓冲区的操作方式了. 前面几篇我们已经见识过3种缓冲区操作方式了. 所以呢, 这个也不是什么问题了.. 最后一个是操作权限, 不要多想. 用FILE_ANY_ACCESS所有权限就OK..

其他就没有什么好说了. 这个代码的话就是用户层这边试验了3中缓冲区方式发送的内核这边, 内核这个做个响应. 没有什么难以理解的地方. 直接上代码!

http://www.joenchen.com/JoenTools/DeviceIoControlIo.rar

用户态:

/*
	Windows内核下DeviceIoControl与驱动进行交互 3环代码
	编译方法参见makefile. TAB = 8
*/
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>

#define  SYS_LINK_NAME	"\\\\.\\SysLinkJoenDevice"
#define  MAX_LENGTH	1024

//		             设备类型             功能号 I/O访问内存使用方式 权限
#define IOCTL_CONTROL_BUFFERED	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define IOCTL_CONTROL_DIRECT	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS )
#define IOCTL_CONTROL_NEITHER	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS )

#pragma comment(linker, "/Entry:Jmain")
#pragma comment(linker, "/subsystem:console")

//===========================================================================
int Jmain() {
	HANDLE	hFile = 0;
	BYTE	byBuf[10];
	BYTE	byBuf2[10];
	BOOL	bRet;
	DWORD	dwByteRead, i;

	//打开设备
	hFile = CreateFile( SYS_LINK_NAME, GENERIC_READ | GENERIC_WRITE, 0, 0,
	                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0  );

	if ( hFile == INVALID_HANDLE_VALUE ) {
		printf( "打开设备错误了!\n" );
		return -1;
	}

	printf( "打开设备成功!\n" );

	RtlFillMemory( byBuf, sizeof( byBuf ), '1' );
	bRet = DeviceIoControl( hFile, IOCTL_CONTROL_BUFFERED, byBuf, sizeof( byBuf ), \
	                        byBuf2, sizeof( byBuf2 ), &dwByteRead, NULL );

	if ( bRet ) {
		printf( "BUFFERED  返回缓冲区长度%d, 数据:" );
		for ( i = 0; i < dwByteRead; i++ ) {
			printf( "%c", byBuf2[i] );
		}
		printf( "\n" );
	}

	RtlFillMemory( byBuf, sizeof( byBuf ), '2' );

	bRet = DeviceIoControl( hFile, IOCTL_CONTROL_DIRECT, byBuf, sizeof( byBuf ),
	                        byBuf2, sizeof( byBuf2 ), &dwByteRead, NULL );

	if ( bRet ) {

		printf( "DIRECT  返回缓冲区长度%d, 数据:" );
		for ( i = 0; i < dwByteRead; i++ ) {
			printf( "%c", byBuf2[i] );
		}
		printf( "\n" );
	}

	RtlFillMemory( byBuf, sizeof( byBuf ), '3' );

	bRet = DeviceIoControl( hFile, IOCTL_CONTROL_NEITHER, byBuf, sizeof( byBuf ),
	                        byBuf2, sizeof( byBuf2 ), &dwByteRead, NULL );

	if ( bRet ) {
		printf( "NEITHER  返回缓冲区长度%d, 数据:" );
		for ( i = 0; i < dwByteRead; i++ ) {
			printf( "%c", byBuf2[i] );
		}
		printf( "\n" );
	}

	if ( hFile ) {
		CloseHandle( hFile );
	}

	system( "pause" );

	ExitProcess(0);
	return 0;
}

内核态:

/*
	Windows内核下DeviceIoControl与驱动进行交互 0环代码
	编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>

#define  DEVICE_NAME	L"\\Device\\DevJoenDevice"
#define  SYS_LINK_NAME	L"\\??\\SysLinkJoenDevice"
#define  MAX_LENGTH	1024

//		             设备类型             功能号 I/O访问内存使用方式 权限
#define IOCTL_CONTROL_BUFFERED	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define IOCTL_CONTROL_DIRECT	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS )
#define IOCTL_CONTROL_NEITHER	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS )

typedef struct tagDeviceExt {
	PDEVICE_OBJECT pDeviceObj;
	UNICODE_STRING USzDeviceName;
	UNICODE_STRING USzSysLinkName;
}DEVICEEXT, *PDEVICEEXT;

//===========================================================================
//驱动卸载例程
#pragma  code_seg( "PAGE" )
VOID DriverUnload( PDRIVER_OBJECT pDriverObj ) {
	PDEVICEEXT pDeviceExt;
	PDEVICE_OBJECT pNextDeviceObj;

	pNextDeviceObj = pDriverObj->DeviceObject;

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

		IoDeleteDevice( pDeviceExt->pDeviceObj );
		IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName );
		KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) );
		pNextDeviceObj = pNextDeviceObj->NextDevice;
	}
}

//===========================================================================
//所有不关心的IRP处理例程
NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {

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

//===========================================================================
//设备控制请求
NTSTATUS DispatchDeviceControl( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	ULONG		Code, i;
	NTSTATUS	Status;
	ULONG		ulInBufLen;
	ULONG		ulOutBufLen;
	ULONG		ulOutInfo;
	UCHAR*		InputBuffer = NULL;
	UCHAR*		OutputBuffer = NULL;
	PIO_STACK_LOCATION Stack;

	Stack = IoGetCurrentIrpStackLocation( pIrp );
	//输入缓冲区大小
	ulInBufLen = Stack->Parameters.DeviceIoControl.InputBufferLength;
	//输出缓冲区大小
	ulOutBufLen = Stack->Parameters.DeviceIoControl.OutputBufferLength;
	//IO控制码
	Code = Stack->Parameters.DeviceIoControl.IoControlCode;

	Status = STATUS_SUCCESS;
	ulOutInfo = ulOutBufLen;

	switch ( Code ) {
//===========================================================================
//		缓冲区IO, 很安全
	case IOCTL_CONTROL_BUFFERED:
		InputBuffer = ( UCHAR* )pIrp->AssociatedIrp.SystemBuffer;

		if ( InputBuffer ) {

			KdPrint( ( "BUFFERED输入缓冲区数据:\n" ) );

			for ( i = 0; i < ulInBufLen; i++ ) {
				KdPrint( ( "%X", InputBuffer[i]  ) );
			}
			KdPrint(( "\n" ));

			RtlFillMemory( pIrp->AssociatedIrp.SystemBuffer, ulOutBufLen, 'a' );
		}
		break;
//===========================================================================
//		MDL类型的IO, MDL的输入缓冲区和缓冲区IO是一样的.
	case IOCTL_CONTROL_DIRECT:
		InputBuffer = ( UCHAR* )pIrp->AssociatedIrp.SystemBuffer;

		if ( InputBuffer ) {
			KdPrint( ( "IN_DIRECT/IO输入缓冲区的数据:\n" ) );

			for ( i = 0; i < ulInBufLen; i++ ) {
				KdPrint( ( "%X", InputBuffer[i] ) );
			}
			KdPrint( ( "\n" ) );
		}

		KdPrint( ( "用户传入OutputBuffer地址: %p\n",
		           MmGetMdlVirtualAddress( pIrp->MdlAddress ) ) );

		//得到输出缓冲地址
		OutputBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );

		if ( OutputBuffer ) {
			KdPrint( ( "映射到内核中的地址是: %p\n", OutputBuffer ) );

			RtlFillMemory( OutputBuffer,ulOutBufLen, 'b' );
		}
		break;
//===========================================================================
//		其他方式的IO
	case IOCTL_CONTROL_NEITHER:

		//得到输入/输出缓冲区
		InputBuffer = ( UCHAR* )Stack->Parameters.DeviceIoControl.Type3InputBuffer;
		OutputBuffer = ( UCHAR* )pIrp->UserBuffer;

		KdPrint( ( "NEITHER/IO用户模式传入的地址%p\n", InputBuffer ) );

		__try {
			//测试用户层传递的内存可读性
			ProbeForRead( InputBuffer, ulInBufLen, 4 );

			for ( i = 0; i < ulInBufLen; i++ ) {
				KdPrint( ( "%X", InputBuffer[i] ) );
			}
			KdPrint(( "\n" ));

			ProbeForWrite( OutputBuffer, ulOutBufLen, 4 );

			RtlFillMemory( OutputBuffer, ulOutBufLen, 'c' );

		}__except( EXCEPTION_EXECUTE_HANDLER ) {
			KdPrint( ( "Win32程序传入了一个无效的地址!\n" ) );
			Status = STATUS_UNSUCCESSFUL;
		}

		break;
//---------------------------------------------------------------------------

	default:
		Status = STATUS_INVALID_VARIANT;
	}

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

//===========================================================================
//驱动程序入口
#pragma  code_seg( "INIT" )
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
	ULONG i;
	NTSTATUS Status;
	PDEVICEEXT pDeviceExt;
	PDEVICE_OBJECT pDeviceObj;
	UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME );
	UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYS_LINK_NAME );

	Status = IoCreateDevice( pDriverObj, sizeof( DEVICEEXT ), &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" ) );
		return Status;
	}

	//采用直接IO方式
	pDeviceObj->Flags |= DO_DIRECT_IO;
	pDeviceExt = pDeviceObj->DeviceExtension;
	pDeviceExt->pDeviceObj = pDeviceObj;
	pDeviceExt->USzDeviceName = USzDeviceName;
	pDeviceExt->USzSysLinkName = USzSysLinkName;

	for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
		pDriverObj->MajorFunction[i] = &DispatchRoutine;
	}
	pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &DispatchDeviceControl;
	pDriverObj->DriverUnload = &DriverUnload;

	return Status;
}

 

发表评论


Warning: Undefined variable $user_ID in /www/wwwroot/joenchen.com/wp-content/themes/agan/comments.php on line 66

您必须登录 才能进行评论。