讲师中心 微信公众号

工具推荐

视频效率加速
Laper
Laper

剧本策划到成片协作

Seko
Seko

AI短剧一键生成成片

剧云
剧云

中文短剧剧本制作平台

立刻MV
立刻MV

低成本歌曲 MV、视频生成

3.3 Windows驱动开发:内核MDL读写进程内存

小强君_9091

小强君_9091

发布时间:2025-06-27 08:14:18

|

716人浏览过

|

来源于php中文网

原创

mdl内存读写是通过创建mdl结构体实现跨进程内存读写的一种方法。在windows操作系统中,每个进程拥有独立的虚拟地址空间,不同进程的内存空间是隔离的。因此,要在一个进程中读取或写入另一个进程的内存数据,首先需要将目标进程的物理内存映射到当前进程的虚拟地址空间中,然后才能进行内存读写操作。

MDL结构体是Windows内核中专门用于描述物理内存的数据结构,包含了物理地址、长度、内存映射的虚拟地址等信息。通过创建MDL结构体并调用系统函数将其映射到当前进程的虚拟地址空间中,可以实现跨进程内存读写操作。

与CR3切换方式相比,MDL内存读写更稳定、安全,且不受寄存器影响。同时,MDL内存读写方式还能充分利用Windows操作系统的内存管理机制,实现更高效的内存读写操作。因此,MDL内存读写是Windows操作系统中最常用和推荐的跨进程内存读写方式。

3.1.1 MDL读取内存步骤

  1. 调用PsLookupProcessByProcessId获取进程Process结构:该函数根据进程ID查找对应的进程对象,通过data->pid获取进程ID,然后调用PsLookupProcessByProcessId获取PEPROCESS结构。如果获取失败,则返回FALSE。
  2. 调用KeStackAttachProcess附加到目标进程:在内核模式下,读取其他进程的内存需要先附加到对应进程的上下文中。调用KeStackAttachProcess函数将当前线程切换到目标进程的上下文,同时保存当前进程的上下文状态。
  3. 调用ProbeForRead检查内存是否可读写:在内核模式下,访问其他进程的内存需要保证访问合法,因此调用ProbeForRead函数检查读取的内存空间是否可读写。如果不可读写,则会触发异常,通过异常处理机制处理这种情况。
  4. 将内存空间中的数据拷贝到自己的缓冲区:完成内存空间检查后,使用RtlCopyMemory函数将目标进程的内存数据拷贝到自己的缓冲区中。由于内存空间可能很大,可能需要多次拷贝操作。
  5. 调用KeUnstackDetachProcess解除绑定:读取完内存数据后,需要将当前线程从目标进程的上下文中解除绑定,返回到原来的上下文中。调用KeUnstackDetachProcess函数完成解绑操作,同时恢复之前保存的当前进程的上下文状态。
  6. 调用ObDereferenceObject减少对象引用数:由于第一步中调用了PsLookupProcessByProcessId函数获取了对应进程的PEPROCESS结构,因此需要调用ObDereferenceObject函数将其引用计数减1,以便释放对该对象的引用。

通过上述步骤,我们可以封装MDLReadMemory()内存读函数,代码如下,该函数用于在Windows内核模式下读取指定进程的内存数据:

#include <ntifs.h>
#include <windef.h>
<p>typedef struct {
DWORD pid;                // 要读写的进程ID
DWORD64 address;          // 要读写的地址
DWORD size;               // 读写长度
BYTE* data;               // 要读写的数据
} ReadMemoryStruct;</p><p>// MDL读内存
BOOL MDLReadMemory(ReadMemoryStruct<em> data) {
BOOL bRet = TRUE;
PEPROCESS process = NULL;
PsLookupProcessByProcessId(data->pid, &process);
if (process == NULL) {
return FALSE;
}
BYTE</em> GetData;
<strong>try {
GetData = ExAllocatePool(PagedPool, data->size);
} </strong>except (1) {
return FALSE;
}
KAPC_STATE stack = { 0 };
KeStackAttachProcess(process, &stack);
<strong>try {
ProbeForRead(data->address, data->size, 1);
RtlCopyMemory(GetData, data->address, data->size);
} </strong>except (1) {
bRet = FALSE;
}
ObDereferenceObject(process);
KeUnstackDetachProcess(&stack);
RtlCopyMemory(data->data, GetData, data->size);
ExFreePool(GetData);
return bRet;
}</p><p>VOID UnDriver(PDRIVER_OBJECT driver) {
DbgPrint(("Uninstall Driver Is OK \n"));
}</p><p>NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) {
DbgPrint(("hello lyshark \n"));
ReadMemoryStruct ptr;
ptr.pid = 6672;
ptr.address = 0x402c00;
ptr.size = 100;
// 分配空间接收数据
ptr.data = ExAllocatePool(PagedPool, ptr.size);
// 读内存
MDLReadMemory(&ptr);
// 输出数据
for (size_t i = 0; i < ptr.size; i++) {
DbgPrint(("%02x ", ptr.data[i]));
}
DbgPrint(("\n"));
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

读取内存地址0x402c00效果如下所示:

Windows 开机自启并隐藏到系统托盘
Windows 开机自启并隐藏到系统托盘

让 Windows 桌面程序在开机时静默自启并隐藏到系统托盘。特别适用于 Flutter、Electron 等无视 VBS/ProcessStartInfo 窗口样式、难以隐藏的顽固应用。提供「VBS 启动器 + Python ctypes/Win32 API」的隐藏窗口方案,可稳定把窗口收进托盘且不闪控制台。

下载

3.3 Windows驱动开发:内核MDL读写进程内存

3.1.2 MDL写入内存步骤

  1. 调用PsLookupProcessByProcessId获取目标进程的进程结构:该函数根据传递的进程ID返回对应进程的PEPROCESS结构体,包含了进程的各种信息。
  2. 使用KeStackAttachProcess附加到目标进程的上下文环境:该函数将当前线程的上下文环境切换到目标进程的上下文环境,使得该线程可以访问和修改目标进程的内存。
  3. 调用ProbeForRead检查要写入的内存空间是否可读写:这个步骤是为了确保要写入的内存空间没有被保护或被其他进程占用,以避免对系统造成不良影响。
  4. 将目标进程的内存空间中的数据拷贝到当前进程的缓冲区:便于进行修改操作。
  5. 调用MmMapLockedPages锁定当前内存页面:该函数将返回一个指向系统虚拟地址的指针,该地址是由系统自动分配的。在写入完成后,需要使用MmUnmapLockedPages函数来释放锁定的内存页面。
  6. 使用RtlCopyMemory完成内存拷贝操作:将缓冲区中的数据写入到锁定的内存页面中。
  7. 调用IoFreeMdl释放MDL锁:MDL锁用于锁定MDL描述的内存页面,以便可以对其进行操作。
  8. 使用KeUnstackDetachProcess解除当前进程与目标进程之间的绑定:使得当前线程的上下文环境恢复到原始的状态。
  9. 调用ObDereferenceObject将MDL对象的引用计数减1:便于在不再需要该对象时释放它所占用的系统资源。

从上述分析来看,写入操作与读取操作基本类似,只是多了锁定页面和解锁操作。MDL写内存的完整实现代码如下所示:

#include <ntifs.h></p><h1>include <windef.h></h1><p>typedef struct {
DWORD pid;                // 要读写的进程ID
DWORD64 address;          // 要读写的地址
DWORD size;               // 读写长度
BYTE* data;               // 要读写的数据
} WriteMemoryStruct;</p><p>// MDL写内存
BOOL MDLWriteMemory(WriteMemoryStruct<em> data) {
BOOL bRet = TRUE;
PEPROCESS process = NULL;
PsLookupProcessByProcessId(data->pid, &process);
if (process == NULL) {
return FALSE;
}
BYTE</em> GetData;
<strong>try {
GetData = ExAllocatePool(PagedPool, data->size);
} </strong>except (1) {
return FALSE;
}
for (int i = 0; i < data->size; i++) {
GetData[i] = data->data[i];
}
KAPC_STATE stack = { 0 };
KeStackAttachProcess(process, &stack);
PMDL mdl = IoAllocateMdl(data->address, data->size, 0, 0, NULL);
if (mdl == NULL) {
return FALSE;
}
MmBuildMdlForNonPagedPool(mdl);
BYTE* ChangeData = NULL;
<strong>try {
ChangeData = MmMapLockedPages(mdl, KernelMode);
RtlCopyMemory(ChangeData, GetData, data->size);
} </strong>except (1) {
bRet = FALSE;
goto END;
}
END:
IoFreeMdl(mdl);
ExFreePool(GetData);
KeUnstackDetachProcess(&stack);
ObDereferenceObject(process);
return bRet;
}</p><p>VOID UnDriver(PDRIVER_OBJECT driver) {
DbgPrint(("Uninstall Driver Is OK \n"));
}</p><p>NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) {
DbgPrint(("hello lyshark \n"));
WriteMemoryStruct ptr;
ptr.pid = 6672;
ptr.address = 0x402c00;
ptr.size = 5;
// 需要写入的数据
ptr.data = ExAllocatePool(PagedPool, ptr.size);
// 循环设置
for (size_t i = 0; i < ptr.size; i++) {
ptr.data[i] = 0x90;
}
// 写内存
MDLWriteMemory(&ptr);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

写出效果如下:

3.3 Windows驱动开发:内核MDL读写进程内存

相关文章

驱动精灵
驱动精灵

驱动精灵基于驱动之家十余年的专业数据积累,驱动支持度高,已经为数亿用户解决了各种电脑驱动问题、系统故障,是目前有效的驱动软件,有需要的小伙伴快来保存下载体验吧!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

5454

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

5631

2025.07.04

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

399

2026.04.23

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2921

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

416

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

437

2026.01.06

C++ 数据结构与算法实现教程合集
C++ 数据结构与算法实现教程合集

以 C++ 为实现语言,系统讲解核心数据结构与算法,涵盖链表(单链表/双链表/环检测)、栈与队列(单调栈/优先队列)、二叉树(遍历/BST/AVL/红黑树)、哈希表(开地址法/链地址法)、图(邻接表/BFS/DFS/Dijkstra/拓扑排序)、常见排序算法(快排/归并/堆排/计数排序)的实现与复杂度分析,同时分享 LeetCode 刷题技巧、竞赛编程常用模板(二分/前缀和/滑动窗口/动态规划),帮助开发者夯实算法基础。

512

2026.05.09

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4878

2023.08.10

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

40

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

Buffalo框架快速入门指南
Buffalo框架快速入门指南

共0课时 | 0人学习

Conan 2 安装指南
Conan 2 安装指南

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn