码迷,mamicode.com
首页 > 其他好文 > 详细

驱动程序调用驱动程序2

时间:2014-05-08 12:15:00      阅读:510      评论:0      收藏:0      [点我收藏+]

标签:des   code   ext   int   get   c   

上一篇说到内核里面用户态这边差不多的函数, 比如ZwCreateFile, ZwReadFile什么之类的, 内核里面其实还有些更加暴力的东西存在的, 比如说用户态这边打开设备只有一个句柄, 但是内核里面是可以直接触摸到指针的, 用户态那边只可以调用几个固定的函数来发送Irp. 那么内核里面可以自定义Irp的发送, 非常的暴力, 好用!
 

 

首先我们也不用去调用什么ZwCreateFile了, 直接用这个IoGetDeviceObjectPointer函数, 这个函数可以通过设备名获得文件对象指针, 和设备对象指针, 指针啊, 不是句柄了..和ZwCreateFile一样, 末尾记得调用ObDereferenceObject函数, 来解引用.

打开以后就是发送Irp消息了, 基本上有很多的选择, 看下面代码就知道了, 有同步的又异步的, 非常的暴力好用, 看自己喜欢了. 其实看下面代码就知道了, 同步的和异步的其实区别不是很大, 无论如何还是需要一个同步事件来同步的. 只是放在了不同的地方了. 稍微搞一下就明白了, 这个很简单的嘛.

重点说说这个, ObReferenceObjectByName这号函数是未公开的函数, 一般未公开的函数就是暴力啊, 其可以获得各类对象的指针, 而不是和IoGetDeviceObjectPointer这样只能够获取设备对象的指针, ObReferenceObjectByName可以获取各种对象的指针, 非常好用了. ObReferenceObjectByName只是引用下对象的指针, 并没有打开操作, 但是IoGetDeviceObjectPointer内部是有打开操作的. 也就是相当于向设备发送了Irp_Mj_Create的Irp. 明白了他们之间的区别, 那么我们就可以适时的在二者中选择某个函数来做一些事情了.

后面还有一个模拟IoGetDeviceObjectPointer内核函数的实现, 首先要打开设备对象, 获得设备对象的句柄,然后ObReferenceObjectByHandle内核函数将设备对象的句柄, 转换设备对象相关的文件对象的指针. 然后再调用IoGetBaseFileSystemDeviceObject函数, 可以将文件对象指针得到设备对象针! 有点晕了. 主要要把握住, 设备, 文件, 句柄. 这是关键字!

下面就上代码, 测试驱动已经在上一篇中说到了, 那么这边看看代码的情况:

 

