windows内核研究(驱动开发-0环与3环的通信)

驱动开发


0环与3环的通信

设备对象

在之前开发窗口程序时,消息都是被封装成一个结构体(MSG),在内核开发时,消息被封装成另外一个结构体:IRP(I/O Request Package)

在窗口程序中,能够接收消息的只能是窗口对象,在内核中,能够接收IRP消息的只能是设备对象

创建设备对象

// 创建设备名称
UNICODE_STRING deviceName;
RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");/*
NTSTATUS IoCreateDevice([in]           PDRIVER_OBJECT  DriverObject,			// 驱动对象[in]           ULONG           DeviceExtensionSize,	// 指定要为设备对象的 设备扩展 分配的驱动程序确定字节数[in, optional] PUNICODE_STRING DeviceName,			// 设备名称[in]           DEVICE_TYPE     DeviceType,			// 设备类型[in]           ULONG           DeviceCharacteristics,	// 设备特征[in]           BOOLEAN         Exclusive,				// 指定设备对象是否表示 独占设备[out]          PDEVICE_OBJECT  *DeviceObject			// 指向接收指向新创建的 DEVICE_OBJECT 结构的指针的变量的指针
);
*/// 创建设备对象
NTSTATUS ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);

数据的交互方式

// 设置数据的交互方式
driverObject->Flags |= DO_BUFFERED_IO;
  • 缓存区方式读写(DO_BUFFERED_IO):操作系统将应用程序提供缓冲区的数据复制到内核模式下的地址中
  • 直接方式读写(DO_DIRECT_IO):操作系统会将用户模式下的缓冲区锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍,这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存(缺点就是要单独占用物理页面)
  • 其他方式读写(在调用IoCreateDevice创建设备后对drivceObjcet->Flags既不设置DO_BUFFERED_IO也不设置DO_DIRECT_IO此时就是其它方式):在使用其他方式读写设备时,派遣函数直接读写应用程序提供的缓冲地址。在驱动程序中,直接操作应用程序的缓冲区是很危险的,只有驱动程序与应用程序运行在相同线程上下文的情况下,才能使用这种方式

IRP的类型

当应用层通过CreateFile,ReadFile,WriteFile,CloseHandle等函数打开,从设备读取数据,向设备写入数据,关闭设备的时候,会使操作系统系统产出不同的IRP_CREATE,IPR_MJ_READ,IRP_MJ_WRITE等IRP

其它类型

IRP类型来源
IRP_MJ_DEVICE_CONTROLDeviceControl函数会产生些IRP
IRP_MJ_POWER在操作系统处理电源消息时,产生此IRP
IRP_MJ_SHUTDOWN关闭系统前会产生些IRP

IRP_MJ_DEVICE_CONTROL才是我们Ring3与驱动交互的常规方式

测试代码

3环应用程序代码

