NX bit (No-eXecute bit) — аппаратный флаг в записях таблиц страниц процессора, который запрещает выполнение инструкций из определённых областей памяти. DEP (Data Execution Prevention) — системная политика Windows, использующая этот флаг для защиты от запуска кода из данных. Вместе они образуют базовый барьер против классических атак через переполнение буфера: даже если злоумышленник записал shellcode в стек или кучу, процессор откажется его выполнять.
В архитектурах x86-64 и x86 с PAE записи таблиц страниц (PTE) имеют ширину 64 бита. Бит 63 в такой записи отведён под флаг запрета выполнения: когда он установлен, страница доступна для чтения и записи, но попытка извлечь из неё инструкцию вызывает исключение #PF (Page Fault) с кодом ошибки, указывающим на нарушение прав выполнения.
Исторически в 32-битном режиме x86 без PAE таблицы страниц имели ширину 32 бита и отдельного бита запрета выполнения не содержали. AMD добавила NX bit в расширение AMD64 (Long Mode), Intel реализовала аналогичную функциональность под названием XD bit (eXecute Disable) в EM64T. В 32-битном режиме с включённым PAE записи расширяются до 64 бит, и бит NX становится доступен — именно так Windows XP SP2 активировала DEP на 32-битных системах.
В Long Mode режим PAE включён принудительно на аппаратном уровне, поэтому NX bit всегда доступен без дополнительной настройки.
DEP — системная функция защиты памяти, встроенная в Windows начиная с Windows XP и Windows Server 2003. Она помечает страницы данных (стек, кучу по умолчанию, пулы памяти) как неисполняемые. Если приложение пытается выполнить код из защищённой страницы, возникает исключение со статусом
DEP не является исчерпывающей защитой от всех эксплойтов — это один из инструментов в многоуровневой модели безопасности.
DEP настраивается при загрузке системы через параметры boot configuration data (политика no-execute page protection). Приложение может узнать текущую политику через
При активной политике DEP следующие области памяти помечаются как неисполняемые:
Выделения через
Microsoft рекомендует после генерации исполняемого кода снять права на запись через
В Linux ядро использует NX bit для разделения прав доступа к страницам. По умолчанию стек и куча пользовательских процессов помечаются как неисполняемые. Управление осуществляется через флаги
Принцип W^X (Write XOR Execute) — страница не должна быть одновременно доступна для записи и выполнения — является базовым ориентиром при проектировании подсистем ядра и пользовательских приложений. Некоторые дистрибутивы исторически использовали дополнительные патчи (exec-shield, PaX) для расширения защиты на сегменты данных и усиления политик, однако в современных ядрах основная функциональность обеспечивается самим NX bit и стандартными механизмами
Флаг
Если вывод содержит
Утилита
Вывод вида
Файл
NX/DEP блокирует простейший сценарий атаки: запись shellcode в буфер и переход на него. Однако это не делает систему неуязвимой. Атакующие разработали техники обхода:
Вместо внедрения нового кода атакующий переиспользует уже существующие инструкции (гаджеты) из исполняемых сегментов программы и библиотек. ROP-цепочка строится из последовательности адресов возврата, каждый из которых указывает на полезную последовательность инструкций, завершающуюся
Частный случай ROP: вместо произвольных гаджетов атакующий вызывает функции стандартной библиотеки (например,
Если приложение использует JIT-компиляцию (браузеры, виртуальные машины), атакующий может внедрить вредоносный байткод, который JIT скомпилирует в исполняемую память. DEP здесь не помогает, потому что память выделена с правами выполнения легально.
DEP может нарушать работу приложений, которые:
Например, приложения, написанные с использованием Active Template Library (ATL) версии 7.1 и ранее, могут пытаться выполнить код на страницах, помеченных как неисполняемые, что приводит к NX fault и завершению процесса.
Для PE-файлов, содержащих код в секции данных, необходимо добавить атрибут
В Linux аналогичная проблема возникает, если бинарный файл собран с исполняемым стеком (флаг
При отладке приложения, завершающегося из-за DEP, в отладчике будет видно исключение
NX/DEP — один из слоёв защиты, а не полное решение. Оно не защищает от:
Для полноценной защиты NX комбинируется с другими механизмами: ASLR (рандомизация адресного пространства), Stack Canaries (обнаружение переполнения стека), CFG (Control Flow Guard в Windows), CFI (Control Flow Integrity в компиляторах), SEHOP (защита структурированных обработчиков исключений). Каждый из этих механизмов закрывает определённый класс атак, который NX оставить открытым.
Аппаратная основа: бит NX в таблицах страниц
В архитектурах x86-64 и x86 с PAE записи таблиц страниц (PTE) имеют ширину 64 бита. Бит 63 в такой записи отведён под флаг запрета выполнения: когда он установлен, страница доступна для чтения и записи, но попытка извлечь из неё инструкцию вызывает исключение #PF (Page Fault) с кодом ошибки, указывающим на нарушение прав выполнения.
Исторически в 32-битном режиме x86 без PAE таблицы страниц имели ширину 32 бита и отдельного бита запрета выполнения не содержали. AMD добавила NX bit в расширение AMD64 (Long Mode), Intel реализовала аналогичную функциональность под названием XD bit (eXecute Disable) в EM64T. В 32-битном режиме с включённым PAE записи расширяются до 64 бит, и бит NX становится доступен — именно так Windows XP SP2 активировала DEP на 32-битных системах.
| Режим | Поддержка NX | Условие |
|---|---|---|
| x86-64 (Long Mode) | Да | Всегда доступна, PAE обязателен |
| 32-бит с PAE | Да | PAE включён через бит 5 регистра CR4 |
| 32-бит без PAE | Нет | Записи PTE 32-битные, бит отсутствует |
В Long Mode режим PAE включён принудительно на аппаратном уровне, поэтому NX bit всегда доступен без дополнительной настройки.
DEP в Windows: политика и механика
DEP — системная функция защиты памяти, встроенная в Windows начиная с Windows XP и Windows Server 2003. Она помечает страницы данных (стек, кучу по умолчанию, пулы памяти) как неисполняемые. Если приложение пытается выполнить код из защищённой страницы, возникает исключение со статусом
STATUS_ACCESS_VIOLATION, и при отсутствии обработчика процесс завершается.DEP не является исчерпывающей защитой от всех эксплойтов — это один из инструментов в многоуровневой модели безопасности.
Политики DEP
DEP настраивается при загрузке системы через параметры boot configuration data (политика no-execute page protection). Приложение может узнать текущую политику через
GetSystemDEPPolicy и при определённых условиях изменить свою собственную через SetProcessDEPPolicy.| Политика | Поведение |
|---|---|
| AlwaysOff | DEP полностью отключён |
| AlwaysOn | DEP включён для всех процессов |
| OptIn | DEP активен только для системных процессов и служб; приложения могут запросить защиту |
| OptOut | DEP активен для всех процессов, кроме явно исключённых |
Какие области защищены
При активной политике DEP следующие области памяти помечаются как неисполняемые:
- Стек потока
- Куча по умолчанию процесса
- Пулы памяти
- Любые страницы, выделенные без флага
PAGE_EXECUTE*
Выделения через
malloc и HeapAlloc всегда возвращают неисполняемую память. Если приложению нужно выполнить код из динамически выделенной области (например, JIT-компилятор), оно должно явно запросить права на выполнение при выделении через VirtualAlloc с флагами PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE или PAGE_EXECUTE_WRITECOPY.Рекомендации для разработчиков
Microsoft рекомендует после генерации исполняемого кода снять права на запись через
VirtualProtect, оставив только PAGE_EXECUTE_READ. Это минимизирует окно для атак типа write-then-execute. Также рекомендуется располагать исполняемые области в нижней части адресного пространства, а неисполняемые — выше, чтобы переполнение буфера в данных не достигало кода. Чем меньше исполняемых страниц в процессе, тем меньше поверхность атаки.NX в Linux: механизм и управление
В Linux ядро использует NX bit для разделения прав доступа к страницам. По умолчанию стек и куча пользовательских процессов помечаются как неисполняемые. Управление осуществляется через флаги
PROT_EXEC, PROT_READ, PROT_WRITE при вызове mmap и через mprotect для изменения прав уже выделенных страниц.Принцип W^X (Write XOR Execute) — страница не должна быть одновременно доступна для записи и выполнения — является базовым ориентиром при проектировании подсистем ядра и пользовательских приложений. Некоторые дистрибутивы исторически использовали дополнительные патчи (exec-shield, PaX) для расширения защиты на сегменты данных и усиления политик, однако в современных ядрах основная функциональность обеспечивается самим NX bit и стандартными механизмами
mmap/mprotect.Проверка поддержки NX процессором
Флаг
nx в выводе /proc/cpuinfo указывает на аппаратную поддержку:
Bash:
grep -m1 '^flags' /proc/cpuinfo | grep -o '\bnx\b'
Если вывод содержит
nx, процессор поддерживает запрет выполнения. В 32-битных системах для активации NX необходимо ядро с поддержкой PAE.Проверка статуса NX для бинарного файла
Утилита
readelf позволяет проверить, помечен ли бинарный файл как совместимый с NX (отсутствие исполняемого стека):
Bash:
readelf -lW /usr/bin/ls | grep GNU_STACK
Вывод вида
GNU_STACK ... RW означает, что стек не исполняемый. Флаг E в поле прав (RWE) указывает на исполняемый стек — это ослабляет защиту и обычно является ошибкой сборки.Права на страницы работающего процесса
Файл
/proc/<pid>/maps показывает распределение виртуальной памяти процесса с правами доступа. Как правило, страницы стека имеют права rw-p (чтение, запись, приватные, без выполнения), что подтверждает работу NX:
Bash:
cat /proc/self/maps | grep stack
Взаимодействие с эксплуатацией уязвимостей
NX/DEP блокирует простейший сценарий атаки: запись shellcode в буфер и переход на него. Однако это не делает систему неуязвимой. Атакующие разработали техники обхода:
Return-Oriented Programming (ROP)
Вместо внедрения нового кода атакующий переиспользует уже существующие инструкции (гаджеты) из исполняемых сегментов программы и библиотек. ROP-цепочка строится из последовательности адресов возврата, каждый из которых указывает на полезную последовательность инструкций, завершающуюся
ret. NX не защищает от ROP, потому что код выполняется из легитимных исполняемых страниц.Ret2libc
Частный случай ROP: вместо произвольных гаджетов атакующий вызывает функции стандартной библиотеки (например,
system()), передавая нужные аргументы через стек. Это позволяет обойтись без внедрения собственного кода.JIT-spraying
Если приложение использует JIT-компиляцию (браузеры, виртуальные машины), атакующий может внедрить вредоносный байткод, который JIT скомпилирует в исполняемую память. DEP здесь не помогает, потому что память выделена с правами выполнения легально.
Совместимость и типичные проблемы
DEP может нарушать работу приложений, которые:
- Генерируют код динамически без явного запроса прав на выполнение
- Содержат исполняемый код в секциях данных (thunks, trampolines)
- Используют старые версии библиотек, не учитывающих NX
Например, приложения, написанные с использованием Active Template Library (ATL) версии 7.1 и ранее, могут пытаться выполнить код на страницах, помеченных как неисполняемые, что приводит к NX fault и завершению процесса.
Для PE-файлов, содержащих код в секции данных, необходимо добавить атрибут
IMAGE_SCN_MEM_EXECUTE в поле Characteristics заголовка соответствующей секции. Альтернатива — перенести код в секцию .text.В Linux аналогичная проблема возникает, если бинарный файл собран с исполняемым стеком (флаг
PT_GNU_STACK с правами RWE). Линковщик по умолчанию делает стек неисполняемым, но некоторые ассемблерные вставки или устаревшие объектные файлы могут переопределить это поведение.Диагностика падения из-за DEP в Windows
При отладке приложения, завершающегося из-за DEP, в отладчике будет видно исключение
STATUS_ACCESS_VIOLATION (код 0xC0000005). Дополнительный флаг в записи исключения указывает, что нарушение вызвано именно попыткой выполнения, а не чтения или записи. В диспетчере задач можно включить столбец «DEP» на вкладке «Процессы», чтобы увидеть, активна ли защита для конкретного процесса.Ограничения NX/DEP
NX/DEP — один из слоёв защиты, а не полное решение. Оно не защищает от:
- ROP и ret2libc (код выполняется из легитимных страниц)
- Атак на логику приложения
- Уязвимостей, не связанных с выполнением кода из данных (use-after-free с переиспользованием объектов, type confusion)
- JIT-эксплойтов
Для полноценной защиты NX комбинируется с другими механизмами: ASLR (рандомизация адресного пространства), Stack Canaries (обнаружение переполнения стека), CFG (Control Flow Guard в Windows), CFI (Control Flow Integrity в компиляторах), SEHOP (защита структурированных обработчиков исключений). Каждый из этих механизмов закрывает определённый класс атак, который NX оставить открытым.
