Во-вторых, у каждого процесса имеется индивидуальное закрытое адресное пространство, защищенное от доступа потоков других процессов. Исключение составляют те случаи, когда процесс разделяет какие- либо страницы с другими процессами или когда у другого процесса есть права на доступ к объекту «процесс» для чтения и/или записи, что позволяет ему использовать функции
В-третьих, кроме косвенной защиты, обеспечиваемой трансляцией виртуальных адресов в физические, все процессоры, поддерживаемые Windows, предоставляют ту или иную форму аппаратной защиты памяти (например доступ для чтения и записи, только для чтения и т. д.); конкретные механизмы такой защиты зависят от архитектуры процессора. Скажем, страницы кода в адресном пространстве процесса помечаются атрибутом «только для чтения», что защищает их от изменения пользовательскими потоками.
Атрибуты защиты памяти, определенные в Windows API, перечислены в таблице 7-3 (см. также документацию на функции
Наконец, совместно используемые объекты «раздел» имеют стандартные для Windows списки контроля доступа (access control lists, ACL), проверяемые при попытках процессов открыть эти объекты. Таким образом, доступ к разделяемой памяти ограничен кругом процессов с соответствующими правами. Когда поток создает раздел для проецирования файла, в этом принимает участие и подсистема защиты. Для создания раздела поток должен иметь права хотя бы на чтение нижележащего объекта «файл», иначе операция закончится неудачно.
После успешного открытия описателя раздела действия потока все равно зависят от описанных выше атрибутов защиты, реализуемых диспетчером памяти на основе аппаратной поддержки. Поток может менять атрибуты защиты виртуальных страниц раздела (на уровне отдельных страниц), если это не противоречит разрешениям, указанным в ACL для данного раздела. Так, диспетчер памяти позволит потоку сменить атрибут страниц общего раздела «только для чтения» на «копирование при записи», но запретит его изменение на атрибут «для чтения и записи». Копирование при записи разрешается потому, что не влияет на другие процессы, тоже использующие эти данные.
Все эти механизмы защиты памяти вносят свой вклад в надежность, стабильность и устойчивость Windows к ошибкам и сбоям приложений.
Хотя в API управления памятью в Windows всегда были определены биты защиты страницы, позволяющие указывать, может ли страница содержать исполняемый код, лишь с появлением Windows XP Service Pack 2 и Windows Server 2003 Service Pack 1 эта функциональность стала поддерживаться на процессорах с аппаратной защитой «запрет на выполнение», в том числе на всех процессорах AMD64 (AMD Athlon64, AMD Opteron), на некоторых чисто 32-разрядных процессорах AMD (отдельных AMD Sempron), на Intel IA64 и Intel Pentium 4 или Xeon с поддержкой EM64T (Intel Extended Memory 64 Technology).
Эта защита, также называемая предотвращением выполнения данных (data execution prevention, DEP), означает, что попытка передачи управления какой-либо инструкции на странице, помеченной атрибутом «запрет на выполнение», приведет к нарушению доступа к памяти. Благодаря этому блокируются попытки определенных типов вирусов воспользоваться ошибками в операционной системе, которые иначе позволили бы выполнить код, размещенный на странице данных. Попытка выполнить код на странице, помеченной атрибутом «запрет на выполнение», в режиме ядра вызывает крах системы с кодом ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY. Если такая же попытка предпринимается в пользовательском режиме, то генерируется исключение STATUS_ACCESS_VIOLATION (0xc0000005); оно доставляется потоку, в котором была эта недопустимая ссылка. Если процесс выделяет память, которая должна быть исполняемой, то при вызове функций, отвечающих за выделение памяти, он обязан явно указать для соответствующих страниц флаг PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE или PAGE_EXECUTE_WRITECOPY.
B б4-разрядных версиях Windows атрибут защиты «запрет на выполнение» всегда применяется ко всем б4-разрядным программам и драйверам устройств, и его нельзя отключить. Поддержка такой защиты для 32-разрядных программ зависит от конфигурационных параметров системы. B 64-разрядной Windows защита от выполнения применяется к стекам потоков (как режима ядра, так и пользовательского режима), к страницам пользовательского режима, не помеченным явно как исполняемые, к пулу подкачиваемой памяти ядра и к сеансовому пулу ядра (описание пулов памяти ядра см. в разделе «Системные пулы памяти»). Однако в 32-разрядной Windows защита от выполнения применяется только к стекам потоков и страницам пользовательского режима. Кроме того, когда в 32-разрядной Windows разрешена защита от выполнения, система автоматически загружается в PAE-режиме (переходя на использование РАЕ-ядра, Windows System32Ntkrnlpa.exe). Описание PAE см. в разделе «Physical Address Extension (PAE)».
Активизация защиты от выполнения для 32-разрядных программ зависит от ключа /NOEXECUTE= в Boot.ini. Эти настройки можно изменить и на вкладке Data Execution Prevention, которая открывается последовательным выбором My Computer, Properties, Advanced, Performance Settings (см. рис. 7-2.) Когда вы выбираете защиту от выполнения в диалоговом окне настройки DEP, файл Boot.ini модифицируется добавлением в него соответствующего ключа /NOEXECUTE. Список аргументов для этого ключа и их описание см. в таблице 7-4. 32-разрядные приложения, исключенные из защиты от выполнения, перечисляются в параметрах в разделе реестра HKLMSoftwareMicrosoftWindows NT CurrentVersion AppCompatFlagsLayers; при этом в качестве имени параметра используется полный путь к исполняемому файлу, а в качестве его значения – «DisableNXShowUI».
Рис. 7-2.
B Windows XP (в 64- и 32-разрядных версиях) защита от выполнения для 32-разрядных программ по умолчанию применяется только к базовым исполняемым образам операционной системы Windows (/NOEXECUTE=OPTIN), чтобы не нарушить работу 32-разрядных приложений, которые могут полагаться на выполнение кода в страницах, не помеченных как исполняемые. B Windows Server 2003 такая защита по умолчанию распространяется на все 32-разрядные приложения (/NOEXECUTE=OPTOUT).