windows内核-R3与R0通信交换数据(三)

本质上是驱动加载完成时会产生一块共享内存用于R3和R0数据交换,控制码用于控制读写哪块内存。

三种方式通信:

  • SystenBuffer (对应r3和r0的3种通信方式之一:buffer io)
  • MdlAddress (对应r3和r0的3种通信方式之一:direct io)
  • UserBuffer (对应r3和r0的3种通信方式之一:neither io)
  1. buffered io
  • 在内核层分配一块缓存,io管理器负责把应用层/内核层copy到buffer,io管理器负责把buffer拷贝到io管理器负责把内核层/应用层。
  • 优点:安全简单,因为不会操作应用层的内存,buffer是来自内核态的,应用层无法改内核层的数据,所以是安全的。
  • 缺点:效率低,因为一次通信有两次拷贝,一般传输数据量是不大的,buffer io是够用的,但如果是类似3d渲染,数据量大,direct io更适合;
  1. direct io
  • io管理器通过MPL把应用层/内核层的虚拟地址映射成物理地址,然后lock,防止被这块内存切换出去(pageout),io管理器通过MPL把同一物理地址映射成内核层/应用层的物理地址
  • 优点效率是最高的,一次通信只有一次拷贝
  • 但稍复杂
  1. neither io 内核层直接访问应用层的数据,前提是应用层和内核层同处于一个进程上下文(因为应用层内存地址是私有的,应用层进程切换之后内存就失效了),要对内核层传入的内存地址要做检查(ProbeForRead/ProbeForWrite),否则会有提取漏洞
  • Q3:三种通信方式中,应用层发下来的内存和内核层把数据返回给应用层的内存对应Irp的什么位置? 应用层发下来给内核层的内存对应Irp的;内核层把数据返回给应用层的内存对应Irp的头部SystenBuffer 、MdlAddressUserBuffer

分发函数处理 


#define ReadCtl  CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED,FILE_ANY_ACCESS) //读控制码
#define WriteCtl CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS) //写控制码
#define RWCtl    CTL_CODE(FILE_DEVICE_UNKNOWN,0x805,METHOD_BUFFERED,FILE_ANY_ACCESS) //读写控制码

NTSTATUS IRP_CALL(PDEVICE_OBJECT device, PIRP pirp)
{
	device;
	KdPrint(("进入派遣函数"));
	PIO_STACK_LOCATION irpStackL;
	//获取R3传来的参数(控制码)
	irpStackL = IoGetCurrentIrpStackLocation(pirp); //获取应用层传来的参数

	switch (irpStackL->MajorFunction)
	{
	case IRP_MJ_DEVICE_CONTROL: //DeviceIoControl
	{
		KdPrint(("用户层调用了 DeviceIoControl \n"));
		UINT32 CtlCode = irpStackL->Parameters.DeviceIoControl.IoControlCode;
		KdPrint(("IRP_MJ_DEVICE_CONTROL R0控制码:%X \n", CtlCode));
		if (CtlCode == ReadCtl)
		{
			KdPrint(("IRP_MJ_DEVICE_CONTROL ReadCtl R0控制码:%X \n", CtlCode));
			//	IRP_IO_Read(pirp); //这里写入到共享缓冲剂即可,打印R3访问共享缓冲区打印
			char* buff = (char*)pirp->AssociatedIrp.SystemBuffer;

			//将R0读取到的数据写入到向共享缓冲区
			char R0returnbuf[] = "R0 read data \n";
			ULONG len = sizeof(R0returnbuf);
			memcpy_s(buff, len, R0returnbuf, len);
			KdPrint(("read data to SystemBuffer \n"));
			pirp->IoStatus.Information = len; // 缓冲区长度
		}
		else if (CtlCode == WriteCtl)
		{
			KdPrint(("IRP_MJ_DEVICE_CONTROL WriteCtl R0控制码:%X \n", CtlCode));
			//取出R3缓冲区的数据
			//根据控制代码来选择使用AssociatedIrp.SystemBuffer的读缓冲区还是写缓冲区
			char* R3buff = (char*)pirp->AssociatedIrp.SystemBuffer;
			KdPrint(("IRP_MJ_DEVICE_CONTROL R0缓冲区:%s \n", R3buff));

		}
		else if (CtlCode == RWCtl)
		{
			KdPrint(("IRP_MJ_DEVICE_CONTROL RWCtl R0控制码:%X \n", CtlCode));
		}
		break;
	}
	case IRP_MJ_CREATE: //CreateFile
	{
		KdPrint(("用户层调用了 CreateFile \n"));
		break;
	}
	case IRP_MJ_CLOSE: //CloseHandle
	{
		KdPrint(("用户层调用了 CloseHandle \n"));
		break;
	}
	}
	pirp->IoStatus.Status = STATUS_SUCCESS;
	//	pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned
	IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作 并且不增加优先级 
	KdPrint(("离开派遣函数 \n"));
	return STATUS_SUCCESS;  //0 返回成功
}

R3层

DeviceIoControl(
		DeviceHandle,		//CreateFile 打开驱动设备返回的句柄
		WriteCtl,			//控制码 CTL_CODE  与IRP事件对应
		WriteData,			//输入缓冲区 &inBuf
		sizeof(inBuf),		//输入缓冲区大小
		&OutBuf,			//输出缓冲区
		sizeof(OutBuf),		//输出缓冲区大小
		&dwRetSize,			//返回字节数
		NULL);

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值