Windows驱动(用户层R3与内核层R0通信)

这篇具有很好参考价值的文章主要介绍了Windows驱动(用户层R3与内核层R0通信)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

内存空间分为用户层和系统层,普通的应用程序只能运行在用户层,为了可以操作系统层的内存 所以引入了驱动程序,有了驱动就可以通过用户层来操作系统层的内存及函数,所以驱动就是应用层和系统层之间的一个桥梁

在应用层通过创建符号链接,自动产生驱动层的IRP事件,即可执行系统层的IRP函数,从而将应用层的数据传到系统层。

首先加载驱动使得系统层存在一个符号链接,然后应用层就可以创建跟系统层同名的符号链接

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

R0创建驱动对象->R0创建驱动设备->R0创建符号链接->R3打开符号链接->R3传入控制码(读、写)->R0执行IRP函数 -> R0根据控制码判断读写哪块共享内存->R3收到R0的读写结果 ->R0删除符号链接 ->R0删除驱动设备

驱动层

#include<ntifs.h>

//控制码与用户层保持一致
#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) //读写控制码

void IRP_IO_Read(PIRP pirp)
{
	char* buff = (char*)pirp->AssociatedIrp.SystemBuffer;
	//获取R3传来的参数(控制码)
	PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pirp);
	//将R0读取到的数据写入到向共享缓冲区
	char R0returnbuf[] = "zxxx R0 read data \n";
	ULONG len = sizeof(R0returnbuf);
	memcpy_s(buff, len, R0returnbuf, len);
	KdPrint(("zxxx IRP_IO_Read read data to SystemBuffer \n"));

	//每次IRP执行完了 要执行下面三行 作为返回结果
	pirp->IoStatus.Status = STATUS_SUCCESS;
	pirp->IoStatus.Information = len;  //共享缓冲区返回的长度
	IoCompleteRequest(pirp, IO_NO_INCREMENT);
}

/*
void IRP_IO_Write(PIRP pirp)
{

}

void IRP_IO_ReadWrite(PIRP pirp)
{

}

*/


//创建驱动对象->创建驱动设备->创建符号链接->使用符号链接  ->删除符号链接 ->删除驱动设备
//当用户层打开符号链接时 会产生IRP事件执行IRP函数 通过IRP函数与内核通信

//创建驱动对象并绑定符号链接
NTSTATUS CreateDevice(PDRIVER_OBJECT driver)
{
	NTSTATUS status;
	UNICODE_STRING MyDriver;	//驱动名称
	PDEVICE_OBJECT device;		//驱动设备
	RtlInitUnicodeString(&MyDriver,L"\\DEVICE\\MyDriver");//初始化驱动名称
	
	//在驱动对象上创建驱动设备
	status = IoCreateDevice(driver, sizeof(driver->DriverExtension),&MyDriver,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&device);

	if (status == STATUS_SUCCESS)
	{
		KdPrint(("zxxx 驱动设备对象创建成功 \n"));
		//创建符合链接
		UNICODE_STRING uzSymbolName;
		RtlInitUnicodeString(&uzSymbolName,L"\\??\\MyDriver"); //初始化符号链接 符号链接格式 L"\\??\\名字
		//为驱动设备绑定符号链接    后续不会使用驱动对象与内核交换,而是使用符号链接与内核交换
		status = IoCreateSymbolicLink(&uzSymbolName,&MyDriver);
		if (status == STATUS_SUCCESS)
		{
			KdPrint(("zxxx 符号链接创建成功 %wZ \n",&uzSymbolName));
		}
		else
		{
			KdPrint(("zxxx 符号链接创建失败 %wZ \n", &uzSymbolName));
		}
	}
	else 
	{
		KdPrint(("zxxx 驱动设备对象创建失败 \n"));
		IoDeleteDevice(device);
	}
	return status;
}

