Можно ли защитить область памяти от 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, и я не могу потрудиться загрузить компилятор и посмотреть, действительно ли он компилируется. [Я знаю, что принцип работает, поскольку мы сделали нечто подобное, где я работал несколько лет назад].
Это то, для чего предназначены Gaurd Pages (см. Этот учебник MSDN), они вызывают специальное исключение при первом обращении к странице, что позволяет вам делать больше, чем просто сбой при первом доступе к недопустимым страницам (и, в отличие от этого, отлавливать неправильные операции чтения / записи). на нулевые указатели и т. д.).
Можно ли защитить область памяти от WinAPI?
В принятом ответе указано «Да, можно», что технически неверно.
Вы не можете защитить область памяти, если эта область не является точно 1 областью памяти.
Так. Вы можете изменить защиту только определенного. Каждый
Поскольку мы говорим о виртуальной памяти и WinAPI, мы привязали к 4096 байтам (0x1000).
Поэтому, если вы хотите защитить определенную область памяти, вы фактически собираетесь изменить защиту области памяти, это означает, что если ваш выделенный объект перекрывает несколько областей памяти, то каждая перекрывающаяся область памяти получает такую же защиту после того, как вы защитите свой объект.