Windows内核-7-(IRP)I/O请求包

IRP(I/O Request Packet)就是一个进行I/O操作的请求包。

IRP是一个结构体,谁分配谁就得释放,通常由执行体里的管理器,获取内核驱动程序来分配。

IRP不是单独的,只要创建了IRP就会跟着创建IRP的I/O栈,有一个栈是给内核驱动用的:

驱动需要调用IoGetCurrentIrpStackLocation函数来获取内驱驱动对应的I/O栈。

I/O传递

I/O系统是以设备对象为中心,而不是以驱动对象为中心的。IRP可以在设备对象中传来传去:

有点类似于计算机网络的体系结构。但是不可否认的是I/O可以在设备直接进行各种传递,所以通常用来作为读取文本数据。

具体的传递过程有点类似于栈。

IRP和I/O栈

这张图是对前面第一张图的细化。

分发例程(dispatch routine)

IRP最主要的一个作用就是拿来做分发例程,其实也就是分发的实例函数,就是对文件数据的传递。在我的理解里,就是对信息的分发,让大家一起用到数据。

所有的分发例程都有一个原型:

typedef NTSTATUS DRIVER_DISPATCH (
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp);

分发例程必须保存在驱动对象的MajorFunction里面,且需要对应和驱动的连接状态:

状态 描述
IRP_MJ_CREATE 获取文件句柄,对应User下的CreateFile
IRP_MJ_CLOSE 关闭文件句柄,对应User下的CloseHandle
IRP_MJ_READ 对应ReadFile
IRP_MJ_WRITE 对应WriteFile
IRP_MJ_DEVICE_CONTROL 对应DeviceIoControl,即可读又可写
IRP_MJ_INTERNAL_DEVICE_CONTROL 和IRP_MJ_DEVICE_CONTROL差不多,但是只有Kernel可用

完成请求

一旦决定要处理IRP(意味着不会把该IRP传递给下一个设备对象),就必须要完成它。

比如:

NTSTATUS MyDispatchRoutine(PDEVICE_OBJECT, PIRP Irp) {
//...
Irp->IoStatus.Status = STATUS_XXX;
Irp->IoStatus.Information = NumberOfBytesTransfered; // depends on request type
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_XXX;
}
//这里的IoCompleteRequest就是必须的

安全IRP操作

由于线程原因,很有可能一个去读一个去写,导致两个只有一个拿到了想要的数据。

还有页面内存的原因,修改的时候有可能一起修改了。

内核提供了两种比较安全的处理方式:

1 缓冲I/O

2 直接I/O

缓冲I/O

要使用缓冲I/O只需要在设备对象的Flag字段里面添加一个DO_BUFFERED_IO

DeviceObject->Flags |= DO_BUFFERED_IO

缓冲I/O的原理就是在系统内存中开辟一段缓冲区,作为一个中间人。

比如说要写,就先把内容写到系统内存缓冲区里,然后系统内存缓冲区再写入/读取到缓冲区里面。

直接I/O

直接缓冲采用物理内存映射来处理,将User和Kernel的缓冲区都指向物理内存里面,并且锁定在内存里,然后读写都采用它。这样的好处是减少了调用的开销。但是占了部分内存。

IRP_MJ_DEVICE_CONTROL 调度

前面的缓冲和直接I/O是读或写操作,这里的IRP_MJ_DEVICE_CONTROL操作是基于控制代码来选择读或写两个都可以的。

User态的IRP_MJ_DEVICE_CONTROL 和Kernel态的调用函数原型差不多:

BOOL DeviceIoControl(
HANDLE       hDevice,
DWORD       dwIoControlCode,
LPVOID       lpInBuffer,
DWORD       nInBufferSize,
LPVOID       lpOutBuffer,
DWORD       nOutBufferSize,
LPDWORD     lpBytesReturned,
LPOVERLAPPED lpOverlapped
);

dwIoControlCode:控制代码,由CTL_CODE宏的四个参数来处理。

Zero驱动程序

Client+Kernel的一个练手项目:

对于读请求,会将提供的缓冲区清零然后输出

对于写请求,会把缓冲区消耗掉

源代码zodiacon/windowskernelprogrammingbook: The Windows Kernel Programming book samples (github.com)