#include<iostream>
#include<windows.h>#define IN_BUFFER_MAXLENGIT			0x10			// 输入缓存最大长度
#define OUT_BUFFER_MAXLENGTH		0x10			// 输出缓存最大长度
// 参数说明:1,设备类型,2,操作码,3,以什么方式进行访问,4,访问权限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) 
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define SYMBOLICLINK_NAME "\\\\.\\MyTestDriver"HANDLE g_hDriver;BOOL open(const CHAR* pLinkName) {TCHAR szBuffer[10] = { 0 };g_hDriver = CreateFileA(pLinkName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);DWORD errorCode = GetLastError();swprintf(szBuffer,sizeof(szBuffer),L"%d:\n",errorCode);if (g_hDriver != INVALID_HANDLE_VALUE)return TRUE;else return FALSE;
}/*
BOOL DeviceIoControl([in]                HANDLE       hDevice,			设备句柄[in]                DWORD        dwIoControlCode,	控制代码[in, optional]      LPVOID       lpInBuffer,		向0环传递的缓冲区的地址[in]                DWORD        nInBufferSize,		缓冲区的大小[out, optional]     LPVOID       lpOutBuffer,		向3还传递的缓冲区的地址[in]                DWORD        nOutBufferSize,	缓冲区的大小[out, optional]     LPDWORD      lpBytesReturned,	实际返回的长度(字节数)[in, out, optional] LPOVERLAPPED lpOverlapped		
);
*/BOOL ioControl(DWORD dwIoCode,PVOID InBuffer,DWORD InBuffLen,PVOID OutBuff,DWORD OutBuffLen) { DWORD dw;DeviceIoControl(g_hDriver,dwIoCode,InBuffer,InBuffLen,OutBuff,OutBuffLen,&dw,NULL);return TRUE;
}int main() {DWORD dwInBuffer = 0x11112222;TCHAR szOutBuffer[OUT_BUFFER_MAXLENGTH] = { 0 };// 通过符号链接 打开设备if (open(SYMBOLICLINK_NAME)) {printf("open device success\n");}else {printf("open device failed\n");}ioControl(OPER2, &dwInBuffer, IN_BUFFER_MAXLENGIT, szOutBuffer, OUT_BUFFER_MAXLENGTH);CloseHandle(g_hDriver);system("pause");return 0;
} 

0环驱动程序

