Here is the scenario - You have a legacy application where you wish to load a DLL or module at a fixed or preferred base address. Why would you need it?, that is because in the EXE or DLL code you may make use of the absolute addresses and pointers. This application would work great on Windows XP or older OS, but on Windows Vista you would see that your DLL fails to load at preferred address as some other module is already loaded in the asked virtual address space range. You would notice that all the dlls including system dlls and custom dlls would be loaded at random addresses.
Here is why it happens:
Starting from Windows Vista a new security feature is added called Address Space Layout Randomization (ASLR) which will randomize all (system + user) Loaded DLLs. You may find more information at MSDN: Windows Vista ISV Security .
In any version of Windows OS there is *no* guarantee that a process or DLL will always load at same address space or it will get a particular /FIXED (Fixed Base Address). You may specify a preferred base address using /BASE (Base Address) linker option and in case “preferred” base address in not available your application must be adaptive to the rebasing/relocation of the image or DLL.
Ideally we should never make this assumption or requirement that a DLL will not be relocated. We must not rely on where the process or DLL is loaded.
DLL relocation may happen when "almost anything" changes, including the installation of service packs, QFEs, third party products, and other major versions of Windows.
Out of curiosity, you may have a question:
1. Is there any way to disable ASLR ?
Unfortunately there is no legitimate way to disable ASLR on Windows Vista and later. In fact, it is a security enhancement and no one should try disabling it.
2. What is the memory address space range in virtual memory map where system DLLs and user DLLs could load?
I would say, there is as such no specific virtual address space range, the DLLs can be loaded at any random address.
You may find more information about ASLR at following blog posts:
Early in the boot process, the Memory Manager picks a random DLL image-load bias from one of 256 64KB-aligned addresses in the 16MB region at the top of the user-mode address space. As DLLs that have the new dynamic-relocation flag in their image header load into a process, the Memory Manager packs them into memory starting at the image-load bias address and working its way down.
Executables that have the flag set get a similar treatment, loading at a random 64KB-aligned point within 16MB of the base load address stored in their image header. Further, if a given DLL or executable loads again after being unloaded by all the processes using it, the Memory Manager reselects a random location at which to load it. Figure 7 shows an example address-space layout for a 32-bit Windows Vista system, including the areas from which ASLR picks the image-load bias and executable load address.
Hence, to determine the range is impractical. The only way is to look at all the base addresses for all the system DLLs, and the add 16MB to the highest one and subtract 16MB from the lowest one. Please note that the base address in any of the system DLLs could change with any update so there is no dependable way to get the range.
There is a flag in the EXE header that marks if it will get a random base address (/DYNAMICBASE)
The base address that is chosen will be somewhere in this range: (BaseAddressInExeHeader-16mb) >= NewBaseAddress <= (BaseAddressInExeHeader +16mb)
The moral of the story is – “no virtual address” is guaranteed available and we should not rely that a process or DLL will be loaded at same address space or at preferred base address every time. The long term and most suitable solution is to have “relative offsets”, where you use relative offsets to the function address instead of using absolute addresses. The preferred way is to get a function pointer in a loaded DLL is to call GetProcAddress Function. GetProcAddress( ) gives you the address of an exported symbol from a loaded DLL. To get the base address of a loaded DLL, you can use EnumProcessModulesEx Function and then for each, call GetModuleInformation Function .
I can't agree with "no one should try disabling it." because when debugging code, it is often extremely helpful to have repeatability. It should be possible to disable this, ideally as a debugger option.
Well, that's great, but now putting breakpoints at the disassembly level in VS2008 is rendered useless, as it is based on the run-time address of the instruction.
Do you know if there's any way to work around that ?
@Barbie: It turns out that in this case you can deal with it by setting your /BASE for your DLLs immediately following the EXE so there are no memory gaps. Obviously if the EXE size changes this won't work anymore so it's only good for a short term solution.