当前位置: 首页 > news >正文

2.5 Windows驱动开发:DRIVER_OBJECT对象结构

在Windows内核中,每个设备驱动程序都需要一个DRIVER_OBJECT对象,该对象由系统创建并传递给驱动程序的DriverEntry函数。驱动程序使用此对象来注册与设备对象和其他系统对象的交互,并在操作系统需要与驱动程序进行交互时使用此对象。DRIVER_OBJECT对象还包含了与驱动程序所管理的设备对象相关联的设备扩展结构,以及用于处理I/O请求的函数指针等信息。它是驱动程序与操作系统内核之间的桥梁,用于协调设备的操作和管理。

本章将探索驱动程序开发的基础部分,了解驱动对象DRIVER_OBJECT结构体的定义,一般来说驱动程序DriverEntry入口处都会存在这样一个驱动对象,该对象内所包含的就是当前所加载驱动自身的一些详细参数,例如驱动大小,驱动标志,驱动名,驱动节等等,每一个驱动程序都会存在这样的一个结构,首先来看一下微软对其的定义;

typedef struct _DRIVER_OBJECT {CSHORT Type;                                // 驱动类型CSHORT Size;                                // 驱动大小PDEVICE_OBJECT DeviceObject;                // 驱动对象ULONG Flags;                                // 驱动的标志PVOID DriverStart;                          // 驱动的起始位置ULONG DriverSize;                           // 驱动的大小PVOID DriverSection;                        // 指向驱动程序映像的内存区对象PDRIVER_EXTENSION DriverExtension;          // 驱动的扩展空间UNICODE_STRING DriverName;                  // 驱动名字PUNICODE_STRING HardwareDatabase;PFAST_IO_DISPATCH FastIoDispatch;PDRIVER_INITIALIZE DriverInit;PDRIVER_STARTIO DriverStartIo;PDRIVER_UNLOAD DriverUnload;                 // 驱动对象的卸载地址PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;

那么如果我们想要遍历出当前自身驱动的一些基本信息,我们只需要在驱动的头部解析_DRIVER_OBJECT即可得到全部的数据,这段代码可以写成如下样子,其中的IRP_MJ_这一系列则是微软的调用号,不同的RIP代表着不同的涵义,但一般驱动也就会用到如下这几种调用号。

#include <ntifs.h>VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark \n");Driver->DriverUnload = UnDriver;DbgPrint("驱动名字 = %wZ \n", Driver->DriverName);DbgPrint("驱动起始地址 = %p | 大小 = %x | 结束地址 %p \n",Driver->DriverStart,Driver->DriverSize,(ULONG64)Driver->DriverStart + Driver->DriverSize);DbgPrint("卸载地址 = %p\n", Driver->DriverUnload);DbgPrint("IRP_MJ_READ地址 = %p\n", Driver->MajorFunction[IRP_MJ_READ]);DbgPrint("IRP_MJ_WRITE地址 = %p\n", Driver->MajorFunction[IRP_MJ_WRITE]);DbgPrint("IRP_MJ_CREATE地址 = %p\n", Driver->MajorFunction[IRP_MJ_CREATE]);DbgPrint("IRP_MJ_CLOSE地址 = %p\n", Driver->MajorFunction[IRP_MJ_CLOSE]);DbgPrint("IRP_MJ_DEVICE_CONTROL地址 = %p\n", Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL]);// 输出完整的调用号for (auto i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++){DbgPrint("IRP_MJ调用号 = %d | 函数地址 = %p \r\n", i, Driver->MajorFunction[i]);}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译这段程序,签名并运行,我们即可看到如下输出信息,此时当前自身驱动的详细参数都可以被输出;

当然运用_DRIVER_OBJECT对象中的DriverSection字段我们完全可以遍历输出当前系统下所有的驱动程序的具体信息,DriverSection结构指向了一个_LDR_DATA_TABLE_ENTRY结构,结构的微软定义如下;

typedef struct _LDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;LIST_ENTRY InMemoryOrderLinks;LIST_ENTRY InInitializationOrderLinks;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;union {LIST_ENTRY HashLinks;struct {PVOID SectionPointer;ULONG CheckSum;};};union {struct {ULONG TimeDateStamp;};struct {PVOID LoadedImports;};};
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

为了能够遍历出所有的系统驱动,我们需要得到pLdr结构,该结构可通过Driver->DriverSection的方式获取到,获取到之后通过pLdr->InLoadOrderLinks.Flink得到当前驱动的入口地址,而每一次调用pListEntry->Flink都将会指向下一个驱动对象,通过不断地循环CONTAINING_RECORD解析,即可输出当前系统内所有驱动的详细信息。这段程序的写法可以如下所示;

#include <ntifs.h>typedef struct _LDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;LIST_ENTRY InMemoryOrderLinks;LIST_ENTRY InInitializationOrderLinks;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;union {LIST_ENTRY HashLinks;struct {PVOID SectionPointer;ULONG CheckSum;};};union {struct {ULONG TimeDateStamp;};struct {PVOID LoadedImports;};};
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark \n");Driver->DriverUnload = UnDriver;PLDR_DATA_TABLE_ENTRY pLdr = NULL;PLIST_ENTRY pListEntry = NULL;PLIST_ENTRY pCurrentListEntry = NULL;PLDR_DATA_TABLE_ENTRY pCurrentModule = NULL;pLdr = (PLDR_DATA_TABLE_ENTRY)Driver->DriverSection;pListEntry = pLdr->InLoadOrderLinks.Flink;pCurrentListEntry = pListEntry->Flink;// 判断是否结束while (pCurrentListEntry != pListEntry){// 获取LDR_DATA_TABLE_ENTRY结构pCurrentModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);if (pCurrentModule->BaseDllName.Buffer != 0){DbgPrint("模块名 = %wZ | 模块基址 = %p | 模块入口 = %p | 模块时间戳 = %d \n",pCurrentModule->BaseDllName,pCurrentModule->DllBase,pCurrentModule->EntryPoint,pCurrentModule->TimeDateStamp);}pCurrentListEntry = pCurrentListEntry->Flink;}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译这段程序,签名并运行,我们即可看到如下输出信息,此时当前自身驱动的详细参数都可以被输出;

通过使用上一篇文章《内核字符串拷贝与比较》中所介绍的的RtlCompareUnicodeString函数,还可用于对比与过滤特定结果,以此来实现通过驱动名返回驱动基址的功能。

LONGLONG GetModuleBaseByName(PDRIVER_OBJECT pDriverObj, UNICODE_STRING ModuleName)
{PLDR_DATA_TABLE_ENTRY pLdr = NULL;PLIST_ENTRY pListEntry = NULL;PLIST_ENTRY pCurrentListEntry = NULL;PLDR_DATA_TABLE_ENTRY pCurrentModule = NULL;pLdr = (PLDR_DATA_TABLE_ENTRY)pDriverObj->DriverSection;pListEntry = pLdr->InLoadOrderLinks.Flink;pCurrentListEntry = pListEntry->Flink;while (pCurrentListEntry != pListEntry){// 获取LDR_DATA_TABLE_ENTRY结构pCurrentModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);if (pCurrentModule->BaseDllName.Buffer != 0){// 对比模块名if (RtlCompareUnicodeString(&pCurrentModule->BaseDllName, &ModuleName, TRUE) == 0){return (LONGLONG)pCurrentModule->DllBase;}}pCurrentListEntry = pCurrentListEntry->Flink;}return 0;
}

上这段代码的使用也非常简单,通过传入一个UNICODE_STRING类型的模块名,即可获取到模块基址并返回,至于如何初始化UNICODE_STRING则在《内核字符串转换方法》中有详细的介绍,此处你只需要这样来写。

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark \n");UNICODE_STRING unicode;// 获取WinDDK驱动基地址RtlUnicodeStringInit(&unicode, L"WinDDK.sys");LONGLONG winddk_address = GetModuleBaseByName(Driver, unicode);DbgPrint("WinDDK模块基址 = %p \n", winddk_address);// 获取ACPI驱动基地址RtlUnicodeStringInit(&unicode, L"ACPI.sys");LONGLONG acpi_address = GetModuleBaseByName(Driver, unicode);DbgPrint("ACPI模块基址 = %p \n", acpi_address);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

运行这段驱动程序,即可分别输出WinDDK.sys以及ACPI.sys两个驱动模块的基地址;

相关文章:

2.5 Windows驱动开发:DRIVER_OBJECT对象结构

在Windows内核中&#xff0c;每个设备驱动程序都需要一个DRIVER_OBJECT对象&#xff0c;该对象由系统创建并传递给驱动程序的DriverEntry函数。驱动程序使用此对象来注册与设备对象和其他系统对象的交互&#xff0c;并在操作系统需要与驱动程序进行交互时使用此对象。DRIVER_OB…...

[ubuntu]ubuntu上安装jdk1.8教程

首先需要去官方网站去下载对应jdk1.8版本&#xff1a; https://www.oracle.com/java/technologies/downloads/ 您也可以去csdn搜索我提供jdk安装包 这里以jdk-8u201-linux-x64.tar.gz为例子&#xff0c;首先下载安装后解压 tar -zxvf jdk-8u201-linux-x64.tar.gz 比如我解…...

金蝶云星空其他出库单保存提示序列号不一致

文章目录 金蝶云星空其他出库单保存提示序列号不一致保存报错初步分析总结 金蝶云星空其他出库单保存提示序列号不一致 保存报错 显示单据数量0.序列号数量3 初步分析 输入实发数量没有触发序列号数量的计算 检查实发数量的值更新事件 实发数量和序列号数量的转换&#xff…...

FBI:皇家勒索软件要求350名受害者支付2.75亿美元

导语 最近&#xff0c;FBI和CISA联合发布的一份通告中透露&#xff0c;自2022年9月以来&#xff0c;皇家勒索软件&#xff08;Royal ransomware&#xff09;已经入侵了全球至少350家组织的网络。这次更新的通告还指出&#xff0c;这个勒索软件团伙的赎金要求已经超过了2.75亿美…...

Layout工程师们--Allegro X AI实现pcb自动布局布线

Cadence 推出 Allegro X AI&#xff0c;旨在加速 PCB 设计流程&#xff0c;可将周转时间缩短 10 倍以上 楷登电子&#xff08;美国 Cadence 公司&#xff0c;NASDAQ&#xff1a;CDNS&#xff09;今日宣布推出 Cadence Allegro X AI technology&#xff0c;这是 Cadence 新一代…...

Hive入门--学习笔记

1&#xff0c;Apache Hive概述 定义&#xff1a; Hive是由Facebook开源用于解决海量结构化日志的数据统计&#xff0c;它是基于大数据生态圈Hadoop的一个数据仓库工具。 作用&#xff1a; Hive可以用于将结构化的数据文件【映射】为一张表&#xff0c;并提供类SQL查询功能。 H…...

【nlp】1文本预处理总括目录(附各章节链接)

文本预处理 1. 文本预处理机器作用2. 文本预处理包含的主要环节2.1 文本处理的基本方法2.1.1 分词2.1.2 词性标注2.2.3 命名实体标注2.2 文本张量表示方法2.2.1 one-hot编码2.2.2 Word2vec2.2.3 Word Embedding2.3 文本语料的数据分析2.3.1 标签数量分布2.3.2 句子长度分布2.3.…...

《增长黑客》思维导图

增长黑客这个词源于硅谷&#xff0c;简单说&#xff0c;这是一群以数据驱动营销、以迭代验证策略&#xff0c;通过技术手段实现爆发式增长的新型人才。 近年来&#xff0c;互联网公司意识到这一角色可以发挥四两拨千斤的作用&#xff0c;因此对该职位的需求也如井喷式增长。本…...

oracle-buffer cache

段&#xff0c;区&#xff0c;块。 每当新建一个表&#xff0c;数据库会相应创建一个段。然后给这个段分配一个区。 一个区包含多个块。 区是oracle给段分配空间的最小单位。 块是oracle i\o的最小单位。 原则上&#xff0c;一个块包含多行数据。 dbf文件会被划分成一个一个…...

数据可视化—D3(Data Driven Documents)

链接 教程链接安装教程官方github仓库 基础知识 D3是一个Javascript库&#xff0c;用于在浏览器中创建可视化和可交互的各种图表。通过以下代码的对比&#xff0c;说明D3的使用场景以及使用效果&#xff08;理论上&#xff0c;以下两段代码效果是一样的&#xff09;&#xf…...

±15kV ESD 保护、3V-5.5V 供电、真 RS-232 收发器MS2232/MS2232T

产品简述 MS2232/MS2232T 芯片是集成电荷泵&#xff0c;具有 15kV ESD 保护的 RS-232 收发器&#xff0c;包括两路接收器、两路发送器。 芯片满足 TIA/EIA-232 标准&#xff0c;为异步通信控制器和串口连 接器提供通信接口。 芯片采用 3V-5.5V 供电&#xff0c;电荷泵仅用…...

企业版远程软件推荐

在当今的数字时代&#xff0c;为您的企业配备远程访问功能至关重要。通过远程访问&#xff0c;您的团队可以在办公室外工作&#xff0c;并且无论身在何处都可以保持相同的生产力水平。在本文中&#xff0c;我们汇总了市场上的四大选择。 我们在远程访问解决方案中寻找什么 远…...

独孤思维:没学会走就要跑,你只能一辈子是穷b

很多人眼高手低&#xff0c;没学会走就要跟别人比赛跑步&#xff1b; 很多人想要发财&#xff0c;没赚到钱就要喊着跟谁比有钱。 眼高手低&#xff0c;自命不凡&#xff0c;愚蠢至极。 上周团队要扩编&#xff0c;招一个运营。 来了一个00后女孩应聘。 上来就说自己目标三…...

鸿蒙LiteOs读源码教程+向LiteOS中添加一个系统调用

本文分为2个部分&#xff1a;第1部分简要介绍如何读鸿蒙Liteos源码&#xff0c;第2部分是实验向LiteOS中添加一个系统调用的完整过程。 前置资料&#xff1a; imx6ull开发板使用方式详解 源码下载 编译运行简单程序 Ubuntu虚拟机使用鸿蒙LiteOs操作系统常见错误汇总 一、鸿…...

美国站群服务器IP如何设置分配?

​  在配置美国站群服务器时&#xff0c;IP的分配是一个重要的步骤。下面将介绍一些关于美国站群服务器IP分配的相关知识。 独享IP和虚拟IP 在租用美国站群服务器之前&#xff0c;我们需要了解提供的IP是独享的还是虚拟的。独享IP指每个网站都有独立的IP地址&#xff0c;而虚…...

R语言——taxize(第二部分)

taxize&#xff08;第二部分&#xff09; 3. taxize 文档中译3.10. classification&#xff08;根据类群ID检索分类阶元层级&#xff09;示例1&#xff1a;传递单个ID值示例2&#xff1a;传递多个ID值示例3&#xff1a;传递单个名称示例4&#xff1a;传递多个名称示例5&#xf…...

Postman+Newman+Jenkins实现接口测试持续集成

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 1.新建一个项目 2.设置自定义工作空间 3.执行windows的批处理命令 4.执行系统的Groovy脚本 5.生成的HTML的报告集成到Jenkin…...

C#WPF中的实现读取和写入文件的几种方式

说明&#xff1a;C#中实现读取和写入的类根据需要来选择。 1、File类 File类是用于操作文件的工具类&#xff0c;提供了对文件进行创建、复制、删除、移动和打开单一文件的静态方法。但需要注意的是&#xff0c;WPF中使用File的类&#xff0c;需要先引用System.IO下的命名空间。…...

如何利用自动发现将现网的进程纳入到监控系统中?

进程监控是一项关键任务&#xff0c;旨在监测系统中运行的进程的性能和状态。通过有效的进程监控&#xff0c;可以实时了解进程的运行情况&#xff0c;及时发现问题并采取措施&#xff0c;确保系统的稳定性和性能。 本期EasyOps产品使用最佳实践&#xff0c;我们将为您揭晓&am…...

英语学习(过去篇)

一、询问别人一周的情况 1.日常活动词汇 1&#xff09;I watched TV 我看了电视 2&#xff09;I ate breakfast 我吃了早餐 3&#xff09;I left the house 我离开了家 4&#xff09;I did the dishes 我洗了碗 5&#xff09;I washed my clothes …...

excel中通过ROW函数返回引用的行号

例如&#xff0c;想引用B3的行号&#xff08;行号应该是3&#xff09;&#xff1a; 鼠标点在想输入函数的单元格&#xff1a; 插入-》函数&#xff1a; 选择ROW函数&#xff1a; 点击“继续”&#xff0c;然后点击红框圈出来的按钮&#xff1a; 鼠标点击B3单元格&…...

spring学习笔记-IOC,AOP,事务管理

目录 概述 什么是spring 侵入式的概念 spring的核心 spring的优势 注意 IOC控制反转 概述 核心 容器 DI&#xff0c;dependency injection依赖注入 概念 注入方式 循环依赖 spring如何解决循环依赖 spring生成Bean的方式 Bean属性注入&#xff08;Bean属性赋值…...

MYSQL中的触发器TRIGGER

1.概念 触发器是一个特殊的存储过程&#xff0c;当触发器保护的数据发生变更时就会触发。 2.特性 1.触发器与表息息相关&#xff0c;一般我们一个表创建六个触发器。 2.六个触发器其实是三种类六个 insert 类型 before | after insertupdate 类型 before | af…...

用人话讲解深度学习中CUDA,cudatookit,cudnn和pytorch的关系

参考链接 本人学习使用&#xff0c;侵权删谢谢。用人话讲解深度学习中CUDA&#xff0c;cudatookit&#xff0c;cudnn和pytorch的关系 CUDA CUDA是显卡厂商NVIDIA推出的运算平台。 CUDA™是一种由NVIDIA推出的通用并行计算架构&#xff0c;是一种并行计算平台和编程模型&…...

【JavaEE】Servlet API 详解(HttpServletRequest类)

一、HttpServletRequest Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成 HttpServletRequest 对象&#xff08;内容和HTTP请求报文一样&#xff09; 1.1 HttpServletRequest核心方法 1.2 方法演示 WebServlet("/showRequest&…...

HTML页面的全屏显示及退出全屏案例

进入全屏 requestFullscreen 接收一个参数 options(可选), options 是一个对象, 但是只有一个字段 navigationUI, 用于控制是否在元素处于全屏模式时显示导航条. 可选值为 auto, hide, show, 默认值为 auto&#xff1b;当元素不在文档内时, 调用requestFullScreen回失败。 退出…...

layui弹出层点回车键无限弹出解决

$(document).keydown(function (event) {if (event.keyCode 13) {$("*").blur();//去掉焦点if ($(".layui-layer-btn0").length > 0)layer.closeAll();}});...

抖音测试付费短视频:从短剧领域拓展到知识、娱乐全品类

11月16日&#xff0c;抖音开始测试短视频内容付费&#xff0c;即用户在观看创作者的内容时&#xff0c;部分内容需要付费解锁才能全部观看&#xff0c;涉及范围不仅包括此前已经进行付费试水的短剧领域&#xff0c;还拓展至知识、娱乐等几乎全品类内容&#xff0c;用户可按单条…...

代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结

代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结 文章链接&#xff1a;两个字符串的删除操作、编辑距离、编辑距离总结 视频链接&#xff1a;两个字符串的删除操作、编辑距离 1. LeetCode 583. 两个字符串的删除操作 1.1 思…...

Excel vlookup 如何使用

Excel vlookup 如何使用 打开WX, 搜索 “程序员奇点” Excel vlookup可以说是利器&#xff0c;非常好用的工具&#xff0c;用来查询 Excel 或者进行数据匹配&#xff0c;十分方便。 VLookuP 如何使用&#xff0c;不常用的同学经常容易忘记&#xff0c;这次做个记录&#xff…...