DLLs and The Portable Executable File Format
I've been looking at different ways of understanding how DLLs work and why they're set up the way they are. I wanted to understand more about DLLs because they've caused some confusion for me during my development process. Also, I wanted to understand the Windows system on a much deeper level. So, without further ado: let's talk about the Portable Executable File Format!
The portable executable (PE) file format is the way an executable's data is arranged, such that the system's memory loader can load the executable and the system can run it.
Every time an executable is loaded, it can live in a different virtual address compared with the previous time that executable was loaded. This is called "virtual address relocation" and this happens because other executables are loaded in the same address space. The OS loads various DLLs into each program's address space, and of course depending on the features needed by the program, different DLLs will be loaded. The PE's headers point to different sections of the executable and uses relative virtual addresses (RVAs) to point to these sections. RVAs are an offset into the file and uses a base address (the virtual address at load time of the executable) as the place from which to offset.
Executable images are divided into sections. These sections are treated differently by the memory manager when the module is loaded, depending on whether that section is readable, writable, or executable. There are two general sections: Code section and Data section. The code section (a.k.a text section) is where the code for the executable lives. The data section is where the initialized variable data live.
Dynamically linked libraries (or DLLs) are the mechanism by which a program can be broken up into more than one executable file. Each of the smaller executable files are responsible for a different feature of the program's functionality. One reason why DLLs are beneficial is that the program only loads the modules right when a certain feature is needed, and this helps to save memory space. Another reason why DLLs are helpful is that individual features of the program can be upgraded without having to upgrade the entire program.
Remember: DLLs are different from static libraries! Static libraries are linked into the executable at compile time, whereas DLLs are linked at load/runtime.
There are two methods for loading DLLs:
Static linking (not the same as compile-time static linking, as mentioned previously).
Run-time linking.
DLL static linking is when an executable has a reference to another executable in its "import table". The import table is a list of all modules used and each function used in those modules. The Windows loader loads all modules mentioned in the import table and resolves the references to each function that the executable plans on using.
On the other hand, run-time linking is when the executable has the ability to decide to load another executable during run-time and call a function in that called executable. Run-time linking is more difficult to implement as a programmer compared with DLL static linking. However, DLL static linking is easier for a reverse engineer because he/she can easily use the import table to determine which modules are used and which functions are called by those modules.
Summary of Important concepts:
An executable can live in a different virtual address in memory from the last time that you loaded it
Executables have different "headers" that give information about different parts of the executable.
Relative Virtual Addresses (RVA) are used to point to different locations in an executable
DLL static linking is different from compile-time static linking
Source: Eilam, Eldad. "Reversing: Secrets of Reverse Engineering", 2005.















