Поделиться через


Реализация совместимого кода целостности памяти

В этом разделе описывается, как реализовать совместимый код целостности памяти.

Примечание.

Целостность памяти иногда называется целостностью кода, защищенной гипервизором (HVCI) или целостностью кода, обеспечиваемой гипервизором, и первоначально была выпущена в составе Device Guard. Device Guard больше не используется, кроме того, чтобы найти параметры целостности памяти и VBS в групповой политике или реестре Windows.

Чтобы реализовать совместимый код, убедитесь, что код драйвера выполняет следующие действия:

  • По умолчанию выбирает NX
  • Использует NX API-интерфейсы и флаги для выделения памяти (NonPagedPoolNx)
  • Не использует разделы, которые являются записываемыми и исполняемыми
  • Не пытается напрямую изменить исполняемую системную память
  • Не использует динамический код в ядре
  • Не загружает файлы данных как исполняемые
  • Выравнивание секций кратно 0x1000 (PAGE_SIZE). Например, DRIVER_ALIGNMENT=0x1000

В следующем списке DDIs, которые не зарезервированы для использования системой, могут оказаться затронутыми:

Имя DDI
ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithQuotaTag
ExAllocatePoolWithTag
ExAllocatePoolWithTagPriority
ExInitializeNPagedLookasideList
ExInitializeLookasideListEx
MmAllocateContiguousMemory
MmAllocateContiguousMemorySpecifyCache
MmAllocateContiguousMemorySpecifyCacheNode
MmAllocateContiguousNodeMemory
MmCopyMemory
MmMapIoSpace
MmMapLockedPages
MmMapLockedPagesSpecifyCache
MmProtectMdlSystemAddress
ZwAllocateVirtualMemory
ZwCreateSection
ZwMapViewOfSection
NtCreateSection
NtMapViewOfSection
ClfsCreateMarshallingArea
NDIS
NdisAllocateMemoryWithTagPriority
Хранение
StorPortGetDataInBufferSystemAddress
StorPortGetSystemAddress
ChangerClassAllocatePool
Дисплей
DxgkCbMapMemory
VideoPortAllocatePool
Минипорт аудио
IMiniportDMus::NewStream
IMiniportMidi::NewStream
IMiniportWaveCyclic::NewStream
IPortWavePci::NewMasterDmaChannel
IMiniportWavePci::NewStream
Класс аудиопорта
PcNewDmaChannel
PcNewResourceList
PcNewResourceSublist
IFS
FltAllocatePoolAlignedWithTag
FltAllocateContext
WDF
WdfLookasideListCreate
WdfMemoryCreate
WdfDeviceAllocAndQueryProperty
WdfDeviceAllocAndQueryPropertyEx
WdfFdoInitAllocAndQueryProperty
WdfFdoInitAllocAndQueryPropertyEx
WdfIoTargetAllocAndQueryTargetProperty
WdfRegistryQueryMemory

Использование тестов целостности кода в HLK для проверки совместимости драйверов целостности памяти

Дополнительные сведения о проверке безопасности основных системных принципов см. в тесте на готовность целостности кода HyperVisor и целостности памяти и VBS.

Дополнительные сведения о тесте на основные характеристики устройства см. в тестах Device.DevFund.

Используйте следующую таблицу, чтобы интерпретировать выходные данные и определить, какие изменения кода драйвера необходимы для исправления различных типов несовместимости целостности памяти.

Предупреждения Искупление

Тип пула выполнения

Вызывающий объект указал тип исполняемого пула. Вызов функции выделения памяти, которая запрашивает исполняемую память.

Убедитесь, что все типы пулов содержат неисполняемый флаг NX.

Запустить защиту страниц

Вызывающий объект указал защиту исполняемой страницы.

Укажите маску защиты страницы "без выполнения".

Выполнить сопоставление страниц

Вызывающий объект указал сопоставление исполнимого дескриптора памяти (MDL).

Убедитесь, что маска, используемая, содержит MdlMappingNoExecute. Дополнительные сведения см. в разделе MmGetSystemAddressForMdlSafe

Раздел Execute-Write

Изображение содержит исполняемый и записываемый раздел.

Ошибки выравнивания разделов

Изображение содержит раздел, который не выровнен по страницам.

Выравнивание разделов должно быть кратным 0x1000 (PAGE_SIZE). Например, DRIVER_ALIGNMENT=0x1000

IAT в разделе исполняемых файлов

Таблица адресов импорта (IAT) не должна быть исполняемым разделом памяти.

Эта проблема возникает, когда IAT находится только в разделе памяти для чтения и выполнения (RX). Это означает, что ОС не сможет записать данные в IAT, чтобы установить правильные адреса для размещения упомянутой библиотеки DLL.

Одним из способов, как это может произойти, является использование опции /MERGE (Объединение разделов) при связывании кода. Например, если rdata (инициализированные данные только для чтения) объединяется с текстовыми данными (исполняемым кодом), возможно, что IAT может оказаться в исполняемом разделе памяти.


Неподдерживаемые релоки

В Windows 10 с версии 1507 по версию 1607 из-за использования рандомизации макета адресного пространства (ASLR) может возникнуть проблема с выравниванием адресов и перемещением памяти. Операционная система должна переместить адрес, из которого компоновщик задает базовый адрес по умолчанию в фактическое расположение, назначенное ASLR. Это перемещение данных не может быть привязано к границе страницы. Например, рассмотрим 64-разрядное значение адреса, которое начинается с смещения 0x3FFC на странице. Это значение адреса переходит на следующую страницу, при смещении 0x0003. Этот тип перекрывающихся перелок не поддерживается до Windows 10 версии 1703.

Эта ситуация может произойти, когда инициализатор переменной типа глобальной структуры имеет неправильно выровненный указатель на другой глобальный объект, расположенный таким образом, что компоновщик не может переместить переменную, чтобы избежать перемещения через границу. Компоновщик попытается переместить переменную, но существуют ситуации, когда это может быть невозможно сделать (например, с большими неправильными структурами или большими массивами несогласованных структур). При необходимости модули должны быть собраны с помощью параметра /Gy (COMDAT), чтобы компоновщик мог максимально выровнять код модуля.

#include <pshpack1.h>

typedef struct _BAD_STRUCT {
      USHORT Value;
      CONST CHAR *String;
} BAD_STRUCT, * PBAD_STRUCT;

#include <poppack.h>

#define BAD_INITIALIZER0 { 0, "BAD_STRING" },
#define BAD_INITIALIZER1 \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      

#define BAD_INITIALIZER2 \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      

#define BAD_INITIALIZER3 \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      

#define BAD_INITIALIZER4 \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      

BAD_STRUCT MayHaveStraddleRelocations[4096] = { // as a global variable
      BAD_INITIALIZER4
};

Существуют и другие ситуации, связанные с использованием кода сборщика, где также может возникнуть эта проблема.


Целостность кода проверяющего драйвера

Используйте флаг целостности кода проверяющего драйвера (0x02000000), чтобы включить дополнительные проверки, проверяющие соответствие этой функции. Чтобы включить это из командной строки, используйте следующую команду.

verifier.exe /flags 0x02000000 /driver <driver.sys>

Чтобы выбрать этот параметр при использовании графического интерфейса проверки, выберите Создать настраиваемые параметры (для разработчиков кода), выберите Далее, а затем выберите Проверки целостности кода.

Вы можете использовать параметр командной строки /query средства проверки для отображения информации о текущем состоянии проверки драйвера.

verifier /query

См. также

Контрольный список безопасности водителя