Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Windows keep randomizing the base address of my executable?

I've made a simple C-program that simply prints the address of main() at execution:

printf("%08X\n", &main);

I compile it with Visual C++ 2015 with the parameter /DYNAMICBASE, for x86 (same thing happens when compiling for x64).

First two times I run it, the address returned is different, as is expected. However, after two times, the address the program returns stays the same:

00C31050
00221050
00221050
00221050 

Recompiling or renaming the executable randomizes the address again.

What is happening here? Is Windows somehow caching the executable?

like image 720
Thomas Avatar asked Jun 30 '17 09:06

Thomas


1 Answers

First of all, you don't need to take an address of function and the pointers are better to print with %p specifier, which helps compiler to check types. The more accurate code would be:

printf ("%p\n", main);

On topic, ASLR technology, which is responsible for rebasing executable images is an OS feature that was designed to withstand buffer overrun attacks by making adresses less predictable. It doesn't guarantee that for two sequential runs the image will be placed at different locations, but an OS tries to vary the base from time to time, depending on many factors. For my tests I got (for example) the following results on Windows-7 32-bit build for 10 sequential runs immediately after compilation:

00BE1260
00BE1260
00221260
00F71260
01391260
01391260
01391260
01391260
01391260
003A1260

As you can see, even if consecutive runs were placed at the same locations, the base is changed after a while. What can be guaranteed is that executable image without support of dynamic base will always be placed at the base, set by linker in the exe-headers. The default base for executable image is the 400000h, hence the printed value will be something like this:

00401260
00401260
00401260
00401260
00401260
...

As for your case I suppose that OS rebasing algorithm works more predictive due to OS algorithm treats attack threats less probable or due to lack of entropy or resources. Rebasing requires an additional time and resources to remap memory pages and to tune relocations, so OS may decide that frequent rebasing is unneeded in your case.

Of course, Windows caches loaded executables to speedup their startup. That's why the probability that the base won't change on the next run is high enough. If you have plenty of RAM, the more RAM may be used for cache, the more probable that image won't be rebased. There is no reason to keep the same base if the image is completely reloaded. Also, the rebasing policy may vary between OS versions.

About the cache. It is not only a cache in functionality. If the image is loaded into memory, it may be used simultaneously for a multiple processes (instances). These instances can safely share the code pages because the code is read-only. This is one of the main reasons why Windows doesn't "unload" image immediately after the process terminates. But two processes may share the code only if it is tuned to the same base, because relocations patch the code in memory. If we force different processes to be rebased we inevitably need to abandon code sharing which will lead to increased consume of RAM.

EDIT:

BTW, I found that /DYNAMICBASE option is ignored by VS2015 and the linker always produces executable image with ASLR support, even if I explicitely set /DYNAMICBASE:NO. Also bit-to-bit comparison shows that the compiled files are identical with the exception of one timestamp and (as the result) a checksum. To get executable built by VS2015 without ASLR support I had to manually remove the IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE bit in exe-header. Don't know whether it was made intentionally or it is an MS bug.

like image 165
Serge Goncharov Avatar answered Oct 27 '22 00:10

Serge Goncharov