I think I finally got it using a method similar to what dxiv suggested in the comments. Instead of using the dummy DLL, I create a basic executable file that loads at the beginning of my reserved area using the /FIXED
and /BASE
compiler flags. The executable file code contains an uninitialized array, which ensures that the image covers the necessary addresses in memory, but does not take up unnecessary space in the file:
unsigned char Reserved[4194304];
At run time, the executable file copies itself to a new location in memory and updates a couple of fields in the Process Environment block to point to it. Without updating fields, calling certain functions, such as FormatMessage
, will fail.
#include <intrin.h>
I built the executable with /NODEFAULTLIB
to reduce its size and the number of DLLs loaded at runtime, therefore using the built-in __movsb
. You may be able to connect to MSVCRT if you want, and then replace __movsb
with memcpy
. You can also import memcpy
from ntdll.dll
or write your own.
Once the executable is deleted, I call the function in the DLL that contains the rest of my code. The DLL uses UnmapViewOfFile
to get rid of the original PE image, which gives me a nice 4MB + memory block to work, guaranteed to not contain associated files, stack streams or heaps.
A few things to keep in mind with this technique are:
- This is a huge hack. I felt this was a dirty letter, and it could very well fall apart in future versions of Windows.
I also have not tested this on anything other than Windows 7. This code works at least on Windows 7 and Windows 10. - Since the executable is built with
/FIXED /BASE
, its code is not position-independent, and you cannot just go to the moved executable. - If the DLL function that calls
UnmapViewOfFile
returns, the program crashes because the code section that we left out no longer exists. I use ExitProcess
to ensure that the function never returns. - Some sections in a relocated PE image, such as those that contain code, can be freed using
VirtualFree
to free some physical memory. - My code does not bother re-sorting the loader data table entries. This seems like normal, but could break if something should depend on the records sorted by image address.
- Some antivirus programs may be suspected of this. Microsoft Security Essentials, at least, did not complain.
In retrospect, the dxiv dummy DLL method may have been simpler because I did not have to bind to PEB. But I stuck with this technique, because the executable is more likely to be downloaded to the desired base address. The dummy dll method did not work for me. DLLs are loaded by Ntdll after Windows has already reserved the memory areas that I need.
source share