Question:
I want to make my own dll loader, which will allow loading dll into the process from an array of bytes, but I found a ready-made version. And I don’t understand one detail. Everything is in order ..
First of all, we project all sections into the target process according to the alignment. Secondly, we create a memory area in the target process into which we write the data necessary to run the dll from memory and a function that will fill in the import table, relocation, and which we, in turn, will run in a separate thread. Actually the loader itself: https://github.com/BenjaminSoelberg/ReflectivePELoader . And the moment that I don’t understand is when we fill in the loaderdata
structure, we pass the addresses of functions from the program that we load the dll into the fields of pointers to functions:
typedef HMODULE(__stdcall* pLoadLibraryA)(LPCSTR);
typedef FARPROC(__stdcall* pGetProcAddress)(HMODULE, LPCSTR);
LoaderParams.fnLoadLibraryA = LoadLibraryA;
LoaderParams.fnGetProcAddress = GetProcAddress;
After all, the loading addresses of these functions will not always be the same in our loader and the target process. Libraries can be loaded at different addresses in different processes. Nevertheless, this loader works like a clock on x32 programs.
UPD. I decided to delve into the debugger, and it’s true that so far all the libraries that I compared have the same load address. Both x32 and x64 (but not x64 with x32). Are they always the same? As far as I knew, a dll can be loaded at an arbitrary address (but within the allowable )
Answer:
When starting the program, I would say that there is a "minimal package" of libraries. Despite the fact that you called LoadLibraryA
, the system still gives you the address of the library that is already preloaded. Those. if you call LoadLibraryA
twice, the library will be loaded at the same address.
I would like to point out a few things:
- Each library or module has a "recommended load address" – called the image base (in the PE-coff header). When a library is loaded for the first time, it is loaded exactly at this address, if it is not occupied by another library or module. This is what leads to the "stability" of library addresses. With the same library loading sequence, they will end up at the same addresses.
- There is a "top area" for loading system libraries.
- The library can load more libraries that it needs during the initialization process (can be both dynamically linked and programmatically)
- Some drivers can inject their library into every running process
- Each process has its own address space, called virtual memory , the memory of address spaces does not overlap (does not conflict, it can intersect – but this is controlled by the OS and you cannot check this from the application level), non-system libraries can be loaded at different addresses for different programs.
Those. even if you theoretically load three or four important libraries kernel32.dll user32.dll gdi32.dll ntdll.dll (they are always in memory) – they will a) be located according to their image base; b) a dozen more dependent libraries will be loaded. Since the system libraries are loaded first, they will occupy their stable addresses, which others will lack.
Further .. I would recommend such an algorithm, first make a call to GetModuleHandleA
, if this function returned the address – this will mean that the library has already been loaded, and it can not be loaded again (exceptions below). For system libraries (And also for libraries of the import section of your executable module) – the function will work without problems. If you "embed" – then I recommend calling this function purely for verification. The LoadLibraryA
function, unlike GetModuleHandleA
, increments the library usage counter, i.e. if your program or a parallel "thread" (thread) makes a call to FreeLibrary
– then in the case of LoadLibraryA
– the library will not be unloaded, because there will be an additional label that it is used, for GetModuleHandleA
– there will be no such behavior. You can use the GetModuleHandleA
/ LoadLibraryA
pair instead of the LoadLibrary
– FreeLibrary
pair if library unloading is not needed. I did not notice that someone unloaded libraries, I think this applies exclusively to plugin libraries.
PS The stability of the address space is fraught with the possibility of viruses penetrating through the introduction of raw code with a link to stable-located system functions. Therefore, in Windows OS, starting with vista ("six", without installing additional packages, in earlier ones it is possible with XP conditionally), there is already ASLR technology that allows you to randomize the address space of loaded libraries. I have not studied thoroughly, I can not say how effective it is. So far (2020), this technology does not apply to windows system libraries. The addresses of the system libraries are specially chosen so that the kernel would effectively fit in memory, perhaps this is the reason for this behavior. ASLR is enabled for new programs by setting the dynamicbase flag and is enabled by default in VS2019. For older programs, ASLR is disabled for backwards compatibility. Perhaps in the future ASLR will work more efficiently.