How do I disable ASLR for heap addresses for a program compiled and linked with mingw-w64 GCC?

  aslr, binutils, mingw-w64, msvcrt, windows

Problem

I am using mingw-w64 GCC to compile and link a C program on Windows 10 Home, build 1809 (I know it’s old–long story). I want to disable Address Space Layout Randomization (ASLR) so my heap addresses do not change from run to run while debugging. How do I do that?

Sample program:

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

Compiling and running:

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

As you can see, the address returned by malloc changes each time. I want it to be the same value on every run.

Toolchain

I’m using mingw-w64 x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z. (I was previously using x86_64-5.4.0-release-posix-seh-rt_v5-rev0.7z, and saw the same behavior.)

$ 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...]

Although I am using cygwin shell utilities, I am not using the cygwin compiler or linker. The executable is only linked with MSVCRT plus the usual Windows libraries:

$ 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)

Attempt 1: –disable-dynamicbase

According to the binutils documentation, there should be an option to ld called --disable-dynamicbase to disable ASLR. But it is not recognized:

$ 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

Meanwhile, -Wl,--dynamicbase is accepted but does not alter the behavior.

Attempt 2: Clear DYNAMIC_BASE afterward

I found a utility called setdllcharacteristics that purports to clear the ASLR flag in the executable. However, running it seems to indicate the flag is already false:

$ 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

and the address is still different on each run after running that tool.

Interestingly, if I pass -Wl,--dynamicbase to the compiler, then setdllcharacteristics does show the flag as having been set, but after clearing it, the addresses are still different on each run. This leads me to conclude that DYNAMIC_BASE is not what is responsible for the varying addresses. But in that case, I don’t know what is or how to change it, even after a lot of googling.

Not attempted: MoveImages registry setting

I am aware there is a registry setting, HKLMSYSTEMCurrentControlSetControlSession ManagerMemory ManagementMoveImages according to this blog post, that might disable ASLR. But according to that same blog post that requires a reboot, which is quite annoying, and ideally I only want this for the one program I am debugging, not my entire system. I’m also doubtful changing that would have any effect given that clearing DYNAMIC_BASE did not.

Speculation: MSVCRT switch?

If DYNAMIC_BASE is not the culprit, then perhaps this is something MSVCRT does on its own. I found an MSDN page that mentions heap randomization. The way the page is written, I can’t tell whether that is controlled by the DYNAMIC_BASE flag, but my experiments seem to indicate it is not. The text also says:

Heap randomization is enabled by default for all applications running on Windows Vista and later.

but does not say how to disable it.

Source: Windows Questions

LEAVE A COMMENT