/*
	Windows 内核下驱动程序通过设备指针调用其他驱动程序 调用驱动程序
	编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>

//===========================================================================
#define SYSLINK_NAME	L"\\??\\SysLinkTestDriver"

#define MAX_PATH	260

#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h>

	NTKERNELAPI
	NTSTATUS
	ObReferenceObjectByName(
		IN PUNICODE_STRING ObjectName,
		IN ULONG Attributes,
		IN PACCESS_STATE PassedAccessState OPTIONAL,
		IN ACCESS_MASK DesiredAccess OPTIONAL,
		IN POBJECT_TYPE ObjectType,
		IN KPROCESSOR_MODE AccessMode,
		IN OUT PVOID ParseContext OPTIONAL,
		OUT PVOID *Object
	);
	NTKERNELAPI
	PDEVICE_OBJECT
	NTAPI
	IoGetBaseFileSystemDeviceObject (
		IN PFILE_OBJECT FileObject
	);
	extern POBJECT_TYPE IoDeviceObjectType;
#ifdef __cplusplus
}
#endif

//===========================================================================
//模拟系统内部IoGetDeviceObjectPointer实现
//===========================================================================
_IoGetDeviceObjectPointer( PUNICODE_STRING pObjName,  ACCESS_MASK DesiredAccess,
			  PFILE_OBJECT* ppFileObj, PDEVICE_OBJECT* ppDeviceObj  ) {
	HANDLE hDevice = NULL;
	NTSTATUS Status;
	PFILE_OBJECT pFileObj = NULL;
	OBJECT_ATTRIBUTES ObjAttr;
	IO_STATUS_BLOCK Status_block;

	//初始化要打开的设备名称
	InitializeObjectAttributes( &ObjAttr, pObjName, OBJ_KERNEL_HANDLE, NULL, NULL );

	//打开设备 对象
	Status = ZwOpenFile( &hDevice, DesiredAccess, &ObjAttr, &Status_block,
		0, FILE_NON_DIRECTORY_FILE );
	if ( !NT_SUCCESS( Status ) ) {
		return Status;
	}

	//通过设备对象句柄得到设备对象指针
	Status = ObReferenceObjectByHandle( hDevice, 0, *IoFileObjectType,
		KernelMode, &pFileObj, NULL );
	if ( !NT_SUCCESS( Status ) ) {
		return Status;
	}

	*ppFileObj = pFileObj;

	//通过设备相关文件对象指针得到设备对象指针
	*ppDeviceObj = IoGetBaseFileSystemDeviceObject( pFileObj );

	if ( hDevice ) {
		ZwClose(hDevice);
	}
	return STATUS_SUCCESS;
}
//===========================================================================
//打开设备
//===========================================================================
NTSTATUS OpenDevice() {
	NTSTATUS Status;
	HANDLE hSysLink;
	HANDLE hDevice = NULL;
	ULONG ulStrLen, i;
	UCHAR ucBuf[10];
	KEVENT Event;
	PIRP pNewIrp = NULL;
	OBJECT_ATTRIBUTES ObjAttr;
	UNICODE_STRING USzDeviceName = {0};
	PIO_STACK_LOCATION pStack = NULL;
	IO_STATUS_BLOCK Status_Block;
	LARGE_INTEGER liOffset;
	PDEVICE_OBJECT pDevice = NULL;
	PFILE_OBJECT pFileObj = NULL;
	UNICODE_STRING USzDeviceLinkName = RTL_CONSTANT_STRING( SYSLINK_NAME );

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

		//这个打开设备比ZwCreateFile好多了, 参数简单,
		//还可以直接获取到文件对象指针, 设备对象指针
		//这边还模拟了一个系统这个部分的实现.
		Status = _IoGetDeviceObjectPointer( &USzDeviceName, FILE_ALL_ACCESS,
						   &pFileObj, &pDevice );
		if ( !NT_SUCCESS( Status ) ) {
			KdPrint( ( "设备名转文件对象指针失败!\n" ) );
			break;
		}

//---------------------------------------------------------------------------
		//创建同步IRP写入请求, 这里的话, 其实同步和异步差不多
//---------------------------------------------------------------------------
		liOffset.QuadPart = 0i64;
		KeInitializeEvent( &Event, NotificationEvent, FALSE );
		RtlFillMemory( ucBuf, sizeof( ucBuf ), ‘a‘ );

		//创建同步IRP请求
		pNewIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, pDevice, &ucBuf[0],
							sizeof( ucBuf ), &liOffset,
							&Event, &Status_Block );

		//得到下一层的I/O堆栈(如果驱动不是只有一层, 应该怎么做呢?)
		pStack = IoGetNextIrpStackLocation( pNewIrp );

		//设置I/O堆栈的文件对象指针
		pStack->FileObject = pFileObj;

		//调用下一层驱动
		Status = IoCallDriver( pDevice, pNewIrp );
		if ( !NT_SUCCESS( Status ) ) {
			KdPrint( ( "调用驱动失败!\n" ) );
			break;
		}

		if ( Status == STATUS_PENDING ) {

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

			Status = Status_Block.Status;

			if ( NT_SUCCESS( Status_Block.Status ) ) {
				KdPrint( ( "写入设备成功, 总共写入了%d字节!\n",
					   Status_Block.Information ) );
			} else {
				KdPrint( ( "写入设备失败!\n" ) );
				break;
			}
		}
//---------------------------------------------------------------------------
		//创建异步Irp读取请求,
//---------------------------------------------------------------------------
		pNewIrp = NULL;
		pStack = NULL;
		KeResetEvent( &Event );
		liOffset.QuadPart = 0i64;
		RtlZeroBytes( &ucBuf[0], sizeof( ucBuf ) );

		//创建异步Irp
		pNewIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ, pDevice, &ucBuf[0],
				sizeof( ucBuf ), &liOffset, &Status_Block );

		//Irp完成后会通过这里通知这边
		pNewIrp->UserEvent = &Event;

		//获取下一层I/O堆栈
		pStack = IoGetNextIrpStackLocation( pNewIrp );

		pStack->FileObject = pFileObj;

		Status = IoCallDriver( pDevice, pNewIrp );
		if ( !NT_SUCCESS( Status ) ) {
			KdPrint( ( "读取设备请求失败!" ) );
			break;
		}

		if ( Status == STATUS_PENDING ) {
			KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
			Status = Status_Block.Status;

			if ( NT_SUCCESS( Status_Block.Status ) ) {

				KdPrint( ( "读取设备成功!\n" ) );

				for( i = 0; i < Status_Block.Information; i++ ) {
					KdPrint( ( "%c\t", ucBuf[i] ) );
				}
				KdPrint( ( "\n" ) );

			} else {
				KdPrint( ( "读取设备失败!\n" ) );
				break;
			}
		}
//---------------------------------------------------------------------------
		//手工创建Irp
//---------------------------------------------------------------------------
		pNewIrp = NULL;
		pStack = NULL;
		KeResetEvent( &Event );
		liOffset.QuadPart = 0i64;
		RtlZeroBytes( &ucBuf[0], sizeof( ucBuf ) );

		//这个创建出来的是最原始的IRP
		pNewIrp = IoAllocateIrp( pDevice->StackSize, FALSE );

		//设置同步事件
		pNewIrp->UserEvent = &Event;
		pNewIrp->UserIosb = &Status_Block;

		//填写新Irp的线程号
		pNewIrp->Tail.Overlay.Thread = PsGetCurrentThread();

		//填写缓冲区
		pNewIrp->AssociatedIrp.SystemBuffer = ucBuf;

		//获取下一层堆栈
		pStack = IoGetNextIrpStackLocation( pNewIrp );

		//填写功能号
		pStack->MajorFunction = IRP_MJ_READ;
		pStack->MinorFunction = IRP_MN_NORMAL;

		//填写文件对象
		pStack->FileObject = pFileObj;

		//填写缓冲区长度和偏移
		pStack->Parameters.Read.Length = sizeof( ucBuf );
		pStack->Parameters.Read.ByteOffset = liOffset;

		Status = IoCallDriver( pDevice, pNewIrp );
		if ( !NT_SUCCESS( Status ) ) {
			KdPrint( ( "Irp发送失败!\n" ) );
			break;
		}

		if ( Status == STATUS_PENDING  ) {
			KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );

			Status = Status_Block.Status;

			if ( NT_SUCCESS( Status_Block.Status ) ) {

				KdPrint( ( "读取设备成功!\n" ) );

				for( i = 0; i < Status_Block.Information; i++ ) {
					KdPrint( ( "%c\t", ucBuf[i] ) );
				}
				KdPrint( ( "\n" ) );

			} else {
				KdPrint( ( "读取设备失败!\n" ) );
				break;
			}

		}

	} while ( FALSE );
//---------------------------------------------------------------------------
	if ( USzDeviceName.Buffer ) {
		ExFreePool( USzDeviceName.Buffer );
	}
	if ( hSysLink ) {
		ZwClose( hSysLink );
	}
	if ( pFileObj ) {
		ObDereferenceObject( pFileObj );
	}

	return Status;
}

//===========================================================================
//驱动入口
//===========================================================================
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
	NTSTATUS Status;
	PDEVICE_OBJECT pDevice = NULL;
	PFILE_OBJECT pFileObj = NULL;
	UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( SYSLINK_NAME );

	//这号函数可以通过名字获取设备指针, 可以获取各种对象的指针(事件, 互斥量等)
	Status = ObReferenceObjectByName( &USzDeviceName, OBJ_CASE_INSENSITIVE,
		NULL, FILE_ALL_ACCESS, IoDeviceObjectType,
					  KernelMode, NULL, &pDevice );
	if ( !NT_SUCCESS( Status ) ) {
		KdPrint( ( "通过名称获取对象指针失败!\n" ) );
		return Status;
	} else {
		KdPrint( ( "通过名称获取对象指针成功!\n" ) );
	}

	if ( pDevice ) {
		ObDereferenceObject( pDevice );
		pDevice = NULL;
	}
	Status = OpenDevice();
	if ( !NT_SUCCESS( Status ) ) {
		KdPrint( ( "操作设备失败!\n" ) );
		return Status;
	} else {
		KdPrint( ( "操作设备成功!\n" ) );
	}

	return STATUS_UNSUCCESSFUL;
}

驱动程序调用驱动程序2,布布扣,bubuko.com

驱动程序调用驱动程序2

标签:des   code   ext   int   get   c   

原文地址:http://www.cnblogs.com/adylee/p/3714295.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!