Windows内核-7-(IRP)I/O请求包的更多相关文章

  1. 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求

    1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置. 2)DRIVER_OBJECT下的派遣函数(分发函 ...

  2. Windows环境中,通过Charles工具,抓取安卓手机、苹果手机中APP应用的http、https请求包信息

    Windows环境中,通过Charles工具,抓取安卓手机.苹果手机中APP应用的http.https请求包信息1.抓取安卓手机中APP应用的http请求包信息1)在电脑上操作,查看Windows机器 ...

  3. windows内核驱动内存管理之Lookaside使用

    Windows内存管理中使用了类似于容器的东西,叫做Lookaside对象,每次程序员申请内存都会从Lookaside里面申请,只有不足的时候,Lookaside才会向内存又一次申请内存空间,这样减少 ...

  4. [14]Windows内核情景分析 --- 文件系统

    文件系统 一台机器上可以安装很多物理介质来存放资料(如磁盘.光盘.软盘.U盘等).各种物理介质千差万别,都配备有各自的驱动程序,为了统一地访问这些物理介质,windows设计了文件系统机制.应用程序要 ...

  5. Windows内核原理-同步IO与异步IO

    目录 Windows内核原理-同步IO与异步IO 背景 目的 I/O 同步I/O 异步I/O I/O完成通知 总结 参考文档 Windows内核原理-同步IO与异步IO 背景 在前段时间检查异常连接导 ...

  6. Windows驱动开发-IRP结构体

    IRP的全名是I/O Request Package,即输入输出请求包,它是Windows内核中的一种非常重要的数据结构. 上层应用程序与底层驱动程序通信时,应用程序会发出I/O请求,操作系统将相应的 ...

  7. Windows内核-7-IRP和派遣函数

    Windows内核-7-IRP和派遣函数 IRP以及派遣函数是Windows中非常重要的概念.IRP 是I/O Request Pocket的简称,意思是I/O操作的请求包,Windows中所有Use ...

  8. 【windwos 操作系统】关键的Windows内核数据结构一览(下)

    I/O管理器 nt!_IRP IRP表示一个I/O请求包结构体,它用来封装执行一个特定I/O操作所需要的所有参数以及I/O操作的状态.IRP的表现也类似于一个线程独立调用栈因此它可以从一个线程传递到另 ...

  9. Windows内核 WDM驱动程序的基本结构和实例

    WDM驱动的基本结构: WDM驱动模型是建立在NT式驱动程序模型基础之上的.对于WDM驱动程序来说,一般都是基于分层的,即完成一个设备的操作,至少要由两个驱动设备共同完成. 1)物理设备对象和功能设备 ...

随机推荐

  1. linux中的vim用法

    p.p1 { margin: 0; font: 16px ".PingFang SC"; color: rgba(53, 53, 53, 1) } p.p2 { margin: 0 ...

  2. Linux 3.16 release 贡献度

    内核 3.16 release 的贡献度可以在下面网页看到: http://www.remword.com/kps_result/3.16_whole.html 一共发布了 12802 个补丁, 18 ...

  3. 一款不错的 Go Server/API boilerplate,使用 K8S+DDD+CQRS+ES+gRPC 最佳实践构建

    Golang API Starter Kit 该项目的主要目的是使用最佳实践.DDD.CQRS.ES.gRPC 提供样板项目设置. 为开发和生产环境提供 kubernetes 配置.允许与反映生产的 ...

  4. C编译器

    GCC:GNU Compiler Collection,即 GNU 编译器套件.TDM-GCC 4.8.1 32-BIT Release: 查看GCC的版本:C:\Program Files\Dev- ...

  5. Java基础00-多线程28

    1. 实现多线程 1.1 进程 1.2 线程 1.3 多线程的实现方式(方式一:继承Thread类) 代码示例:定义类MyThread: //1:定义一个类MyThread继承Thread类 publ ...

  6. java 实现中英文拼写检查和错误纠正?可我只会写 CRUD 啊!

    简单的需求 临近下班,小明忙完了今天的任务,正准备下班回家. 一条消息闪烁了起来. "最近发现公众号的拼写检查功能不错,帮助用户发现错别字,体验不错.给我们系统也做一个." 看着这 ...

  7. Mac OS系统安装pymssql 报错

    Mac OS系统安装pymssql 一开始报错:缺少Cython,于是pip install Cython 然后还是报错:解决办法如下操作: 首先安装freetds 在 FreeTDS stable ...

  8. eladmin-plus V2.0.0 发布,单表链式调用更丝滑

    一.项目简介 eladmin的mybatis-plus版本,单表使用链式调用,代码更简洁,调用更便捷.目前更新到2021年7月.项目基于 Spring Boot 2.4.2 . Mybatis-plu ...

  9. Python - 基础数据类型 set 集合

    集合的简介 集合是一个无序.不重复的序列 它的基本用法包括成员检测和消除重复元素 集合对象也支持像 联合,交集,差集,对称差分等数学运算 集合中所有的元素放在 {} 中间,并用逗号分开 集合的栗子 这 ...

  10. Node.js躬行记(7)——定时任务的进化史

    一.纯手工 公司主营的是直播业务,会很许多打榜活动,也就是按主播收到的礼物或收益进行排序,排在前面的会有相应奖励. 纯手工时代,每接到一个活动,就重新写一份,第一次写完.之后就是复制黏贴,再修改,每次 ...