🧩 一、基本概念对比
| 函数名 | 作用 | 类比 |
|---|---|---|
| VirtualAlloc | 在内存中 申请新的空间(分配内存) | “找块新地建房子” |
| VirtualProtect | 修改一块 已有内存的保护属性(可读/可写/可执行) | “给房子换个用途或权限,比如从住宅改为工厂” |
🧠 二、VirtualAlloc —— 分配虚拟内存
📘 原型
c
LPVOID VirtualAlloc(
LPVOID lpAddress, // 申请的起始地址(一般为 NULL)
SIZE_T dwSize, // 申请的大小
DWORD flAllocationType, // 分配类型
DWORD flProtect // 初始保护属性(读写/执行)
);
💡 主要功能
- 在当前进程的虚拟地址空间中,开辟一段新的内存区域。
- 返回一个指向该区域的指针。
- 这块区域可以指定是否可执行、可写、可读。
🔨 常见用法
申请一段可读可写的内存,用来存放数据、shellcode、或动态代码。
c
LPVOID p = VirtualAlloc(
NULL, // 系统自动选择地址
0x1000, // 分配 4KB
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE // 可读可写
);
📦 这就相当于:
向系统要了一间新的“房子”(内存页),可以在里面读写数据。
🧩 三、VirtualProtect —— 修改内存保护属性
📘 原型
c
BOOL VirtualProtect(
LPVOID lpAddress, // 要修改的内存地址
SIZE_T dwSize, // 修改的大小
DWORD flNewProtect, // 新的保护属性
PDWORD lpflOldProtect // 保存旧属性
);
💡 主要功能
- 改变现有内存的访问权限,比如从:
- 只读 → 可写
- 可写 → 可执行
- 不可执行 → 可执行
🧱 四、二者关系形象比喻
| 操作 | 类比 |
|---|---|
VirtualAlloc |
向政府申请地皮 + 建房(开辟新内存) |
VirtualProtect |
改房子的用途或门禁(修改已有内存属性) |
举个例子:
你写了个程序,它的代码段是“只读只执行”的。
但你想在运行时动态修改一条指令,就必须:
- 先用
VirtualProtect临时把那块区域改成 可写;- 改完后再改回原来的保护属性。
🧪 五、通俗例子:修改一段代码(内存打补丁)
假设你要在程序运行时把某个函数的第一条指令改成 RET(直接返回)。
c
DWORD oldProtect;
BYTE patch[] = { 0xC3 }; // RET 指令
// 将目标函数的前 1 字节改为可写
VirtualProtect(targetFunc, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
// 写入补丁
memcpy(targetFunc, patch, 1);
// 改回原保护
VirtualProtect(targetFunc, 1, oldProtect, &oldProtect);
🔍 过程说明:
- 程序原本的代码段是不可写的;
- 用
VirtualProtect临时打开写权限; - 写入字节;
- 再把权限恢复;
- 程序继续正常执行。
💣 六、恶意代码中的典型用法
比如在 shellcode 或注入代码 中:
c
LPVOID buf = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(buf, shellcode, size);
((void(*)())buf)(); // 直接执行
或:
c
VirtualProtect(shellcode, size, PAGE_EXECUTE_READ, &old);
((void(*)())shellcode)();
这意味着:
程序动态申请或修改了一段可执行内存区域,然后把机器码写进去再运行。
这种行为往往在安全分析中被标记为可疑(代码注入或自修改代码)。
⚙️ 七、保护属性常见值(flProtect)
| 值 | 含义 |
|---|---|
PAGE_NOACCESS |
不能读、写、执行 |
PAGE_READONLY |
只读 |
PAGE_READWRITE |
可读可写 |
PAGE_EXECUTE |
只可执行 |
PAGE_EXECUTE_READ |
可执行可读 |
PAGE_EXECUTE_READWRITE |
可执行、可读、可写(常用于 shellcode) |
✅ 八、总结对比表
| 函数 | 作用 | 举例 | 注意事项 |
|---|---|---|---|
| VirtualAlloc | 分配新内存(可设置保护属性) | VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE) |
返回地址可写、可执行等 |
| VirtualProtect | 修改已有内存的保护属性 | 把代码页改成可写后打补丁 | 必须保存原属性并恢复 |
| 配合使用 | 分配可执行内存 + 修改权限执行 | 常见于代码注入、JIT 编译、恶意程序 | 注意权限安全与系统保护 |
💬 一句话总结:
VirtualAlloc:开辟地盘(申请内存)。VirtualProtect:改地盘的用途(改读写执行权限)。