Windows内核中的数据结构与函数调用

2023-10-27

2.3重要的数据结构
2.3.1驱动对象:
Windows内核认为许多东西都是“对象”,比如一个驱动、一个设备、一个文件,甚至其他的一些东西。(采用面对对象的编程方式,但是使用的是C语言)
一个驱动对象代表了一个驱动程序,或者说一个内核模块。
驱动对象的结构如下:
typdef struct _DRIVER_OBJECT {
     // 结构的类型和大小
     CSHORT Type;
     CSHORT Size;
     // 设备对象,这里实际上是一个设备对象的链表的开始。因为DeviceObject
     // 中有相关的链表信息。阅读下一小节“设备对象”会得到更多的信息
     PDEVICE_OBJECT DeviceObject;
     ...
     
     // 这个内核模块再内核空间中的开始地址和大小
     PVOID DriverStart;
     ULONG DriverSize;
     ...
     // 驱动的名字
     UNICODE_STRING DriverName;
     ...
     // 快速IO分发函数
     PFAST_IO_DISPATCH FastIoDispatch;
     ...
     // 驱动的卸载函数
     PDRIVER_UNLOAD DriverUnload;
     // 普通分发函数
     PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
⑴如果写一个驱动程序(或者说内核模块),要在Windows中加载,则必须填写这样一个结构,来告诉Windows 程序提供哪些功能。
⑵编写应用程序时,Windows直接从main()函数开始执行来生成一个进程。 内核模块并不生成一个进程,而是填写一组回调函数让Windows来调用,而且这组回调函数必须符合Windows内核规定。
⑶这组 回调函数包括上面的“普通分发函数”和“快速IO分发函数”。这些函数用来处理发送给这个内核模块的请求。一个内核模块所有的功能都由它们提供给Windows。
⑷如果编写内核程序,能找到这些关键的驱动对象结构(比如NTFS文件系统),然后改写下面的分发函数,替换成我们自己的函数,可能就可以捕获Windows的文件操作,让我们的内核程序处理完毕后,再交给NTFS文件系统处理。这样就可以加入我们自己的功能(比如扫描病毒,文件加密等)。这就是所谓的 分发函数Hook技术,本书后面会有所描述。
2.3.2设备对象:
important: 在内核世界里,大部分“消息”都以请求(IRP)的方式传递。而设备对象(DEVICE_OBJECT)是唯一可以接受请求的实体,任何一个“请求”(IRP)都是发送给某个设备对象的。
设备对象的结构是DEVICE_OBJECT,简称DO。
因为我们总是在内核程序中生成一个DO,而一个内核程序是用一个驱动对象表示的,所以一个设备对象总是属于一个驱动对象。
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)
_DEVICE_OBJECT {
     
      // 结构的类型和大小
     CSHORT Type;
     USHORT Size;
      // 引用计数
     ULONG ReferenceCount;
      // 这个设备所属的驱动对象
     struct _DRIVER_OBJECT* DriverObject;
      // 下一个设备对象。在一个驱动对象中有n个设备,
     // 这些设备用这个指针连接 起来作为一个单向的链表。
     struct _DEVICE_OBJECT* NextDevice;
      // 设备类型
     DEVICE_TYPE DeviceType;     
     
      // IRP栈大小
     HAR StackSize;
     ...
} DEVICE_OBJECT;
驱动对象生成多个设备对象。 当Windows向设备对象发送请求时,这些请求被驱动对象的分发函数所捕获。当Windows内核向一个设备发送一个请求时,驱动对象的分发函数中的某一个会被调用。分发函数原型如下:
// 一个典型的分发函数,第一个参数device是请求的目标设备
// 第二个参数irp是请求的指针
NTSTATUS MyDispatch(PDEVICE_OBJECT device, PIRP irp);
2.3.3请求:
⑴何为请求?举一个浅显的例子:如果要求网卡发送一个数据包,或者向网卡请求把已经存在缓冲区里接收到的包读出来,这就是一个请求;如果读取一个文件从0开始的512个字节,这也是一个请求;如果在磁盘的64MB位置写入长达512字节的一组数据,这还是一个请求。
⑵应用程序的开发者是看不到这些请求的,只需调用API即可。但是这些操作最终在内核中会被IO管理器翻译成请求(IRP或者与之等效的其他形式,比如快速IO调用)发送往某个设备对象。
大部分请求以IRP的形式发送。IRP也是一个内核数据结构,非常复杂,因为这个结构要表示无数种实际请求的缘故。在WDK的wdm.h中能找到IRP的结构如下:
typedef struct _IRP {
  // 类型和大小
  CSHORT Type;
  USHORT Size;
  // 内存描述符链表指针。实际上,这里用来描述一个缓冲区。可以想象
  // 一个内核请求一般都需要一个缓冲区(如读硬盘需要有读出缓冲区)
  PMDL   MdlAddress;
  ...
  // 下面这个共用体中也有一个SystemBuffer。这是比MdlAddress稍微简单
  // 的表示缓冲区的一种方式。IRP用MdlAddress还是用SystemBuffer取决于
  // 这次请求的IO方式。总之二者都有可能。
  union {
    struct _IRP  * MasterIrp;
    __volatile LONG IrpCount;
    PVOID   SystemBuffer;
  }  AssociatedIrp;
  .
  // IO状态,一般请求完成之后的返回情况放在这里
  IO_STATUS_BLOCK   IoStatus;
  // IRP栈空间大小
  CHAR StackCount;
  // IRP当前栈空间
  CHAR CurrentLocation;
  ...
  // 用来取消一个未决请求的函数
  PDRIVER_CANCEL   CancelRoutine;
  // 与MdlAddress和SystemBuffer一样都可以表示缓冲区,
  // 但是缓冲区的特性稍有不同。以后再详细解释
  PVOID UserBuffer;
  union {
    struct {
    .
    .
    union {
      KDEVICE_QUEUE_ENTRY  DeviceQueueEntry;
      struct {
        PVOID   DriverContext[4];
      };
    };
    .
    // 发出这个请求的线程
    PETHREAD   Thread;
    .
    .
    LIST_ENTRY   ListEntry;
    .
    .
    }  Overlay;
  .
  .
  }  Tail;
} IRP, *PIRP;
⑷这里值得注意的是 IRP栈空间因为一个IRP往往需要传递n个设备才得以完成(第三章有描述)。可以想象,在传递过程中,有可能又些“中间变换”,导致请求的参数变化。为了保存这种参数变化,我们给每次“中转”都留一个“栈空间”,用来保存中间参数。所以一个请求并非简单的一个输入,并等待一个输出,而是经过许多中转才得以完成。而且在中转的每个步骤,输入都可以改变,所以可变部分的输入信息保存在一个栈似的结构中。每中转一次,都使用其中一个位置。域CurrentLocation表示当前使用了哪一个。
⑸本书后面内容所使用的词语“请求”如不特殊说明,就是指IRP。衍生说法如下:
生成请求:主功能号为 IRP_MJ_CREATE 的 IRP
查询请求:主功能号为 IRP_MJ_QUERY_INFORMATION 的 IRP
设置请求:主功能号为 IRP_MJ_SET_INFORMATION 的 IRP
控制请求:主功能号为 IRP_MJ_DEVICE_CONTROL,或者是仅仅在本书的第10章TDI过滤中出现的 IRP_MJ_INTERAL_DEVICE_CONTROL 的 IRP
关闭请求:主功能号为 IRP_MJ_CLOSE 的 IRP
请求指针:IRP 的指针。类型写作 PIRP 或者 IRP*。
2.4函数调用
2.4.1查阅帮助:
查阅WDK Documentation
2.4.2帮助中有的几类函数:
⑴大部分内核API都有前缀,主要的函数以Io-,Ex-,Rtl-,Ke-,Zw-,Nt-和Ps-开头。此外,与NDIS网络驱动开发的相关函数几乎都是以Ndis-开头的,与开发WDF驱动相关的函数都是以Wdf-开头的。
⑵部分函数相关介绍:看课本P30
有分配内存、获取互斥体
文件操作、注册表操作
字符串操作、获取当前Windows版本
IO管理器操作、IRP操作
进程线程操作
2.4.3帮助中没有的函数:
⑴并不是所有可以调用的函数都在帮助里。比如C运行时库中的 stdlib.h  stdio.h 和 memory.h 三个头文件里有很多函数可以使用。也并非全部,比如printf,scanf,fopen,fclose,fwrite,fread就不行,因为内核里没有控制台,而且读/写文件也不是那么轻松。但是,如spirntf,strlen,strcpy,wcslen,wcscpy,memcpy,memset都是可以的,相应的malloc,free,strdup是不行的。
⑵基本上可以认为,C运行时库中的函数,如果 只涉及字符串和内存数据(不涉及内存管理,比如内存的分配和释放),则是可以在内核程序里调用的。但是MS 不提倡这样做
⑶如果函数涉及内存管理,文件操作,网络操作,线程等。则往往头文件中有这个函数存在,甚至编译可以通过,但是连接的时候会出问题。
2.5 Windows的驱动开发模型
⑴“模型”源于单词“Mode”
⑵在Windows NT上,驱动程序被称为 Kernel Driver Mode 驱动程序。
⑶在Windows 9x上的驱动程序,都叫做VXD。
⑷Windows 98~2000这个时期出现的新模型叫做WDM。
⑸Windows的驱动模型概念,本来是就驱动程序的行为而言的。比如 WDM驱动,必须要满足n种被要求的特性(如电源管理、即插即用)才被称为WDM驱动。如果不提供这些功能,那么统一称为NT式驱动。
⑹本书采用简单的区分方法。将一切在Windows 2000 ~ Windows Vista下能正常运动且未调用WDF相关的内核API函数的驱动都称为传统型驱动(包括NT式和WDM)。如果调用了WDF相关的内核API则称为 WDF驱动
WDF驱动是可以调用传统型驱动所调用的内核API的,WDF可以视为传统型的升级版。
WDF与其说是新的驱动开发模型,还不如说是在已有的内核API和数据结构的基础上,又封装出一套让使用者觉得更简单、更易用的 Wdf- 开头的一组API。从KDM到WDM再到WDF是一脉相承的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Windows内核中的数据结构与函数调用 的相关文章

  • 在 WSL Ubuntu 20.04 上安装 npm 后,我收到消息“/usr/bin/env: ‘bash\r’: No such file or directory”

    运行时我看到以下消息npm install or npm来自终端的命令 执行中node按预期工作 gt npm install usr bin env bash r No such file or directory 2023 年 7 月更
  • Windows平台下C语言控制串口DTR和RTS引脚

    如何在windows平台上控制串口的DTR和RTS引脚 我希望通过升高或降低电压来对其进行位敲击或操作 您需要使用EscapeComm 函数 https learn microsoft com en us windows desktop a
  • 使用 Windows 命令行连接文本文件,删除前导行

    我需要连接一些相对较大的文本文件 并且更喜欢通过命令行来完成此操作 不幸的是我只有Windows 无法安装新软件 type file1 txt file2 txt gt out txt 允许我几乎得到我想要的 但我不希望 file2 txt
  • windows关闭tomcat后保持端口锁定

    我遇到了一个问题 该问题发生在不同站点的 3 台不同服务器上 问题是 当我关闭 Windows 服务器上的 Tomcat 7 和 8 5 版本 服务并尝试重新启动该服务后 该服务将无法启动 因为 tomcat 认为端口仍在使用中 以下是错误
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • Boost + Visual Studio 2010 + Windows 平台 SDK 7.1

    有人可以告诉我 bjam 的命令行开关或其他可以使用新的 Windows Platform SDK 7 1 工具链使用 VS2010 进行 boost 编译的东西吗 您可以在普通的视觉工作室项目中设置该选项 默认值是 v100 是平台 7
  • 使用 BitmapEncoder 生成时如何使 GIF 循环重复

    我能够使用 BitmapEncoder C WinRT 创建动画 gif 但是 我一直无法弄清楚如何让GIF循环回来并从头开始 没有尝试太多 因为我不确定要尝试什么 搜索了更多要在 GIF 上设置的属性 但找不到任何相关内容 好吧 终于能弄
  • PostgreSql“运行安装后步骤...数据库集群初始化失败”

    我是一名 Windows 用户 我花了几个小时不断地安装和卸载 然后才使其正常工作 前 10 次左右才看到标题中的错误消息 我将其作为一个自我回答的问题放在这里 以防止其他人在安装时可能遇到同样的问题 并为像我这样第一次使用 Postgre
  • 哪个版本的 Miniconda 具有适用于 Windows 64 位的 Python 3.6?

    我正在开发一个需要这些深度学习库的项目 keras 和 tensorflow 不幸的是 这些不适用于 Python 3 7 有人可以告诉我一个带有 Python 3 6 的 Miniconda 版本 适用于 Windows 64 位 吗 我
  • MinGW Make 抛出“系统找不到指定的路径。”错误

    我正在尝试在 Windows 7 上使用 cmake 生成一个 c 项目 在实际创建项目之前 cmake 会对您的工具链进行快速测试 我正在使用 MinGW 这就是我的问题所在 Cmake 触发 make 构建 最终失败并返回 系统找不到指
  • 将文件夹中的所有文件及其所有子文件夹移动到一个大文件夹中 - windows xp

    我有一个文件夹 c downloads ffme 里面有很多子文件夹 每个子文件夹中都有不同数量的文件 我想将所有这些单独的文件合并到一个大文件夹中 同时将它们从子文件夹中删除 我希望最终得到一个包含大量文件的文件夹 但没有子文件夹 我怎样
  • 从 Python 下载/安装 Windows 更新

    我正在编写一个脚本来自动安装 Windows 更新 我可以将其部署在多台计算机上 这样我就不必担心手动更新它们 我想用 Python 编写这个 但找不到任何关于如何完成此操作的信息 我需要知道如何搜索更新 下载更新并从 python 脚本安
  • VB - 以隐式方式链接 DLL

    我正在开发 VB6 图形界面 并且需要隐式链接到 DLL 这样做的动机来自于我上一个问题 https stackoverflow com questions 5194573 有问题的 DLL 使用静态 TLS declspec thread
  • 如何在 Ubuntu VirtualBox 中运行 Meteor 应用程序并使用 Windows 主机上的编辑器进行编辑?

    我希望在运行 Ubuntu 的 virtualbox 来宾中运行一个用于开发目的的流星服务器 该项目将位于主机上的一个文件夹内 该文件夹将共享给来宾 该文件夹本身位于 Dropbox 文件夹内 这样我可以在多个虚拟机和工作站之间共享开发 但
  • 无法加载 JNI 共享库 (JDK)

    当我尝试打开时Eclipse http www eclipse org 弹出对话框指出 无法加载 JNI 共享库 C JDK bin client jvm dll 此后 Eclipse 强制关闭 我想提出以下几点 我检查了这条路径上是否存在
  • Windows批处理文件:将结构转换为单行字符串

    我需要将这个艰巨的任务作为批处理文件来完成 这对于 C 来说不是最困难的 但在 DOS 中是一个地狱 至少对我来说 我需要将结构转换为单个 var 字符串 才能在我的程序中再次将它们转换为该结构 别担心回归 一切都已经完成了 该结构的大小会
  • 如何使用Python在Django for Windows中激活虚拟环境?

    我被告知要在 Django for Windows 中激活虚拟环境 我应该尝试 environment path Scripts activate 但是当我输入该命令时 cmd 返回此错误 该系统找不到指定的路径 我通过输入以下命令创建了虚
  • 如何验证文件名称在 Windows 中是否有效?

    是否有一个 Windows API 函数可以将字符串值传递给该函数 该函数将返回一个指示文件名是否有效的值 我需要验证文件名是否有效 并且我正在寻找一种简单的方法来完成此操作 而无需重新发明轮子 我正在直接使用 C 但针对的是 Win32
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • Visual C++ 找不到“Windows 类型”,如 PVOID、DWORD、ULONG 等

    Windows 似乎无法找到任何这些类型 我完全不知道该怎么办 我在 MSDN 上找到的东西似乎表明它们是默认包含的 但它们在 Native 程序或 CLR 程序中不起作用 我收到的具体错误是