//传入驱动设备的IRP事件
NTSTATUS IRP_CALL(PDEVICE_OBJECT device,PIRP pirp)
{
	device;
	KdPrint(("zxxx 发生IRP事件 进入IRP函数 \n"));
	PIO_STACK_LOCATION irpStackL;
	irpStackL = IoGetCurrentIrpStackLocation(pirp);

	switch (irpStackL->MajorFunction)
	{
		case IRP_MJ_CREATE:
		{
			KdPrint(("zxxx IRP_MJ_CREATE \n"));
			break;
		}
		case IRP_MJ_CLOSE:
		{
			KdPrint(("zxxx IRP_MJ_CLOSE \n"));
			break;
		}
		case IRP_MJ_DEVICE_CONTROL:
		{
			KdPrint(("zxxx IRP_MJ_DEVICE_CONTROL \n"));
			//取到的R3的控制码
			UINT32 CtlCode = irpStackL->Parameters.DeviceIoControl.IoControlCode;
			KdPrint(("zxxx IRP_MJ_DEVICE_CONTROL R0控制码:%X \n", CtlCode));


			if ( CtlCode  == ReadCtl )
			{
				KdPrint(("zxxx IRP_MJ_DEVICE_CONTROL ReadCtl R0控制码:%X \n", CtlCode));
				IRP_IO_Read(pirp); //这里写入到共享缓冲剂即可,打印R3访问共享缓冲区打印
				return STATUS_SUCCESS;
			}
			else if ( CtlCode == WriteCtl )
			{
				KdPrint(("zxxx IRP_MJ_DEVICE_CONTROL WriteCtl R0控制码:%X \n", CtlCode));
				//取出R3缓冲区的数据
				//根据控制代码来选择使用AssociatedIrp.SystemBuffer的读缓冲区还是写缓冲区
				char* R3buff = (char*)pirp->AssociatedIrp.SystemBuffer;
				KdPrint(("zxxx IRP_MJ_DEVICE_CONTROL R0缓冲区:%s \n", R3buff));

			}
			else if (CtlCode == RWCtl )
			{
				KdPrint(("zxxx IRP_MJ_DEVICE_CONTROL RWCtl R0控制码:%X \n", CtlCode));
			}
			break;
		}
	}

	//注意 只要pirp这个对象发生变化 就要跟着下面这三行 
	pirp->IoStatus.Status = STATUS_SUCCESS;
	pirp->IoStatus.Information = 4;
	IoCompleteRequest(pirp,IO_NO_INCREMENT);
	KdPrint(("zxxx 结束IRP事件 离开IRP函数 \n"));
	return STATUS_SUCCESS;
}

//卸载驱动
void Unload(PDRIVER_OBJECT pDriver)
{
	KdPrint(("zxxx unload  %p \n", pDriver));
	//先删除符号链接
	//再删除驱动设备
	if (pDriver->DeviceObject)
	{
		UNICODE_STRING uzSymbolName;
		RtlInitUnicodeString(&uzSymbolName, L"\\??\\MyDriver");
		IoDeleteSymbolicLink(&uzSymbolName);
		IoDeleteDevice(pDriver->DeviceObject);
		KdPrint(("zxxx 删除符号链接 \n"));
		KdPrint(("zxxx 删除驱动设备 \n"));
	}
}

NTSTATUS
DriverEntry(
	_In_ PDRIVER_OBJECT DriverObject,
	_In_ PUNICODE_STRING RegistryPath
)
{
	//初始化驱动对象
	DriverObject->DriverUnload = Unload;					//指定卸载驱动函数
	DriverObject->MajorFunction[IRP_MJ_CREATE] = IRP_CALL;	//指定IRP事件函数
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = IRP_CALL;   //指定IRP事件函数
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_CALL;   //指定IRP事件函数

	//创建驱动设备
	CreateDevice(DriverObject);

	RegistryPath;
	KdPrint(("zxxx entry  \n"));
	return 0;
}

应用层(MFC)

//通过不同的控制码让驱动执行不同的函数
//控制码在用户层和驱动层都需要定义且保持一致
#include<winioctl.h>
#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) //读写控制码

static HANDLE DeviceHandle = NULL;
//打开驱动按钮
void CMFCApplication1Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	//创建驱动
	//执行 CreateFileW 会触发IRP事件 执行IRP函数 IRP_MJ_CREATE被执行
	DeviceHandle = CreateFileW(
		L"\\??\\MyDriver",		//符号链接
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);
}

//关闭驱动按钮
void CMFCApplication1Dlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	//执行 CloseHandle 会触发IRP事件 执行IRP函数 IRP_MJ_CLOSE被执行
	CloseHandle(DeviceHandle);
}

