c++怎么将程序的内存快照DUMP到本地磁盘_二进制直写技术【详解】

夏芳姑娘_2953

夏芳姑娘_2953

2026-03-23

141人浏览

原创

需用virtualqueryex遍历mem_commit且可读内存区,跳过mem_free/reserve,以baseaddress+size头写入二进制文件,避开aslr偏移、堆栈无效页及文本模式写入问题。

c++怎么将程序的内存快照dump到本地磁盘_二进制直写技术【详解】

用 WriteProcessMemory + CreateFile 直写内存到文件,但别直接调

Windows 下没法用一句 C++ 代码把整个进程内存“dump”出来——WriteProcessMemory 只能读其他进程(且需权限),而你自己的进程要 dump 自身,得靠 VirtualQueryEx 遍历内存区域 + ReadProcessMemory(对自己 PID 调用也合法)+ CreateFile/WriteFile 直写二进制。关键不是“能不能”,而是“哪些区域值得写、哪些会失败、哪些写了也没用”。

常见错误现象:ReadProcessMemory 返回 FALSE,GetLastError() 是 ERROR_PARTIAL_COPY 或 ERROR_ACCESS_DENIED;生成的文件里大片 0x00 或乱码;加载回调试器时找不到模块基址。

  • 必须跳过 MEM_FREE 和 MEM_RESERVE 区域——它们没物理页,读必然失败
  • MEM_COMMIT 且 PAGE_READABLE(如 PAGE_READONLY、PAGE_READWRITE、PAGE_EXECUTE_READ 等)才真正可读
  • 绕开 ASLR 基址偏移:dump 文件里要记录每个区块的 BaseAddress 和 RegionSize,否则还原时无法映射
  • 别读 Heap 或 Stack 的未使用部分——VirtualQueryEx 会告诉你 State == MEM_COMMIT,但实际内容可能是野指针或已释放内存,写进去反而干扰分析

手动遍历内存区用 VirtualQueryEx,不是 EnumProcessModules

EnumProcessModules 只给你模块(DLL/EXE)加载基址和大小,但 dump 需要所有可读内存页,包括堆、线程栈、内存映射文件、私有数据段等。必须用 VirtualQueryEx 从 0x10000 开始逐块查(Windows 用户空间从 0x10000 起,避开 NULL 页),直到返回 0。

使用场景:你想做轻量级 crash 后现场保存,不依赖 dbghelp 或 minidump 机制,也不引入 pdb 依赖。

  • 起始地址别用 NULL——VirtualQueryEx 对 0x0 返回无效信息,从 0x10000 安全
  • 每次调用后,把 MEMORY_BASIC_INFORMATION::BaseAddress + RegionSize 当作下一轮 lpAddress,别自增字节——页边界不对齐会导致重复或遗漏
  • AllocationBase 字段可用来合并连续同属性区块(比如多个 MEM_COMMIT+PAGE_READWRITE 的堆页),减少 ReadProcessMemory 调用次数

ReadProcessMemory 失败时别重试,先检查 Protect 和 State

90% 的读失败不是权限问题,而是区域状态不对:State != MEM_COMMIT 或 Protect & PAGE_NOACCESS。直接重试或提权毫无意义。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载

性能影响:对每个 MEM_COMMIT 区域都调一次 ReadProcessMemory 开销不小,尤其大堆;但跳过检测又会漏数据。折中做法是只读 Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE) 的子集。

  • PAGE_GUARD 和 PAGE_NOCACHE 位要屏蔽掉再判断可读性——它们修饰行为,不否定可读
  • 遇到 ERROR_PARTIAL_COPY,说明目标页部分被回收或跨页保护不一致,应放弃整块,记日志,继续下一块
  • 不要用 SuspendThread 全局暂停——dump 过程本身可能被中断,且挂起线程栈可能导致死锁(比如正在 malloc)

dump 文件格式越简单越好,别学 minidump 套嵌结构

如果你只是想用 WinDbg / x64dbg 加载看内存,不需要符号、线程上下文、异常记录——那就用纯二进制拼接:每块前加 16 字节头(BaseAddress uint64 + Size uint64),后面紧跟原始内存字节。总大小可控,解析脚本三行搞定。

容易踩的坑:用 std::ofstream 默认文本模式写二进制,Windows 下会把 0x0A 换成 0x0D 0x0A;或者用 fwrite 但没设 FILE_FLAG_NO_BUFFERING,导致 SSD 上小块写放大。

  • 务必用 CreateFile(..., GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL) ——绕过系统缓存,避免 dump 中断时文件损坏
  • 每块写入前,用 SetFilePointerEx 定位,别依赖顺序写——某些区域 BaseAddress 可能小于前一块,顺序写会错位
  • 最后写一个 EOF 标记(比如 8 字节 0xFFFFFFFFFFFFFFFF),方便 loader 判断结束,而不是靠文件尺寸硬算

真正麻烦的是还原:dump 里没有重定位信息,也没有 PE 头,WinDbg .loadby 会失效;你得手动 .addmap 每个模块基址——这点常被忽略,以为写完就完事了。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

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

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1678

6

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

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

2026.04.23

339

31

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5267

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2328

6

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5267

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2328

6

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

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

2023.08.10

3878

6

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.26

3139

3

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习