忆杰的博客

忆杰的博客

直接方式模拟文件读写

上一篇说的是直接方式的读取设备, 这篇接着说. 其实还有两种方式的, 一种是直接方式读写设备, 这种方式需要创建完设备以后将Flags设置成DO_DIRECT_IO. 这种的话就是Windows内部给做内存映射, 所以相对比缓冲区方式的话就快多了.

款式也是和上一篇一样了, 就是还是模拟写入文件和读取文件的款式, 没有什么太大的区别, 主要的区别是内核这边操作方式不一样了,还多了个MDL, 这个东西Windows驱动开发技术详解也没有说, 寒江独钓也没有说, 我倒. 回头看看其他书. 反正都是这么用, 就先将就着用吧!不过这心里卡主东西, 让我很难受了.回头再看看.

直接上代码吧. 没有撒好说的, 上一篇都说了, 用户态的代码就和上一篇一样了. 主要来看看这个内核态代码!

 

/*
	Windows内核下模拟文件的读写操作, IRP的处理(使用MDL的IO方式) 0环代码
	编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>
#define  DEVICE_NAME	L"\\Device\\DevJoenDevice"
#define  SYS_LINK_NAME	L"\\??\\SysLinkJoenDevice"
#define  MAX_LENGTH	1024

typedef struct tagDEVICEEXT {
	CHAR*		pBuf;
	ULONG		ulCurFileLength;
	PDEVICE_OBJECT	pDeviceObj;
	UNICODE_STRING	USzDeviceName;
	UNICODE_STRING	USzSysLinkName;
}DEVICEEXT, *PDEVICEEXT;
//===========================================================================
//驱动卸载例程
VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) {
	PDEVICEEXT pDriveExt;
	PDEVICE_OBJECT pNextDeviceObj;

	pNextDeviceObj = pDriverObj->DeviceObject;
	while ( pNextDeviceObj != NULL ) {
		pDriveExt = (PDEVICEEXT)pNextDeviceObj->DeviceExtension;

		//删除设备和符号链接
		IoDeleteDevice(pNextDeviceObj);
		IoDeleteSymbolicLink(&pDriveExt->USzSysLinkName);

		KdPrint(( "删除%wZ设备成功!\n", &pDriveExt->USzDeviceName ));

		pNextDeviceObj = pNextDeviceObj->NextDevice;
	}	

}
//===========================================================================
//其他一概不关心的IRP处理
NTSTATUS DispatchRoutin( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return STATUS_SUCCESS;
}
//===========================================================================
//读请求处理例程
NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	ULONG ulReadLength;
	ULONG ulReadOffset;
	ULONG ulMdlLength;
	ULONG ulMdlOffset;
	PVOID ulMdlAddress;
	CHAR* pBuf;
	NTSTATUS Status;
	PDEVICEEXT pDeviceExt;
	PIO_STACK_LOCATION Stack;

	pDeviceExt = (PDEVICEEXT)pDeviceObj->DeviceExtension;
	Stack = IoGetCurrentIrpStackLocation(pIrp);

	//读取长度和偏移
	ulReadOffset = (ULONG)Stack->Parameters.Read.ByteOffset.QuadPart;
	ulReadLength = Stack->Parameters.Read.Length;

	ulMdlAddress = MmGetMdlVirtualAddress( pIrp->MdlAddress );
	ulMdlLength = MmGetMdlByteCount( pIrp->MdlAddress );
	ulMdlOffset = MmGetMdlByteOffset( pIrp->MdlAddress );

	//要读取长度大于最大长度, 返回失败
	if ( ulReadLength + ulReadOffset > MAX_LENGTH ) {
		Status = STATUS_FILE_INVALID;
		ulReadLength = 0;
	}else {
		//获取到那个MDL对应的内核地址, 都是这么用. 回头搞明白到底做了什么?
		pBuf = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
		KdPrint(( "内核下的映射地址%p\n", pBuf ));

		//写会3环那边
                RtlCopyMemory(pBuf, pDeviceExt->pBuf+ulReadOffset,ulReadLength );
		Status = STATUS_SUCCESS;
	}

	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return Status;
}
//===========================================================================
//写请求处理例程
NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	CHAR*		pBuf;
	NTSTATUS	Status;
	ULONG		ulWriteLength;
	ULONG		ulMdlLength;
	ULONG		ulWriteOffset;
	PVOID		ulMdlAddress;
	ULONG		ulMdlOffset;
	PDEVICEEXT	pDeviceExt;
	PIO_STACK_LOCATION Stack;

	pDeviceExt = (PDEVICEEXT)pDeviceObj->DeviceExtension;
	Stack = IoGetCurrentIrpStackLocation(pIrp);
	ulWriteLength = Stack ->Parameters.Write.Length;
	ulWriteOffset = (ULONG)Stack->Parameters.Write.ByteOffset.QuadPart;

	//目前不了解Windows的内存管理, 先这样用着
	ulMdlLength = MmGetMdlByteCount( pIrp->MdlAddress );
	ulMdlOffset = MmGetMdlByteOffset( pIrp->MdlAddress );
	ulMdlAddress = MmGetMdlVirtualAddress( pIrp->MdlAddress );

	//如果要写入的长度达到了最大长度, 返回无效.
        if ( ulWriteOffset + ulWriteLength > MAX_LENGTH ) {
                Status = STATUS_FILE_INVALID;
                ulWriteLength = 0;
	}

	//MDL的长度应该和读取的长度相等. 否则就有问题了
	if ( ulMdlLength != ulWriteLength ) {
		pIrp->IoStatus.Information= 0;
		Status = STATUS_UNSUCCESSFUL;

	}else {
		//获取到那个MDL对应的内核地址, 都是这么用. 回头搞明白到底做了什么?
		pBuf = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
		KdPrint(( "内核下的映射地址%p\n", pBuf ));

		//将3环那边的数据存储在缓冲区中
                RtlCopyMemory(pDeviceExt->pBuf+ulWriteOffset,pBuf,ulWriteLength );

		if ( ulWriteLength + ulWriteOffset > pDeviceExt->ulCurFileLength ) {
			pDeviceExt->ulCurFileLength = ulWriteLength + ulWriteOffset;
		}

		pIrp->IoStatus.Information = ulWriteLength;
		Status = STATUS_SUCCESS;
	}
	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 USzSysLinkName = RTL_CONSTANT_STRING( SYS_LINK_NAME );
	UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_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" ));
		IoDeleteDevice( pDeviceObj );
		return Status;
	}

	//直接缓冲区方式
	pDeviceObj->Flags |= DO_DIRECT_IO;
	pDeviceExt = (PDEVICEEXT)pDeviceObj->DeviceExtension;
	pDeviceExt->pDeviceObj = pDeviceObj;
	pDeviceExt->USzDeviceName = USzDeviceName;
	pDeviceExt->USzSysLinkName = USzSysLinkName;
	pDeviceExt->pBuf = ExAllocatePool(PagedPool, MAX_LENGTH );
	RtlZeroMemory(pDeviceExt->pBuf, MAX_LENGTH );

	//设置分发函数和卸载函数
	for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
		pDriverObj->MajorFunction[i] = &DispatchRoutin;
	}
	pDriverObj->MajorFunction[IRP_MJ_READ] = &DispatchRead;
	pDriverObj->MajorFunction[IRP_MJ_WRITE]= &DispatchWrite;
	pDriverObj->DriverUnload = &DriverUnLoad;

	return Status;
}

发表评论


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

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