//读数据按钮
void CMFCApplication1Dlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	DWORD dwRetSize = 0;
	typedef struct TINPUT_BUF
	{
		DWORD m_arg1;
		DWORD m_arg2;
		DWORD m_arg3;
		DWORD m_arg4;
		DWORD m_arg5;
		DWORD m_arg6;
	}TINPUT_BUF;

	//打印控制码 测试 验证R3与R0是否一致
	char buftest[256];
	sprintf_s(buftest, "zxxx R3 控制码:%x", ReadCtl);
	OutputDebugStringA(buftest);

	char WriteData[100] = "zxxx R3 DeviceIoControl read test \n";

	TINPUT_BUF inBuf = { 0 };    //写数据 R3的数据写入到R0
	CHAR OutBuf[512] = { 0 };	//输出缓冲区	   //读数据 R0的数据读出到R3
	//IRP函数DeviceIoControl  
	//这里的控制码+缓冲区 指明了R3读(写)了哪块共享内存,后续驱动用控制码即可执行对应的读写操作
	DeviceIoControl(
		DeviceHandle,		//CreateFile 打开驱动设备返回的句柄
		ReadCtl,			//控制码 CTL_CODE  与IRP事件对应
		WriteData,			//输入缓冲区 &inBuf
		sizeof(inBuf),		//输入缓冲区大小
		&OutBuf,			//输出缓冲区
		512,		//输出缓冲区大小
		&dwRetSize,			//返回字节数
		NULL
	);

	//打印返回参数
	CString csStr;
	csStr.Format(L"zxxx R3读到的数据 %x \n", OutBuf[0]);
	OutputDebugStringA("zxxx R3读到的数据 \n");
	strcat_s(OutBuf," zxxx R3");
	//R3读取到的结果
	OutputDebugStringA(OutBuf);
}

//写数据按钮
void CMFCApplication1Dlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	DWORD dwRetSize = 0;
	typedef struct TINPUT_BUF
	{
		DWORD m_arg1;
		DWORD m_arg2;
		DWORD m_arg3;
		DWORD m_arg4;
		DWORD m_arg5;
		DWORD m_arg6;
	}TINPUT_BUF;

	//打印控制码 测试 验证R3与R0是否一致
	char buftest[256];
	sprintf_s(buftest,"zxxx R3 控制码:%x", WriteCtl);
	OutputDebugStringA(buftest);
	
	char WriteData[100] = "zxxx R3 DeviceIoControl write test \n";

	//打印缓冲区 测试 验证R3与R0是否一致
	char buftest2[100];
	memcpy(buftest2, WriteData,100);
	OutputDebugStringA(buftest2);

	TINPUT_BUF inBuf = { 1,2,3,4,5,0x6ABC666 };    //写数据 R3的数据写入到R0
	DWORD OutBuf[6] = { 0 };	//输出缓冲区	   //读数据 R0的数据读出到R3
	//IRP函数DeviceIoControl  
	//这里的控制码+缓冲区 指明了R3读(写)了哪块共享内存,后续驱动使用控制码即可执行对应的读写操作
	DeviceIoControl(
		DeviceHandle,		//CreateFile 打开驱动设备返回的句柄
		WriteCtl,			//控制码 CTL_CODE  与IRP事件对应
		WriteData,			//输入缓冲区 &inBuf
		sizeof(inBuf),		//输入缓冲区大小
		&OutBuf,			//输出缓冲区
		sizeof(OutBuf),		//输出缓冲区大小
		&dwRetSize,			//返回字节数
		NULL
	);
}

 MFC一些配置问题:

r3层和r0层,Windows驱动,驱动开发

r3层和r0层,Windows驱动,驱动开发

r3层和r0层,Windows驱动,驱动开发

全部流程

r3层和r0层,Windows驱动,驱动开发

r3层和r0层,Windows驱动,驱动开发文章来源地址https://www.toymoban.com/news/detail-619770.html

