如何为与 mingw-w64 GCC 编译和链接的程序禁用堆地址的 ASLR?

问题描述

问题

我正在使用 mingw-w64 GCC 在 Windows 10 Home 上编译和链接 C 程序,构建 1809(我知道这是一个古老的故事)。我想禁用地址空间布局随机化 (ASLR),以便在调试时我的堆地址不会随运行而改变。我该怎么做?

示例程序:

// testaslr.c
#include <stdio.h>                     // printf
#include <stdlib.h>                    // malloc
int main()
{
  printf("allocation: %p\n",malloc(16));
  return 0;
}

编译运行:

$ gcc -o testaslr -g -Wall testaslr.c
$ ./testaslr
allocation: 00000000007A1420
$ ./testaslr
allocation: 0000000000A81420
$ ./testaslr
allocation: 0000000000BF1420

如您所见,malloc 返回的地址每次都会发生变化。我希望它在每次运行时都具有相同的值。

工具链

我正在使用 mingw-w64 x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z。 (我之前使用过 x86_64-5.4.0-release-posix-seh-rt_v5-rev0.7z,并且看到了相同的行为。)

$ gcc --version
gcc.exe (x86_64-posix-seh-rev0,Built by MinGW-W64 project) 8.1.0
[...copyright stuff...]
$ ld --version
GNU ld (GNU Binutils) 2.30
[...copyright stuff...]

虽然我使用的是 cygwin shell 实用程序,但我没有使用 cygwin 编译器或链接器。可执行文件仅与 MSVCRT 以及通常的 Windows 库链接

$ ldd testaslr.exe
        ntdll.dll => /cygdrive/c/WINDOWS/SYstem32/ntdll.dll (0x7fff5ad40000)
        KERNEL32.DLL => /cygdrive/c/WINDOWS/System32/KERNEL32.DLL (0x7fff57f60000)
        KERNELBASE.dll => /cygdrive/c/WINDOWS/System32/KERNELBASE.dll (0x7fff56fa0000)
        msvcrt.dll => /cygdrive/c/WINDOWS/System32/msvcrt.dll (0x7fff5a3b0000)

尝试 1:--disable-dynamicbase

根据binutils documentation,应该有一个选项ld 叫做--disable-dynamicbase 来禁用ASLR。但无法识别:

$ gcc -o testaslr -g -Wall testaslr.c -Wl,--disable-dynamicbase
E:/cygwin/home/Scott/opt/mingw64-8.1.0/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: unrecognized option '--disable-dynamicbase'
E:/cygwin/home/Scott/opt/mingw64-8.1.0/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: use the --help option for usage information
collect2.exe: error: ld returned 1 exit status

同时,-Wl,--dynamicbase 被接受但不会改变行为。

尝试 2:之后清除 DYNAMIC_BASE

我发现了一个名为 setdllcharacteristics 的实用程序,它声称可以清除可执行文件中的 ASLR 标志。然而,运行它似乎表明标志已经是假的:

$ setdllcharacteristics.exe -d testaslr.exe
Original DLLcharacteristics = 0x0000
 DYNAMIC_BASE    = 0
 NX_COMPAT       = 0
 FORCE_INTEGRITY = 0
Updated  DLLcharacteristics = 0x0000
 DYNAMIC_BASE    = 0
 NX_COMPAT       = 0
 FORCE_INTEGRITY = 0

运行该工具后,每次运行的地址仍然不同。

有趣的是,如果我将 -Wl,--dynamicbase 传递给编译器,那么 setdllcharacteristics 确实 将标志显示为已设置,但清除它后,地址仍然不同每次运行。这使我得出结论,DYNAMIC_BASE 不是造成地址变化的原因。但在那种情况下,即使经过大量谷歌搜索,我也不知道是什么或如何更改它。

未尝试:MoveImages 注册表设置

我知道根据 this blog post注册表设置 HKLM\SYstem\CurrentControlSet\Control\Session Manager\Memory Management\MoveImages 可能会禁用 ASLR。但是根据需要重新启动的同一篇博客文章,这很烦人,理想情况下,我只希望我正在调试的一个程序,而不是我的整个系统。鉴于清除 DYNAMIC_BASE 没有。

猜测:MSVCRT 切换?

如果 DYNAMIC_BASE 不是罪魁祸首,那么这可能是 MSVCRT 自己做的事情。我找到了一个 MSDN page that mentions heap randomization页面的编写方式,我不知道是否由 DYNAMIC_BASE 标志控制,但我的实验似乎表明它不是。文中还说:

在 Windows Vista 及更高版本上运行的所有应用程序认启用堆随机化。

但没有说明如何禁用它。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)