A load address is the address at which a DLL loads.
All versions of Microsoft Windows load modules (.dll, .exe) into address space that is reserved using a call to VirtualAlloc().
The allocation of VirtualAlloc() can be queried by calling Win32 API GetSystemInfo() and examining the value returned in dwAllocationGranularity. For all versions of Microsoft Windows this has been 64KB.
Why is the load address important?
The load address is important because without it we can't calculate the offset inside the DLL so that we can obtain a symbol.
That's why a crash address with no DLL Load Address isn't very useful - we don't know which DLL the crash is in, nor do we know where the DLL was loaded.
But I don't have a load address. What can I do?
Depending upon how your module (DLL/EXE) was built we may be able to guess the correct load address.
If the OS you are using is Windows XP or earlier, we can guess the address.
First a brief chat about Address Space Layout Randomisation...
If the OS you are using is Windows Vista or later, we may be able to guess the load address. The reason this is not precises is because something known as Address Space Layout Randomisation (ASLR) was introduced with Microsoft Vista to improve security against many malicious computer attacks. Any program built with ASLR enabled when run on Vista (or later) will have the load address for all modules (including the .exe) randomised, making guessing the load address a waste of time.
ASLR is enabled by the /DYNAMICBASE in the linker settings of Visual Studio.
If you are using Visual Studio 2005 or earlier this setting is not available, your program is not affected by ASLR.
If you are using Visual Studio 2008 or later you will need to check to see if this option is present. If it is not present, your program is not affected by ASLR.
If you are not using Visual Studio to build your program then you may not be affected by this option, consult your compiler/linker documentation.
If your program is not affected by ASLR...
We can try to guess the load address of your DLL/EXE. We can do this regardless of which compiler/linker you used to build your program. All the programs I mention here are free to download at the time of writing this help file.
VM Validator
https://www.softwareverify.com/cpp-virtual-memory.php
This works for 32 bit and 64 bit programs.
Method 1
•Start your program using VM Validator or attach to your running program with VM Validator.
•On the Summary tab, inspect the DLLs sub tab in the lower half of the display.
•Find the DLL name in the DLL column.
•The load address is the value in the Address column.
Method 2
•Start your program using VM Validator or attach to your running program with VM Validator.
•Go to the Paragraphs tab.
•Find any purple entry, check the DLL name in the Description field.
•The load address is the value in the Address column.
In the example above, for dbgHelpBrowser.exe, the load address is 0x00400000.
Process Explorer
https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx
This works for 32 bit and 64 bit programs.
•Start your program
•Start Process Explorer. If your program is a service or runs as administrator you'll need to start Process Explorer as administrator.
•In Process Explorer, enable View -> Show Lower Pane. Then for View -> Lower Pane Window, choose DLLs.
•Select your program in the top window.
•Find your DLL in the bottom window. Right click. Choose Properties from the Context menu.
•In the Properties dialog, read the load address.
In the example above, for dbgHelpBrowser.exe, the load address is 0x00400000.
Visual Studio (any version)
•Start Visual Studio.
•From the Project menu, choose File -> Open -> Solution. Choose your executable.
•From the Debug menu, choose Start Debugging.
•From the Debug menu, choose Windows -> Modules.
•In the Modules window, find your DLL, then read the Address column.
In the example above, for threadLockChecker.exe, the load address is 0x00130000.
WinDbg
https://msdn.microsoft.com/en-gb/library/windows/hardware/ff551063(v=vs.85).aspx
•Start WinDbg
•From the File menu, choose Open Executable. Choose your executable.
•Type lm, then press return.
•All modules are listed. Find your module. The start address is the load address.
In the example above, for threadLockChecker.exe, the load address is 0x00130000.
Final Comments
OK, you should now know how to find the load address of a DLL or an EXE (or any module type). Remember that a load address obtained this way is only valid for symbol decoding if the executable doesn't have ASLR applied to it.
If your crash reporting code only grabs crash addresses and not DLL load addresses, you need to update your code so that you grab DLL load addresses at the time of the crash. That way you know for sure what the load addresses were and you won't have to guess the load addresses in future.