#include <ntddk.h>#define DEVICE_NAME L"\\Device\\MyDevice"
// Ring3用CreateDevice打开设备时用 \\\\.\\MyTestDriver
#define SYMBOLICLINK_NAME L"\\??\\MyTestDriver"#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)// IRP_MJ_CREATE 处理函数
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj,PIRP pIrp) {DbgPrint("设备创建了...");// 设置返回状态pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_CLOSE 处理函数
NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {DbgPrint("设备关闭了...");// 设置返回状态pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_DEVICE_CONTROL 处理函数
NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {NTSTATUS stauts = STATUS_INVALID_DEVICE_REQUEST;PIO_STACK_LOCATION pIrpStack;ULONG uIoControlCode;PVOID pIoBuffer;ULONG uInLength;ULONG uOutLength;ULONG uRead;ULONG uWrite;// 设置临时变量的值uRead = 0;uWrite = 0x12345678;//获取IRP数据pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//获取控制码uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 获取缓冲区地址(输入和输出的缓冲区都是一个)pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;// Ring3 发送数据的长度uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// Ring0 发送数据的长度uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;pIrp->IoStatus.Information = 0;switch (uIoControlCode) {case OPER1:{DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 1");// 设置返回状态pIrp->IoStatus.Information = 1;stauts = STATUS_SUCCESS;break;}case OPER2:{DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 接收字节数:%d\n", uInLength);DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 输出字节数:%d\n", uOutLength);// 读缓存memcpy(&uRead,pIoBuffer,4);DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 地址:%llx",uRead);// 写缓存memcpy(pIoBuffer,&uWrite,4);// 设置返回状态pIrp->IoStatus.Information = 2;stauts = STATUS_SUCCESS;break;}}// 设置返回状态pIrp->IoStatus.Status = stauts;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;}// 卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("驱动被卸载了\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING reg_path) {NTSTATUS ntIoCreate = 0;PDEVICE_OBJECT pDeviceObject = NULL;UNICODE_STRING deviceName;UNICODE_STRING symbolicLinkName;// 创建设备名称RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");// 创建设备对象ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);if (ntIoCreate != STATUS_SUCCESS) {DbgPrint("设备对象创建失败!\n");return ntIoCreate;}// 设置数据的交互方式driverObject->Flags |= DO_BUFFERED_IO;// 创建符号链接名称(给Ring3访问)// Ring3用CreateFile打开设备时用 \\\\.\\MyTestDriverRtlInitUnicodeString(&symbolicLinkName, L"\\??\\MyTestDriver");// 创建符号链接ntIoCreate = IoCreateSymbolicLink(&symbolicLinkName, &deviceName);if(ntIoCreate != STATUS_SUCCESS) {DbgPrint("符号链接创建失败!\n");	IoDeleteDevice(pDeviceObject);return ntIoCreate;}// 设置派遣函数和卸载函数driverObject->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;driverObject->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceControlProc;driverObject->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

演示效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/915680.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915680.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Core Web API 内存缓存(IMemoryCache)入门指南

在 Web API 开发中&#xff0c;频繁访问数据库或第三方服务可能会带来性能瓶颈。为了提升接口响应速度并减轻后端压力&#xff0c;使用缓存是非常有效的优化手段。本文将带你快速上手 ASP.NET Core 提供的内存缓存&#xff08;IMemoryCache&#xff09;&#xff0c;无需安装额外…

Axios Token 设置示例

以下是一个完整的 Axios Token 设置示例&#xff0c;涵盖全局配置、请求拦截器和单次请求设置三种方式&#xff1a;1. 基础配置&#xff08;推荐方案&#xff09;javascript复制代码import axios from axios;// 创建 Axios 实例 const apiClient axios.create({baseURL: https…

Excel数据合并工具:零门槛快速整理

软件介绍 在数据处理工作中&#xff0c;合并Excel同类数据是一项常见但繁琐的任务。今天为大家推荐一款专为简化此类操作设计的工具&#xff0c;它能快速完成工作表内多行同类数据的合并整理&#xff0c;大幅提升数据处理效率。 零门槛操作体验 相比Excel自带的数据透视…

深度学习 -- 梯度计算及上下文控制

深度学习 – 梯度计算及上下文控制 文章目录深度学习 -- 梯度计算及上下文控制一&#xff0c;自动微分1.1 基础概念1.2 计算梯度1.2.1 计算标量梯度1.2.2 计算向量梯度1.2.3 多标量梯度计算1.2.4 多向量梯度计算二&#xff0c;梯度上下文控制2.1 控制梯度计算2.2 累计梯度2.3 梯…

Redisson RLocalCachedMap 核心参数详解

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

【Unity3D实例-功能-移动】角色移动-通过WSAD(Rigidbody方式)

你是否曾梦想在虚拟世界中自由翱翔&#xff0c;像海豚一样在海洋自由穿梭&#xff0c;或者像宇航员一样在宇宙中尽情探索&#xff1f;今天&#xff0c;我们就来聊聊如何在Unity中使用Rigidbody来实现角色移动。 废话不多说&#xff0c;走&#xff0c;让我们马上来一探究竟&…

Vue接口平台学习十一——业务流测试

效果图及简单说明 与之前的用例列表相似布局&#xff0c;也分左右&#xff0c;左边用于显示测试流程的名称&#xff0c;右边用于显示流程相关信息。 左侧点击添加&#xff0c;直接增加一个新的业务流。 右侧是点击的业务流详情&#xff0c;展示名称&#xff0c;名称的编辑保存&…

碳化硅缺陷分类与原因

01一、碳化硅晶体材料中的缺陷到底是什么&#xff1f;碳化硅晶体材料中的缺陷是指在晶体生长、加工或使用过程中出现的不完美结构。这些缺陷可能表现为晶体内部的裂纹、表面的凹坑、原子排列的错误等。虽然缺陷看起来微不足道&#xff0c;但它们却可能对晶体的电学、热学和机械…

Jenkins 实现项目的构建和发布

作者&#xff1a;小凯 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01; 本文的宗旨在于通过简单干净实践的方式教会读者&#xff0c;如何在 Docker 中部署 Jenkins&#xff0c;并通过 Jenkins 完成对项目的打包构建并在 Docker 容器中部署。 Jenkins 的主要…

Django接口自动化平台实现(三)

3.2 后台 admin 添加数据 1&#xff09;注册模型类到 admin&#xff1a; 1 from django.contrib import admin2 from . import models3 4 5 class ProjectAdmin(admin.ModelAdmin):6 list_display ("id", "name", "proj_owner", "tes…

CentOS 7 配置环境变量常见的4种方式

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

k8s:手动创建PV,解决postgis数据库本地永久存储

1.离线环境CPU:Hygon C86 7285 32-core Processor 操作系统&#xff1a;麒麟操作系统 containerd&#xff1a;1.7.27 Kubernetes:1.26.12 KubeSphere:4.1.2 kubekey&#xff1a;3.1.10 Harbor:2.13.1 Postgis:17-3.52创建StorageClass2.1创建 apiVersion: storage.k8s.io/v1kin…

谷歌浏览器Chrome的多用户配置文件功能

谷歌浏览器Chrome的多用户配置文件功能允许在同一设备上创建多个独立账户,每个账户拥有完全隔离的浏览数据(如书签、历史记录、扩展、Cookies等),非常适合工作/生活账户分离、家庭共享或临时多账号登录场景。 如何使用Chrome的多用户配置文件功能? 一、创建与切换用户 1.…

傲软录屏 专业高清录屏软件 ApowerREC Pro 下载与保姆级安装教程!!

小编今天分享一款强大的电脑屏幕录像软件 傲软录屏 ApowerREC&#xff0c;能够帮助用户录制中电脑桌面屏幕上的所有内容&#xff0c;包括画面和声音&#xff0c;支持全屏录制、区域录制、画中画以及摄像头录制等多种视频录制模式&#xff0c;此外&#xff0c;还支持计划任务录制…

【计算机网络】MAC地址与IP地址:网络通信的双重身份标识

在计算机网络领域&#xff0c;MAC地址与IP地址是两个核心概念&#xff0c;它们共同构成了数据传输的基础。理解二者的区别与联系&#xff0c;对于网络配置、故障排查及安全管理至关重要。 一、基本概念 1. MAC地址&#xff08;物理地址&#xff09; 定义&#xff1a;固化在网络…

如何用keepAlive实现标签页缓存

什么是KeepAlive首先&#xff0c;要明确所说的是TCP的 KeepAlive 还是HTTP的 Keep-Alive。TCP的KeepAlive和HTTP的Keep-Alive是完全不同的概念&#xff0c;不能混为一谈。实际上HTTP的KeepAlive写法是Keep-Alive&#xff0c;跟TCP的KeepAlive写法上也有不同。TCP的KeepAliveTCP…

数据库隔离级别

隔离级别决定了事务之间的可见性规则&#xff0c;直接影响数据库的并发性能和数据一致性。SQL 标准定义了 4 种隔离级别&#xff0c;从低到高依次为&#xff1a;读未提交→读已提交→可重复读→串行化。隔离级别越高&#xff0c;对并发问题的解决能力越强&#xff0c;但对性能的…

基于Python flask的电影数据分析及可视化系统的设计与实现,可视化内容很丰富

摘要&#xff1a;基于Python的电影数据分析及可视化系统是一个应用于电影市场的数据分析平台&#xff0c;旨在为广大电影爱好者提供更准确、更详细、更实用的电影数据。数据分析部分主要是对来自猫眼电影网站上的数据进行清洗、分类处理、存储等步骤&#xff0c;数据可视化则是…

TCP通讯开发注意事项及常见问题解析

文章目录一、TCP协议特性与开发挑战二、粘包与拆包问题深度解析1. 成因原理2. 典型场景与实例验证3. 系统化解决方案接收方每次读取10字节2. 丢包检测与验证工具3. 工程化解决方案四、连接管理关键实践1. 超时机制设计2. TIME_WAIT状态优化3. 异常处理最佳实践五、高性能TCP开发…

2021 RoboCom 世界机器人开发者大赛-本科组(复赛)解题报告 | 珂学家

前言 题解 睿抗机器人开发者大赛CAIP-编程技能赛-历年真题 汇总 2021 RoboCom 世界机器人开发者大赛-本科组&#xff08;复赛&#xff09;解题报告 感觉这个T1特别有意思&#xff0c;非典型题&#xff0c;着重推演下结论。 T2是一道玄学题&#xff0c;但是涉及一些优化技巧…