WIN32_内存

1. 跨进程内存修改

1.1 通过CE修改进程中某数据的值

流程:

  1. 右键点击打开当前所处.cpp文件的所在的文件夹路径,然后找到DeBug目录下的exe文件进行运行。
  2. 打开CE,选择一个进程打开,然后找到我们需要的指定进程。
  3. 点击查找内存。
  4. Ctrl + G输入我们的内存地址,进行跳转。
  5. 框选指定字节进行输入数据完成跨进程内存修改。

1.2 跨进程修改某内存地址的数据


2. 进程内存管理

2.1 C


2.2 CPP


2.3 WIN32


3. 跨进程写入数据以及读取数据

3.1 流程叙述

  • 定义进程句柄、PID、内存地址、读写数据、计数等所需变量

  • 根据 PID 调用 OpenProcess 获取目标进程句柄,校验获取结果,失败直接收尾退出

  • 调用 VirtualAllocEx 在目标进程内申请一段可读可写内存,校验内存分配状态

  • 循环逐字节向远程内存依次写入数值数据,过程简单校验写入状态

  • 再次循环逐字节读取远程内存数据,每读取成功就格式化打印

  • 每打印 16 个字节自动换行规整排版

  • 操作完毕,调用 VirtualFreeEx 释放远程申请的内存

  • 关闭进程句柄,整套跨进程内存读写流程结束


4. 虚拟内存页面


5. 内存信息查询


6. 进程内存查询

输出结果:


6.1 初始化内存遍历变量

c 复制代码
LPVOID lpBaseAddr = 0;
MEMORY_BASIC_INFORMATION mbi;
RtlZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
  • lpBaseAddr: 遍历的起始地址,初始为 0
  • mbi: 存储内存区域信息的结构体
  • RtlZeroMemory:把结构体清零,避免脏数据影响后续调用

6.2 循环调用 VirtualQueryEx 遍历内存

c 复制代码
while (VirtualQueryEx(hProcess, lpBaseAddr, &mbi, sizeof(mbi)))
{
	printf("==================================\n");
	printf("BaseAddress					0x%08x\n", mbi.BaseAddress);
	printf("AllocationBase				0x%08x\n", mbi.AllocationBase);
	printf("AllocationProtect			0x%08x\n", mbi.AllocationProtect);
	printf("RegionSize					0x%08x\n", mbi.RegionSize);
	printf("State						0x%08x\n", mbi.State);
	printf("Protect						0x%08x\n", mbi.Protect);
	printf("Type						0x%08x\n", mbi.Type);
	printf("==================================\n");
	//更新地址
	lpBaseAddr = (PUCHAR)mbi.BaseAddress + mbi.RegionSize;
}
  • VirtualQueryEx:查询目标进程中,从 lpBaseAddr 开始的内存区域信息,结果写入 mbi
  • 打印该内存区域的关键信息。
  • 更新 lpBaseAddr: 当前区域结束地址 = 基址 + 区域大小,作为下一次查询的起点
  • 循环直到 VirtualQueryEx 返回 0(遍历完整个地址空间)

7. 内存属性修改

先做一个小练习:

解释: 通过用汇编访问地址形式,绕过语法糖的限制,但是由于编译器优化问题,直接输出变量会导致依旧输出的是原值,通过1.取地址2.强转3.解引用形式完成语法糖限制拿到新值


7.1 循环打印变量属性

输出结果:


7.2 更改变量属性,通过汇编角度改变


7.3 内存页属性修改与写入流程


8. 内存权限校验


9. 堆区内存管理

9.1 malloc 的调试链路

调试时通过 F11 单步跟进,malloc会先调用_malloc函数,过程中涉及中转表、堆栈等底层机制,最终会调用到HeapLock函数。调用HeapLock时需传入关键参数:申请内存的大小、对应的堆句柄等,完成内存分配。

9.2 堆的相关函数及特性

  • 默认堆

    • 每个进程在创建时会自动拥有一个默认堆,可通过GetProcessHeap函数获取其句柄,用于默认的内存分配操作。
  • 创建自定义堆

    • 可通过HeapCreate函数手动创建新的堆,函数返回该堆的句柄,便于对内存分配进行更精细的管理(如隔离不同模块的内存使用)。
  • HeapLock 函数: 是堆内存分配的关键函数,主要作用是申请堆内存,其参数包括

    • 堆句柄(指定操作的堆)

    • 标记(如HeapZeroMemory可使分配的内存初始化为 0,多个标记可通过逻辑 "或" 组合)

    • 需分配的字节数


10. 进程堆区内存

10.1 堆上开辟内存


10.2 堆内存管理操作

输出结果:

整体流程总览

这段代码演示了 Windows 堆(Heap)的完整生命周期操作,分为两大部分:

  1. 进程默认堆的简单使用
  2. 自定义私有堆的创建、分配、扩容、读写、释放与销毁
  • 第一部分: 进程默认堆的使用
  • 第二部分: 自定义私有堆的完整操作
  • 第三部分: 写入数据
  • 第四部分: 内存扩容(ReAlloc)
  • 第五部分: 遍历打印内存数据
  • 第六部分: 资源释放与清理

11. 堆区信息管理


12. 遍历堆块内容


本章完~