随机推荐

  • 吐血解决磁盘占用率100%

    吐血解决磁盘占用率100 问题简述 解决步骤 吐血解决 磁盘利用率高的建议 问题简述 一次偶然使用电脑后 发现每次开机后 磁盘长时间占用率达到100 带来的影响是打开浏览器 打开本地电脑磁盘特别卡 解决步骤 1 尝试了网络上提供的绝大部分方
  • 常用的范数求导

    矢量范数的偏导数 L1范数不可微 但是存在次梯度 即是次微分的 L1范数的次梯度如下 x x 1 sign x begin equation begin aligned frac partial partial mathbf x mathb
  • 【CV with Pytorch】第 8 章 :图像超分辨率

    随着高分辨率图像捕获代理的出现 图像中捕获的信息是巨大的 技术已经从超高清转向 4K 和 8K 分辨率 如今 电影正在使用高分辨率帧 但是 在某些情况下 他们需要将低分辨率图像增强为高分辨率图像 想象这样一个场景 电影的主角正试图确定从一张
  • 第一站:探索JavaWeb的神秘世界

    欢迎来到 JavaWeb的奇妙冒险 教学系列 在这里 我们将探索Web开发的奥秘 让你在学习的过程中不仅轻松愉快 还能掌握高质量的知识 JavaWeb的奇妙冒险 第一站 探索JavaWeb的神秘世界 1 什么是JavaWeb 2 为什么学习
  • 2022-03-03JAVA面试笔试题记录

    最近在学习JAVA技术基础 也尝试练习一些JAVA面试中的编程题来巩固相关的知识点 具体的问题和代码如下 问题1 package com interview demo 利用条件运算符的嵌套来完成此题 学习成绩 gt 90分的同学用A表示 6
  • 决策树(Decision Tree,DT)(ID3、C4.5、剪枝、CART)

    目录 1 算法简介 2 特征选择 3 生成决策树 ID3 C4 5 4 修剪决策树 5 CART算法 CART回归树的生成 CART分类树的生成 CART剪枝 1 算法简介 决策树模型是树形结构 既可以用于分类 也可以用于回归 一颗决策树由
  • Mysql数据库基础(四)—— 表的字段类型(Mysql数据类型)

    Mysql的数据类型是一种约束 为了确保数据插入和存储的一致性 一旦我们插入的数据不合法 比如插入与字段类型不符的数据 Mysql会直接终止 这一点上和C语言就有区别 C语言存在隐式类型转换 即便类型不一致 编译器也不会报错 除此之外 虽然
  • 语义分割模型LinkNet介绍

    语义分割模型LinkNet 模型提出的背景 网络结构 实验结果 结论 GitHub代码链接 LinkNet是2017年CVPR上的一篇论文 论文地址 https arxiv org abs 1707 03718 由于网上的论文笔记以及讲解不
  • 推荐收藏

    本文将对数据竞赛的 技巧 进行全面的总结 同时还会分享下个人对比赛方法论的思考 前者比较客观 总结了不同数据类型下涉及到的比赛技巧 后者稍微主观 是我个人对解决比赛思路的总结 2019年下半年对我触动很大的两个知识分享是 志峰现场讲解的 T
  • VLAN是什么,我们为什么需要它?

    VLAN是一组逻辑上的设备和用户 这些设备和用户并不受物理位置的限制 可以根据功能 部门及应用等因素将它们组织起来 相互之间的通信 任何典型的LAN环境都包括各种各样的设备和计算机系统 它们都有各自的用途 有些设备应用是特有的 语音 数据
  • ABAP 新语法记录(一)

    主要内容 内联声明 构造表达式 内表操作 Open SQL 其他 本文列出了ABAP新语法的一些使用方式 供大家学习参考 内联声明 代码实现 pre amp 主题一 内联声明 语法 DATA FILED SYMBOL 1 定义变量 2 定义
  • Ribbon负载均衡(二)Ribbon负载均衡策略

    Ribbon负载均衡策略 文章目录 Ribbon负载均衡策略 1 默认 轮询策略 1 1 修改User服务 使用Ribbon默认轮询策略 1 2 RestTemplate配置 1 3 RestTemplate访问Order订单服务 1 4
  • 数据库多表合为一表

    insert into total select from c1 注 total为总表 c1为单表之一 简单说就是 需要哪些表就把相应的表插入到一个总表里面 注意总表和单表的类型必须一样 select from c1 把表c1的数据全部查出
  • 微信小程序笔记

    空待整理
  • 2.5万字讲解DDD领域驱动设计,从理论到实践掌握DDD分层架构设计,赶紧收藏起来吧

    推荐好文 2 5万字详解23种设计模式 微服务springcloud环境下基于Netty搭建websocket集群实现服务器消息推送 netty是yyds 代码中如何干掉太多的if else即if else的多种替代方案以提高代码质量通过公
  • 工作流程引擎之flowable(集成springboot)

    0 背景 现状 公司各部门业务系统有各自的工作流引擎 也有cross function的业务在不同系统或OA系统流转 没有统一的去规划布局统一的BPM解决方案 近期由于一个项目引发朝着整合统一的BPM方案 特了解一下市面上比较主流的开源和收
  • 充分必要条件

    充分必要条件 p 是 q 的充分必要条件 等价于 q 的充分必要条件是 p 则 p 可 推出 q 证明了 充分性 q 可推出 p 证明了必要性
  • nvprof 性能评估主要指标

    nvprof 用于性能评估的三个主要指标 occupancy nvprof metrics achieved occupancy helloCuda out gld throughput nvprof metrics gld through
  • 数据分析|情绪字典 绘图 火星坐标转换 「某社交平台」内容情绪分析

    任务要求 情绪理解是文本处理里最常见任务之一 现提供一个五类情绪字典 由情绪词组成 5 个文件 人工标注 实现一个情绪分析工具 并利用该工具对10000条 某社交平台 内容进行测试和分析 一行一条 某社交平台 内容 字典数据见公开数据中的e
  • Windows内核中的数据结构与函数调用

    2 3重要的数据结构 2 3 1驱动对象 Windows内核认为许多东西都是 对象 比如一个驱动 一个设备 一个文件 甚至其他的一些东西 采用面对对象的编程方式 但是使用的是C语言 一个驱动对象代表了一个驱动程序 或者说一个内核模块 驱动对