Force VirtualAlloc allocations to fall below the 2GB mark (#36)

Co-authored-by: ConorBobbleHat <c.github@firstpartners.net>
This commit is contained in:
ConorB 2023-06-02 20:30:45 +01:00 committed by GitHub
parent e83af50b10
commit 3e2d84fa69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 0 deletions

View File

@ -1171,6 +1171,10 @@ namespace kernel32 {
void *mem = 0; void *mem = 0;
posix_memalign(&mem, 0x1000, dwSize); posix_memalign(&mem, 0x1000, dwSize);
memset(mem, 0, dwSize); memset(mem, 0, dwSize);
// Windows only fences off the lower 2GB of the 32-bit address space for the private use of processes.
assert(mem < (void*)0x80000000);
DEBUG_LOG("-> %p\n", mem); DEBUG_LOG("-> %p\n", mem);
return mem; return mem;
} else { } else {

View File

@ -7,6 +7,8 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <stdarg.h> #include <stdarg.h>
#include <iostream>
#include <fstream>
uint32_t wibo::lastError = 0; uint32_t wibo::lastError = 0;
char *wibo::commandLine; char *wibo::commandLine;
@ -233,6 +235,42 @@ int main(int argc, char **argv) {
exec.loadPE(f); exec.loadPE(f);
fclose(f); fclose(f);
// 32-bit windows only reserves the lowest 2GB of memory for use by a process (https://www.tenouk.com/WinVirtualAddressSpace.html)
// Linux, on the other hand, will happily allow nearly the entire 4GB address space to be used.
// In order to prevent windows programs from being very confused as to why it's being handed
// addresses in "invalid" memory, let's map the upper 2GB of memory to ensure libc can't allocate
// anything there.
std::ifstream procMap("/proc/self/maps");
std::string procLine;
unsigned int lastMapEnd = 0;
const unsigned int FILL_MEMORY_ABOVE = 0x80000000; // 2GB
while (getline(procMap, procLine)) {
std::size_t idx = 0;
unsigned int mapStart = std::stoul(procLine, &idx, 16);
unsigned int mapEnd = std::stoul(procLine.substr(idx + 1), nullptr, 16);
// The empty space we want to map out is now between lastMapEnd and mapStart
unsigned int holdingMapStart = lastMapEnd;
unsigned int holdingMapEnd = mapStart;
if ((holdingMapEnd - holdingMapStart) != 0 && holdingMapEnd > FILL_MEMORY_ABOVE) {
holdingMapStart = std::max(holdingMapStart, FILL_MEMORY_ABOVE);
void* holdingMap = mmap((void*) holdingMapStart, holdingMapEnd - holdingMapStart, PROT_READ, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0);
if (holdingMap == MAP_FAILED) {
perror("Failed to create holding map");
return 1;
}
}
lastMapEnd = mapEnd;
}
procMap.close();
uint16_t tibSegment = (tibDesc.entry_number << 3) | 7; uint16_t tibSegment = (tibDesc.entry_number << 3) | 7;
// Invoke the damn thing // Invoke the damn thing
asm( asm(