ring3通过METHOD_BUFFERED、METHOD_IN_DIRECT两种常用方式和ring0级交互读文件测试

为了熟悉ring3和ring0交互过程,写了个简单的程序测试一下,以便加深印象。

本文通过测试METHOD_BUFFERED、METHOD_IN_DIRECT方式读某磁盘下固定的文件,关于ring0和ring3通信方式具体见如下链接

http://book.51cto.com/art/201107/275240.htm

具体代码如下:

ring3:

#include <Windows.h>
#include <winioctl.h>
#include <stdio.h>

#define BUFFERSIZE 1024
//两种读写方式
#define IOCTL_DO_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IN_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS)


//
//
void Usage(char *proc)
{
	printf(
		"%s -b  // buffer io\n"
		"%s -d  // direct io\n",
		proc, proc
		);
}

int main(int argc, char* argv[])
{
	if(argc != 2)
	{
		Usage(argv[0]);
		return 0;
	}
	char OutBufer[BUFFERSIZE];
	bool ret = true;
	DWORD dwLength = 0; //实际读到的文件大小
	HANDLE hDevice = CreateFile(
						"\\\\.\\KeReadSL",
						GENERIC_READ | GENERIC_WRITE,
						0,
						NULL,
						OPEN_EXISTING,
						FILE_ATTRIBUTE_SYSTEM,
						NULL);
	if(hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to open device ---- errorcode = %d ...\n",GetLastError());
		return 0;
	}
	if(strcmp(argv[1], "-b") == 0)
	{
		printf("Read File by Buffer Io way...\n");
		ret = DeviceIoControl(hDevice,
			IOCTL_DO_BUFFER,
			NULL,
			0,
			OutBufer,
			BUFFERSIZE,
			&dwLength,
			NULL);
	}
	else if (strcmp(argv[1], "-d") == 0)
	{
		printf("Read File by Direct Io way...\n");
		ret = DeviceIoControl(hDevice,
			IOCTL_IN_DIRECT,
			NULL,
			0,
			OutBufer,
			BUFFERSIZE,
			&dwLength,
			NULL);
	}
	else
	{
		Usage(argv[0]);
		ret = false;
	}
	
	if(ret)
	{
		OutBufer[dwLength] = '\0';
		printf("Congratulation!!!\nReadData: %s\n",OutBufer);
	}
	CloseHandle(hDevice);
	return 0;
}

ring0

#include <ntddk.h>

#define IOCTL_DO_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IN_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS)

typedef struct _DEVICE_EXTENSION
{
	PDEVICE_OBJECT pDevice;
	UNICODE_STRING ustrDeviceName;  //设备名称
	UNICODE_STRING ustrSymlinkName;  //符号链接名称

}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//
// 读文件(为了方便,测试读取c盘下一个小的test.txt文件)
ULONG KeReadFileData(UCHAR* OutputBuffer, ULONG BufferSize, ULONG* ReadSize)
{
	OBJECT_ATTRIBUTES objectAtrtributes;
	IO_STATUS_BLOCK iostatus;
	HANDLE hFile;
	//初始化文件路径

	UNICODE_STRING ustrFilePath;
	RtlInitUnicodeString(&ustrFilePath, L"\\??\\C:\\test.txt");

	InitializeObjectAttributes(&objectAtrtributes, &ustrFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
	//打开文件
	NTSTATUS zwStatus = ZwCreateFile(&hFile,
								GENERIC_READ,
								&objectAtrtributes,
								&iostatus,
								NULL,
								FILE_ATTRIBUTE_NORMAL,
								FILE_SHARE_READ,
								FILE_OPEN,
								FILE_SYNCHRONOUS_IO_NONALERT,
								NULL,
								0);
	if(!NT_SUCCESS(zwStatus))
	{
		KdPrint(("The file is not exist!\n"));
		return 0;
	}
	//获取文件长度
	FILE_STANDARD_INFORMATION fsi;
	zwStatus = ZwQueryInformationFile(hFile,
									&iostatus,
									&fsi,
									sizeof(FILE_STANDARD_INFORMATION),
									FileStandardInformation);
	if(!NT_SUCCESS(zwStatus))
	{
		KdPrint(("Failed to ZwQueryInformationFile ...\n"));
		ZwClose(hFile);
		return 0;
	}
	ULONG DataSizeReaded = BufferSize < fsi.EndOfFile.QuadPart ? BufferSize : fsi.EndOfFile.QuadPart;  //实际读取文件的大小
	//读取文件
	zwStatus =ZwReadFile(hFile,
					NULL,
					NULL,
					NULL,
					&iostatus,
					OutputBuffer,
					DataSizeReaded,
					NULL,
					NULL
					);
	if(!NT_SUCCESS(zwStatus))
	{
		KdPrint(("Failed to ZwReadFile ...\n"));
		ZwClose(hFile);
		return 0;
	}
	KdPrint(("The program really read %d byutes ...\n",iostatus.Information));
	*ReadSize = iostatus.Information;
	ZwClose(hFile);
	return 1;
}
//
//创建设备
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject, UNICODE_STRING devname, UNICODE_STRING symLinkName)
{
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj;
	PDEVICE_EXTENSION pDevExt;
	//创建设备
	status = IoCreateDevice(pDriverObject,
		sizeof(DEVICE_EXTENSION),
		&devname,
		FILE_DEVICE_UNKNOWN,
		0,
		TRUE,
		&pDevObj);
	if(!NT_SUCCESS(status))
		return status;
	pDevObj->Flags |= DO_BUFFERED_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devname;
	pDevExt->ustrSymlinkName = symLinkName;
	KdPrint(("devname = %wZ\nsymbollink = %wZ\n",&devname, &symLinkName));
	//创建设备链接
	status = IoCreateSymbolicLink(&symLinkName, &devname);
	if(!NT_SUCCESS(status))
	{
		KdPrint(("Failed to IoCreateSymbolicLink and delete DeviceObject --- errorcode = %d ...\n",status));
		IoDeleteDevice(pDevObj);
		return status;
	}
	return status;
}


