【问题标题】:Why do allocated blocks in virtual memory vary so much from one run to the other?为什么虚拟内存中分配的块从一次运行到另一次运行差异如此之大?
【发布时间】:2024-05-03 11:45:02
【问题描述】:

我知道这可能被认为是一个愚蠢的问题。但我的好奇心强于对投票的恐惧。下面的代码简单地保留了 1GB 的进程虚拟内存,打印了保留块的地址并释放了该块。

#include <iostream>
#include <Windows.h>

int main()
{
    // Reserves 1GB of the process virtual memory

    LPVOID lp1 = VirtualAlloc((LPVOID)NULL, 0x40000000, MEM_RESERVE, PAGE_NOACCESS);

    std::cout << lp1 << '\n';

    // Releases the 1GB block of virtual memory

    VirtualFree(lp1, NULL, MEM_RELEASE);
}

我在x64机器上运行这段代码几次,得到lp1的以下地址:

0x1e 9c22 0000
0xe1 8000 0000
0x16 92a3 0000
0x34 83ec 0000

为什么地址从一个运行到另一个变化如此之大?我知道 MS 文档对此没有任何说明,但我想知道对于这种奇怪的行为是否有合理的解释?

【问题讨论】:

  • 您可能还想意识到这只是一个保留,还没有提交任何内容。它只是在可用的虚拟地址空间中找到一块并保留它。可能,诸如地址空间随机化之类的东西也发挥了作用。

标签: c windows winapi memory-management


【解决方案1】:

没有理由在分配之间有所不同,但在后续分配时提供不同地址的一个普遍原因是使安全漏洞更难实施。

这个想法是,如果漏洞利用代码能够知道程序运行之间的内存位置,则它更容易执行。另一个原因可能是您看到的不同地址只是分配器跟踪内存的一种副作用。

【讨论】:

【解决方案2】:

您可能使用 /DYNAMICBASE 链接器选项进行链接,对于 x64 项目,默认情况下它是打开的。这也会在可执行文件头中打开 /HIGHENTROPYVA 选项。在您的 EXE 文件上运行 Dumpbin.exe /headers:

OPTIONAL HEADER VALUES
             20B magic # (PE32+)
             ...
           8160 DLL characteristics
                  High Entropy Virtual Addresses     <== here
                  Dynamic base                       <== and here
                  NX compatible
                  Terminal Server Aware

它要求内存管理器生成高度随机的地址。它使您的程序很难被恶意软件攻击。 this SE Q+A 的一些背景和高度可搜索的。

注意 /DYNAMICBASE 也打开了调试配置。虽然这在某种程度上有助于在程序有指针错误时让你的程序爆炸,但当你必须诊断这样的错误时,它更有可能是一个巨大的痛苦。不要犹豫,关掉它,它只是为了保护你的程序在野外。项目>属性>链接器>高级>随机基地址=“否”。

【讨论】: