Well, I read several of Matt Pietrek's articles on Portable Executable (PE) files, like:
- An In-Depth Look into the Win32 Portable Executable File Format, Part 1 and Part 2
- MSJ article on linkers
- MSJ article on COFF format
In addition, I have read a few other sources on the subject. It is either me overlooking some parts, or the questions aren't answered there.
So, here are the questions:
It is known that, when loading an EXE, the Windows Loader reads the list of imported DLL's from the Importa Address Table (IAT), and loads them into the process address space.
The process address space is a virtual space. The DLL may have already loaded into some physical space. This happens for DLLs like KERNEL32.dll
or USER32.dll
. What is the relation between the physical and virtual address? Does the loader just allocate pages and copy the DLL, or does it make references?
If a DLL is not loaded, does the Loader load the whole DLL, or just the functions needed? For instance, if you used function foo()
from bar.dll
, does the loader load the whole bar.dll
into the process address space? Or, does it just load the foo
's code into the process address space?
Assume your EXE file uses function MessageBox()
from USER32.DLL
, which resides in %WINDIR%\system32\user32.dll
. Can you develop a customized USER32.DLL
, put it in the same directory as your EXE file, and expect that your customized MessageBox
is called by your app instead of the system'd default MessageBox
?
Re 1: physical addresses play no role, everything involved here is virtual memory. The physical address is only established when a virtual memory page gets mapped into RAM, triggered by a page fault. Many basic DLLs appear at the same virtual memory address in several processes, like kernel32.dll. The processes simply share the same pages of code (not data).
Re 2: no actual 'loading' takes place, the feature used is the same one that supports memory mapped files. The backing of these pages is the DLL file itself, not the paging file. Nothing gets loaded until a page fault forces Windows to read the page from the file into RAM. But yes, the entire code section of the DLL gets mapped.
Re 3: yes, that would work. But it is next to impossible to make it work in practice since you will have to write replacement functions for all the user32 exports that your program uses. Including the ones that other Win32 functions use, you cannot know. API hooking is the typical technique used, Detours from Microsoft Labs is a good one.
Windows Internals edition 5 is an excellent book to learn more about the plumbing.
1) When you create new process NT kernel loader allocates space for the process and map all PE sections on specified place. Then NT loader looks through import table, loads DLLs in process memory and correct pointers if necessary (it's called relocation).
2) Loader loads the whole DLL in process address space.
3) Yes, it will use user32.dll
from the same directory where EXE is located. See this link. But as the most WinAPI functions located in user32.dll
your custom dll must export a lot of them.