How to reserve memory areas before Windows maps my DLL files to a program?

My Windows program should use very specific memory areas. Unfortunately, Windows loads quite a few DLLs in memory, and because of the ASLR, their locations are not predictable, so they can be mapped to the regions that my program should use. On Linux, Wine solves this problem using a preloader application that reserves memory areas and then manually loads and executes the actual image and dynamic linker. I assume that a specific method is not possible on Windows, but is there any other way to get reserved areas of memory that are guaranteed not to be used by DLLs or a bunch of processes?

If this helps, memory regions are fixed and known at compile time. In addition, I know that ASLR can be disabled in the registry or in the process using the Enhanced Mitigation Experience Toolkit, but I do not want my users to do this.

+5
source share
1 answer

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]; // 4MB 

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> #include <windows.h> #include <winternl.h> #pragma intrinsic(__movsb) void Relocate() { void *Base, *NewBase; ULONG SizeOfImage; PEB *Peb; LIST_ENTRY *ModuleList, *NextEntry; /* Get info about the PE image. */ Base = GetModuleHandleW(NULL); SizeOfImage = ((IMAGE_NT_HEADERS *)(((ULONG_PTR)Base) + ((IMAGE_DOS_HEADER *)Base)->e_lfanew))->OptionalHeader.SizeOfImage; /* Allocate memory to hold a copy of the PE image. */ NewBase = VirtualAlloc(NULL, SizeOfImage, MEM_COMMIT, PAGE_READWRITE); if (!NewBase) { ExitProcess(GetLastError()); } /* Copy the PE image to the new location using __movsb since we don't have a C library. */ __movsb(NewBase, Base, SizeOfImage); /* Locate the Process Environment Block. */ Peb = (PEB *)__readfsdword(0x30); /* Update the ImageBaseAddress field of the PEB. */ *((PVOID *)((ULONG_PTR)Peb + 0x08)) = NewBase; /* Update the base address in the PEB loader data table. */ ModuleList = &Peb->Ldr->InMemoryOrderModuleList; NextEntry = ModuleList->Flink; while (NextEntry != ModuleList) { LDR_DATA_TABLE_ENTRY *LdrEntry = CONTAINING_RECORD( NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); if (LdrEntry->DllBase == Base) { LdrEntry->DllBase = NewBase; break; } NextEntry = NextEntry->Flink; } } 

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.
+2
source

Source: https://habr.com/ru/post/1244395/


All Articles