Sdílet prostřednictvím


Implementace kódu kompatibilního s integritou paměti

Tato část popisuje, jak implementovat kód kompatibilní s integritou paměti.

Poznámka:

Integrita paměti se někdy označuje jako hypervisorem chráněná integrita kódu (HVCI) nebo hypervisorem vynucená integrita kódua původně byla uvedena jako součást Device Guard. Device Guard se už nepoužívá s výjimkou vyhledání integrity paměti a nastavení VBS v zásadách skupiny nebo registru Windows.

Pokud chcete implementovat kompatibilní kód, ujistěte se, že kód ovladače provede následující:

  • NX je ve výchozím nastavení povolen.
  • Používá NX API a příznaky pro přidělení paměti (NonPagedPoolNx).
  • Nepoužívá oddíly, které jsou zapisovatelné i spustitelné.
  • Nepokoušá se přímo upravit paměť spustitelného systému.
  • Nepoužívá dynamický kód v jádru.
  • Nenačítá datové soubory jako spustitelné soubory.
  • Zarovnání oddílu je násobkem 0x1000 (PAGE_SIZE). Např. DRIVER_ALIGNMENT=0x1000

Může to mít vliv na následující seznam DDI, které nejsou vyhrazené pro použití systému:

Název 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
Skladování
StorPortGetDataInBufferSystemAddress
StorPortGetSystemAddress
ChangerClassAllocatePool
Displej
DxgkCbMapMemory
VideoPortAllocatePool
Miniport zvuku
IMiniportDMus::NewStream
IMiniportMidi::NewStream
IMiniportWaveCyclic::NewStream
IPortWavePci::NewMasterDmaChannel
IMiniportWavePci::NewStream
Třída zvukového portu
PcNewDmaChannel
PcNewResourceList
PcNewResourceSublist
IFS
FltAllocatePoolAlignedWithTag
FltAllocateContext
WDF
WdfLookasideListCreate
WdfMemoryCreate
WdfDeviceAllocAndQueryProperty
WdfDeviceAllocAndQueryPropertyEx
WdfFdoInitAllocAndQueryProperty
WdfFdoInitAllocAndQueryPropertyEx
WdfIoTargetAllocAndQueryTargetProperty
WdfRegistryQueryMemory

Použití testů integrity kódu v HLK k otestování kompatibility ovladače integrity paměti

Další informace o základním testu bezpečnosti systému naleznete viz HyperVisor Code Integrity Readiness Test a Integrita paměti a VBS.

Další informace o základním testu souvisejícím se zařízením naleznete v tématu Device.DevFund testy.

Pomocí následující tabulky interpretujte výstup a zjistěte, jaké změny kódu ovladače jsou potřeba k opravě různých typů nekompatibility integrity paměti.

Upozornění Vykoupení

Provedení typu fondu

Volající zadal typ spustitelného fondu. Volání funkce přidělování paměti, která vyžaduje spustitelné paměti.

Ujistěte se, že všechny typy fondů obsahují příznak NX, který není spustitelný.

Spustit ochranu stránky

Volající zadal ochranu pro spustitelnou stránku.

Zadejte masku ochrany stránky s nastavením zákazu provádění.

Spustit mapování stránek

Volající zadal mapování seznamu popisů spustitelné paměti (MDL).

Ujistěte se, že použitá maska obsahuje MdlMappingNoExecute. Další informace najdete v tématu MmGetSystemAddressForMdlSafe

oddíl Execute-Write

Soubor obsahuje spustitelnou a zapisovatelnou sekci.

Selhání zarovnání sekcí

Obrázek obsahuje část, která není zarovnaná se stránkou.

Zarovnání sekce musí být násobkem 0x1000 (PAGE_SIZE). Např. DRIVER_ALIGNMENT=0x1000

IAT v spustitelné sekci

Tabulka adres importu (IAT) by neměla být spustitelná část paměti.

K tomuto problému dochází, když je IAT umístěna v části paměti, která je určena pouze pro čtení a spuštění (RX). To znamená, že operační systém nebude moct zapisovat do IAT, aby nastavil správné adresy pro odkazovanou knihovnu DLL.

Jedním ze způsobů, jak k tomu může dojít, je použití možnosti /MERGE (Kombinovat oddíly) v propojení kódu. Pokud je například .rdata (inicializovaná data jen pro čtení) sloučena s daty .text (spustitelný kód), je možné, že IAT může skončit ve spustitelné části paměti.


Nepodporované relokace

Ve Windows 10 verze 1507 až Windows 10 verze 1607 může dojít kvůli použití randomizace rozložení adresního prostoru (ASLR) k problému s zarovnáním adresy a přemístěním paměti. Operační systém musí přemístit adresu, ze které linker nastavil výchozí základní adresu na skutečné umístění přiřazené službou ASLR. Toto přemístění nemůže překlenout mez stránky. Představte si například 64bitovou hodnotu adresy, která má počátek na posunu 0x3FFC na stránce. Hodnota adresy se překrývá na další stránku na posunu 0x0003. Tento typ překrývajících se relokací není podporován před Windows 10, verze 1703.

K této situaci může dojít, když má inicializátor proměnné globální struktury nesprávně zarovnaný ukazatel na jinou globální proměnnou, která je uspořádána tak, že linker nemůže přesunout proměnnou, aby se zabránilo problémovému přemístění. Linker se pokusí přesunout proměnnou, ale jsou situace, kdy to nemusí být možné provést (například u velkých špatně zarovnaných struktur nebo velkých polí špatně zarovnaných struktur). V případě potřeby by měly být moduly sestaveny pomocí /Gy (COMDAT) volby, aby linker mohl co nejvíce zarovnat kód modulu.

#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
};

Existují i další situace týkající se použití kódu assembleru, kdy k tomuto problému může také dojít.


Integrita kódu verifieru ovladače

Pomocí příznaku integrity kódu Verifieru ovladače (0x02000000) povolte dodatečné kontroly, které ověřují dodržování této funkce. Pokud to chcete povolit z příkazového řádku, použijte následující příkaz.

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

Pokud chcete tuto možnost zvolit, pokud používáte grafické uživatelské rozhraní ověřovatele, vyberte Vytvořit vlastní nastavení (pro vývojáře kódu), vyberte Dalšía pak vyberte kontroly integrity kódu.

K zobrazení aktuálních informací o ověřovači ovladače můžete použít příkazový řádek s možností /query.

verifier /query

Viz také

kontrolní seznam zabezpečení ovladače