Можно ли защитить область памяти от WinAPI?

Прочитав эта интересная статья Излагая методику отладки повреждения кучи, я начал задаваться вопросом, как я могу настроить ее для своих собственных нужд. Основная идея состоит в том, чтобы предоставить пользовательский malloc () для выделения целых страниц памяти, а затем включить некоторые биты защиты памяти для этих страниц, чтобы программа аварийно завершала работу при их записи, и некорректная инструкция записи могла быть обнаружена в действии. , Пример кода на C под Linux (mprotect () используется для включения защиты), и мне любопытно, как применить это к собственным C ++ и Windows. VirtualAlloc () и / или VirtualProtect () выглядят многообещающе, но я не уверен, как будет выглядеть сценарий использования.

Fred *p = new Fred[100];
ProtectBuffer(p);
p[10] = Fred(); // like this to crash please

Мне известно о существовании специализированных инструментов для отладки повреждения памяти в Windows, но мне все еще любопытно, можно ли было бы сделать это «вручную», используя этот подход.

РЕДАКТИРОВАТЬ: Кроме того, это даже хорошая идея под Windows, или просто занимательный интеллектуальный тренинг?

3

Решение

Да, вы можете использовать VirtualAlloc и VirtualProtect для настройки разделов памяти, защищенных от операций чтения / записи.

Вы должны были бы повторно реализовать operator new а также operator delete (и их [] родственников), так что ваши выделения памяти контролируются вашим кодом.

И имейте в виду, что это будет только для каждой страницы, и вы будете использовать (по крайней мере) три страницы виртуальной памяти на выделение — не большая проблема в 64-битной системе, но может вызвать проблемы, если у вас много распределений в 32-битной системе.

Примерно то, что вам нужно сделать (вы должны найти размер страницы для сборки Windows — я слишком ленив, поэтому я буду использовать 4096 и 4095 для представления размеров страниц и страниц-1 — вам также нужно будет сделать больше проверка ошибок, чем этот код делает !!!):

void *operator new(size_t size)
{
Round size up to size in pages + 2 pages extra.
size_t bigsize = (size + 2*4096 + 4095) & ~4095;

// Make a reservation of "size" bytes.
void *addr = VirtualAlloc(NULL, bigsize, PAGE_NOACCESS, MEM_RESERVE);

addr = reinterpret_cast<void *>(reinterpret_cast<char *>(addr) + 4096);

void *new_addr = VirtualAlloc(addr, size, PAGE_READWRITE, MEM_COMMIT);

return new_addr;
}

void operator delete(void *ptr)
{
char *tmp = reinterpret_cast<char *>(ptr) - 4096;

VirtualFree(reinterpret_cast<void*>(tmp));
}

Как я уже сказал, что-то в этом роде — я не пробовал компилировать этот код, поскольку у меня есть только виртуальная машина Windows, и я не могу потрудиться скачать компилятор и посмотреть, действительно ли он компилируется. [Я знаю, что принцип работает, поскольку мы сделали нечто подобное, где я работал несколько лет назад].

5

Другие решения

Это то, для чего предназначены страницы Gaurd (см. Это MSDN учебник), они вызывают специальное исключение при первом обращении к странице, что позволяет вам делать больше, чем просто сбой при первом доступе к недопустимым страницам (и отлавливать плохие операции чтения / записи в отличие от указателей NULL и т. д.).

2

По вопросам рекламы [email protected]