到了这里,关于Windows驱动(用户层R3与内核层R0通信)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • APP渗透—MobSF安全评估、frida、r0capture抓包

      在之前的文章都已经介绍了如何对APP应用及小程序的抓包方式,本次将主要探讨,如何更全面的获取详细信息与获取非HTTP/S的流量,同时利用自动化工具对APK文件继续自动化扫描相关的威胁。   APP与小程序—信息收集   在之前的演示中只是介绍了一下AppInfoScanner项目

    2024年02月03日
    浏览(41)
  • R3live官方数据集测试及R3live+ Velodyne

    1. 下载livox-SDK,编译安装 2.下载livox驱动,编译安装 3.CGAL和pcl_viewer安装 4.下载r3live源码,编译安装 顺利编译成功后就可以尝试运行launch文件了,我们需要将livox驱动source到环境中,所以需要从livox_ws文件夹中启动 再rosbag play你的数据集就可以了。 r3live一般使用的是livox固态激

    2024年02月14日
    浏览(47)
  • 遥感目标检测(1)--R3Det

    目录 一、概述 二、三个挑战 三、网络架构​ 1、旋转RetinaNet 2、精细化旋转RetinaNet 3、与RoIAlign(感兴趣区域插值)进行比较 4、消融实验与对比实验           R3Det论文中提到一个端到端的精细化的单级旋转检测器,通过从粗到细的逐步回归的方法快速和准确地目标检测。

    2024年02月17日
    浏览(33)
  • 真手把手带你跑r3live

    实验室来了台机器人,上面的设备是依据r3live的设备选的,因为R3LIVE的效果太好了,特别感谢大佬的开源精神。这几天把车子跑起来,就打算写个博客记录一下。 本人能力有限,可能某些地方会有些问题,若发现问题,还请指正。 效果如下: 在多传感器融合slam中,由于会集

    2024年02月09日
    浏览(73)
  • 小米路由R3G Breed 刷Padavan/openWRT固件

    小米R3G这款路由器,采用MT7621A处理器,256M RAM,128M ROM,全千兆网口,且价格便宜(60CNY左右),是一款十分值得折腾的路由器,推荐想要折腾路由器的新手入手。 本文介绍使用UART串口向小米路由R3G刷入Breed的详细操作流程, 通过此方式,可以绕过小米官方对系统固件的限制(

    2024年02月08日
    浏览(170)
  • 2022-12-07 小米pro路由(R3G) 刷固件 openwrt

    1.先登录小米开发者平台,解开小米路由的SSH http://www.miwifi.com/miwifi_open.html 2.路由连接电脑,通过SSH可直接登录到小米路由   如何刷入breed 不同设备方法不同,可以直接U盘,请自行搜索方法 拔掉路由器电源,按住reset同时接上电源等双蓝灯闪烁后松开, 浏览器输入 192.168.1.1 即

    2024年02月05日
    浏览(122)
  • 小米R3G-OpenWrt&花生壳内网穿透插件

    首先,花生壳官网提供了教程,但细节处需要自己把握。本文就是对细节的补充说明。 通过ssh登录路由器  输出: 通过互联网搜索,可以得知,R3G-MT7621选择mipsel-24kc的版本  按顺序上传安装:  安装成功后:  接下来的一些步骤按照官网的教程走。 配置好后检查: 登陆软件

    2024年02月15日
    浏览(95)
  • 【Arduino UNO R3使用esp8266-01s连接onenet云平台

    注意 : 1、电源接口一定是纯净的3.3V电压(此电源最好没有串并联其他元器件)否则可能出现电压不稳定,无法成功连接。 2、第一次wifi模块第一次使用需要 手动配置热点 ,连接成功之后才可将完整的程序代码烧录进arduino开发板。 测试连接esp826601s代码段 : (手动配置热

    2023年04月16日
    浏览(47)
  • 小米R3G路由器Breed控制台刷OpenWrt固件

    地址:192.168.123.1 用户名:root 密码:password 这不是官方原生固件,是定制版的,主要加了“ SSR,网易解锁歌曲,KMS服务” ,可看Github项目https://github.com/TwoTu/OpenWrt-MiR3G,每月2号自动拉取源码更新固件。 固件下载地址: GitHub:https://github.com/TwoTu/OpenWrt-MiR3G/releases 百度网盘:

    2024年02月10日
    浏览(110)
  • 真手把手带你跑r3live by 自己设备 (二)

    前面详细讲了如何给电脑连接avia 和 海康工业相机,连接后想跑r3live呢,则需要标定好相机内参和avia 和相机之间的外参。 首先标定海康工业相机的内参,则可以用到livox_camera_lidar_calibration帮助我们得到相机内参 by cameraCalib.launch。官方写的很详细,直接跑就可以得到参数了。

    2024年02月17日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包