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

在应用层通过创建符号链接,自动产生驱动层的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的数据写入到R0CHAR OutBuf[512] = { 0 };   //输出缓冲区    //读数据 R0的数据读出到R3//IRP函数DeviceIoControl  //这里的控制码+缓冲区 指明了R3读(写)了哪块共享内存,后续驱动用控制码即可执行对应的读写操作DeviceIoControl(DeviceHandle,       //CreateFile 打开驱动设备返回的句柄ReadCtl,            //控制码 CTL_CODE  与IRP事件对应WriteData,          //输入缓冲区 &inBufsizeof(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的数据写入到R0DWORD OutBuf[6] = { 0 };   //输出缓冲区    //读数据 R0的数据读出到R3//IRP函数DeviceIoControl  //这里的控制码+缓冲区 指明了R3读(写)了哪块共享内存,后续驱动使用控制码即可执行对应的读写操作DeviceIoControl(DeviceHandle,      //CreateFile 打开驱动设备返回的句柄WriteCtl,           //控制码 CTL_CODE  与IRP事件对应WriteData,          //输入缓冲区 &inBufsizeof(inBuf),        //输入缓冲区大小&OutBuf,           //输出缓冲区sizeof(OutBuf),      //输出缓冲区大小&dwRetSize,            //返回字节数NULL);
}

MFC一些配置问题:

全部流程

Windows驱动(用户层R3与内核层R0通信)相关推荐

  1. 【Linux 内核 内存管理】内存管理架构 ④ ( 内存分配系统调用过程 | 用户层 malloc free | 系统调用层 brk mmap | 内核层 kmalloc | 内存管理流程 )

    文章目录 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) 二.内存管理流程 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) " 堆内存 " ...

  2. 用户层和内核层异常的处理流程

    文章目录 内核层异常的处理流程 用户层异常和内核层异常 KiDispatchException函数详解 RtlDispatchException函数的执行流程 用户层异常的处理流程 用户异常的处理流程 ...

  3. 安卓RK3399编译驱动MPU6050,实现内核层与HAL层驱动

    新手编译安卓驱动学习 今天我们一起学习一下如何实现对一款有驱动代码的传感器适配安卓系统 开发板:某AR眼镜公司的开发板RK3399 文章目录 新手编译安卓驱动学习 安卓驱动开发常用知识(非新手可以跳过 ...

  4. 安卓学习日记(一):了解安卓架构(linux内核层、系统运行库层、应用框架层、应用层)

    首先为了理解安卓系统是怎么工作的,就先来看一下android的系统架构,其架构大至可以分为四层:linux内核层.系统运行库层.应用框架层和应用层,那就先说说这几层. 1.linux内核层: Andr ...

  5. windows驱动快速入门

    本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正 NT驱动框架 <Windows 内核情景分析>.(毛德操) 前置知识 R3和R0 的由来 Intel ...

  6. 驱动保护:挂接SSDT内核钩子(1)

    SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用 ...

  7. X86驱动:挂接SSDT内核钩子

    SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用 ...

  8. 驱动通信:通过PIPE管道与内核层通信

    在本人前一篇博文<驱动开发:通过ReadFile与内核层通信>详细介绍了如何使用应用层ReadFile系列函数实现内核通信,本篇将继续延申这个知识点,介绍利用PIPE命名管道实现应用层与内 ...

  9. 驱动开发:内核层InlineHook挂钩函数

    在上一章<驱动开发:内核LDE64引擎计算汇编长度>中,LyShark教大家如何通过LDE64引擎实现计算反汇编指令长度,本章将在此基础之上实现内联函数挂钩,内核中的InlineHook函 ...

最新文章

  1. 研究生论文盲审、查重再加码!毕业或将变的更加困难...
  2. mysql for Mac 下创建数据表中文显示为?的解决方法
  3. python的哪个模块提供了文件处理方法_Python处理文件路径有哪些方法?
  4. 机器学习入门必备的13张“小抄”(附下载)
  5. mysql查询数据库报错sql_mode_MySQL数据库的sql_mode
  6. javascript encodeURI和encodeURIComponent的比较
  7. python交互模式中换行_在Python日志模式中禁止换行
  8. 计算机科学与技术的应用图,安徽农业大学计算机科学与技术视图及其应用.ppt...
  9. 词云 -python
  10. 如何使用PDF虚拟打印机打印文件
  11. 手把手教你做视频播放器(二)-获取视频信息
  12. win10 Kafka环境搭建 + 编译C++(librdkafka) 封装库
  13. C Prime plus 第七章练习题
  14. 文献翻译--《Siamese Regression Tracking With Reinforced Template Updating》--增强模板更新的孪生回归跟踪,IEEE-2021
  15. 世间安得双全法,不负如来不负卿。
  16. Oracle中coalesce函数的用法
  17. 小程序占服务器空间吗,小程序会占用手机存储空间吗?| 小程序问答 #21
  18. Linux系统文件夹作用粗略解析
  19. 04.05 Linux系统用户与用户组
  20. Javascript中的事件捕获、事件冒泡与事件委托

热门文章

  1. 诺基亚5800 XM实测
  2. 大数据基础环境搭建的从spark到hadoop,从底层硬件到上层软件的一些必备注意事项
  3. 去掉高德地图左下角的logo和文字
  4. windows socket编程五种模型
  5. RocketMq修改namesrv和broker默认端口
  6. 小熊派 移植TencentOS-tiny+EC20+MQTT对接腾讯云
  7. 微信业务域名两个解决方法
  8. day01【Object类、常用API】-笔记
  9. 【苹果相册推iMessage】群发执行日历推位置推 ionic platform add ios (增加ios平台)
  10. 北京pHp彭老师,记忆惊人的彭老师 - 交朋聚友 - 天涯比邻网 - Powered by Discuz!