//卸载驱动
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	PDEVICE_OBJECT pNextObj;
	KdPrint(("Enter DriverUnload...\n"));
	pNextObj = pDriverObject->DeviceObject;
	//循环遍历删除所有该驱动上的设备
	while(pNextObj != NULL)
	{
		//设备的名称和链接名称均在扩展结构中存储
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;
		//删除符号链接
		UNICODE_STRING LinkName = pDevExt->ustrSymlinkName;
		IoDeleteSymbolicLink(&LinkName);
		pNextObj = pNextObj->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
	}
}

//处理消息
NTSTATUS DeviceIoControlDispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter DeviceIoControlDispatch ...\n"));
	//得到当前栈
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输如缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
	//实际读取文件大小
	ULONG ReadSize = 0;
	//判断文件操作方式
	switch(code)
	{
	case IOCTL_DO_BUFFER: //缓冲区方式操作仅进行读文件测试)
		{
			UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			if(!KeReadFileData(OutputBuffer, cbout, &ReadSize))
				status = STATUS_UNSUCCESSFUL;
			break;
		}
	case IOCTL_IN_DIRECT: //直接文件操作
		{
			//将缓冲区映射到内核模式下地址
			UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
			if(!KeReadFileData(OutputBuffer, cbout, &ReadSize))
				status = STATUS_UNSUCCESSFUL;
			break;
		}
	default:
		{
			status = STATUS_INVALID_VARIANT;
		}
	}
	//设置IRP的完成状态
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = ReadSize;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("Leave DeviceIoControlDispatch ...\n"));
	return status;
}

//IRP请求处理函数
NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device, PIRP irp)
{
	//获得当前IRP调用的栈空间
	PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
	NTSTATUS status = STATUS_INVALID_PARAMETER;
	//处理各种请求
	switch(irpsp->MajorFunction)
	{
	case IRP_MJ_CREATE:    //此IRP需做简单处理,否则CreateFile打开设备链接出错
		{
			//简单返回一个IRP成功三部曲
			irp->IoStatus.Information = 0;
			irp->IoStatus.Status = STATUS_SUCCESS;
			IoCompleteRequest(irp,IO_NO_INCREMENT);
			//应用层,打开设备后 打印此字符串,仅为测试
			DbgPrint("congratulations gay,open device");
			status = irp->IoStatus.Status;
			break;
		}
	case IRP_MJ_CLOSE:
		{
			irp->IoStatus.Information = 0;
			irp->IoStatus.Status = STATUS_SUCCESS;
			IoCompleteRequest(irp,IO_NO_INCREMENT);
			//应用层,打开设备后 打印此字符串,仅为测试
			DbgPrint("congratulations gay,close device");
			status = irp->IoStatus.Status;
			break;
		}
	case IRP_MJ_READ:
		{
			break;
		}
	default:
		{
			DbgPrint("unknow request!!!");
			break;
		}
	}

	return status;
}

NTSTATUS 
	DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath) 
{
	DbgPrint("Enter DriverEntry\n");
//	KdPrint(("Enter DriverEntry\n"));
	NTSTATUS status;
	//设置派遣函数
	for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
		pDriverObject->MajorFunction[i] = MyDispatchFunction;

	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlDispatch;
	pDriverObject->DriverUnload = DriverUnload;

	//创建设备和链接
	UNICODE_STRING ustrDevName, ustrSymbolicName;
	RtlInitUnicodeString(&ustrDevName,  L"\\Device\\KeRead");
	RtlInitUnicodeString(&ustrSymbolicName, L"\\DosDevices\\KeReadSL");
	status = CreateDevice(pDriverObject, ustrDevName, ustrSymbolicName);
	if(!NT_SUCCESS(status))
	{
		KdPrint(("Failed to Create Device ...\n"));
		return STATUS_UNSUCCESSFUL;
	}
	KdPrint(("Exit DriverEntry\n"));
	return STATUS_SUCCESS;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值