DEP только отключив разрешение Execution от каждого без кода страницы памяти. Код приложения загружается в память, у которой есть разрешение на выполнение; и есть много JIT, которые работают в Windows/Linux/MacOSX, даже когда DEP активен. Это связано с тем, что существует возможность динамически распределять память с установленными разрешениями.
Обычно обычный malloc нельзя использовать, поскольку разрешения для каждой страницы. Выравнивание malloced памяти на страницах все еще возможно по цене некоторых накладных расходов. Если вы не будете использовать malloc, нестандартное управление памятью (только для исполняемого кода). Настраиваемое управление - это общий способ выполнения JIT.
Существует решение от проекта Chromium, в котором используется JIT для javascript V8 VM и который является кросс-платформенным. Чтобы быть кросс-платформенным, необходимая функция реализована в нескольких файлах, и они выбираются во время компиляции.
Linux: (хром src/v8/src/platform-linux.cc) флаг PROT_EXEC of mmap().
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
const size_t msize = RoundUp(requested, AllocateAlignment());
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* addr = OS::GetRandomMmapAddr();
void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mbase == MAP_FAILED) {
/** handle error */
return NULL;
}
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, msize);
return mbase;
}
Win32 (SRC/v8/SRC/platform-win32.cc): флаг PAGE_EXECUTE_READWRITE из VirtualAlloc
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
// The address range used to randomize RWX allocations in OS::Allocate
// Try not to map pages into the default range that windows loads DLLs
// Use a multiple of 64k to prevent committing unused memory.
// Note: This does not guarantee RWX regions will be within the
// range kAllocationRandomAddressMin to kAllocationRandomAddressMax
#ifdef V8_HOST_ARCH_64_BIT
static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
#else
static const intptr_t kAllocationRandomAddressMin = 0x04000000;
static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
#endif
// VirtualAlloc rounds allocated size to page size automatically.
size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
intptr_t address = 0;
// Windows XP SP2 allows Data Excution Prevention (DEP).
int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
// For exectutable pages try and randomize the allocation address
if (prot == PAGE_EXECUTE_READWRITE &&
msize >= static_cast<size_t>(Page::kPageSize)) {
address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits)
| kAllocationRandomAddressMin;
address &= kAllocationRandomAddressMax;
}
LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address),
msize,
MEM_COMMIT | MEM_RESERVE,
prot);
if (mbase == NULL && address != 0)
mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);
if (mbase == NULL) {
LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
return NULL;
}
ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize));
return mbase;
}
MacOS (SRC/v8/SRC/platform-macos.cc): флаг это PROT_EXEC mmap, как Linux или другой posix.
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
const size_t msize = RoundUp(requested, getpagesize());
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* mbase = mmap(OS::GetRandomMmapAddr(),
msize,
prot,
MAP_PRIVATE | MAP_ANON,
kMmapFd,
kMmapFdOffset);
if (mbase == MAP_FAILED) {
LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, msize);
return mbase;
}
И я также хочу отметить, что bcdedit.exe
-как способ следует использовать только для очень старых программ, что создает новый исполняемый код в памяти, но не устанавливает в Exec свойство на этой странице. Для более новых программ, таких как firefox или Chrome/Chromium, или любого современного JIT, DEP должен быть активным, а JIT будет управлять разрешениями памяти мелкомасштабным образом.
Что не так с VirtualProtectEx? «Я хочу делать то, что делает VirtualProtectEx, но я не хочу использовать VirtualProtectEx?» А? –
Если вы внимательно прочитаете мой вопрос, вы увидите, что я хотел бы иметь кросс-платформу кода. Это означает, что я не хочу ничего использовать из API окон, если я могу помочь. Единственной платформой, зависящей от объекта, должен быть набор команд x86. – mac
Этого не произойдет. Компиляторы (в отличие от переводчиков) являются специфичными для платформы. Даже в x86 вам приходится иметь дело с вещами, такими как независимый от позиции код в Linux. Не говоря уже о разрешениях на выполнение, которые являются аппаратными, но живут в ОС. –