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

文章来源地址https://uudwc.com/A/MZ81N

应用层(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一些配置问题:

全部流程

原文地址:https://blog.csdn.net/qq_34479012/article/details/128892693

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

上一篇 2023年08月02日 01:03
使用pip使用报错:pip is configured with locations that require TLS/SSL
下一篇 2023年08月02日 01:09