Implémenter du code compatible avec l’intégrité de la mémoire

Cette section explique comment implémenter du code compatible avec l’intégrité de la mémoire.

Notes

L’intégrité de la mémoire est parfois appelée intégrité du code protégée par l’hyperviseur (HVCI) ou intégrité du code appliqué à l’hyperviseur, et a été publiée à l’origine dans le cadre de Device Guard. Device Guard n’est plus utilisé, sauf pour localiser l’intégrité de la mémoire et les paramètres VBS dans stratégie de groupe ou le Registre Windows.

Pour implémenter du code compatible, vérifiez que votre code de pilote effectue les opérations suivantes :

  • Opte pour NX par défaut
  • Utilise des API/indicateurs NX pour l’allocation de mémoire (NonPagedPoolNx)
  • N’utilise pas de sections qui sont à la fois accessibles en écriture et exécutables
  • Ne tente pas de modifier directement la mémoire système exécutable
  • N’utilise pas de code dynamique dans le noyau
  • Ne charge pas les fichiers de données comme exécutables
  • L’alignement de section est un multiple de 0x1000 (PAGE_SIZE). Par exemple, DRIVER_ALIGNMENT=0x1000

La liste suivante des DDIs qui ne sont pas réservés à l’utilisation du système peut être affectée :

Nom 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
Stockage
StorPortGetDataInBufferSystemAddress
StorPortGetSystemAddress
ChangerClassAllocatePool
Affichage
DxgkCbMapMemory
VideoPortAllocatePool
Audio Miniport
IMiniportDMus ::NewStream
IMiniportMidi ::NewStream
IMiniportWaveCyclic ::NewStream
IPortWavePci ::NewMasterDmaChannel
IMiniportWavePci ::NewStream
Classe de port audio
PcNewDmaChannel
PcNewResourceList
PcNewResourceSublist
IFS
FltAllocatePoolAlignedWithTag
FltAllocateContext
WDF
WdfLookasideListCreate
WdfMemoryCreate
WdfDeviceAllocAndQueryProperty
WdfDeviceAllocAndQueryPropertyEx
WdfFdoInitAllocAndQueryProperty
WdfFdoInitAllocAndQueryPropertyEx
WdfIoTargetAllocAndQueryTargetProperty
WdfRegistryQueryMemory

Utiliser les tests d’intégrité du code dans le HLK pour tester la compatibilité du pilote d’intégrité de la mémoire

Pour plus d’informations sur le test de sécurité de base du système associé, consultez Test de préparation de l’intégrité du code HyperVisor et Intégrité de la mémoire et VBS.

Pour plus d’informations sur le test de base de l’appareil associé, consultez Tests Device.DevFund.

Utilisez le tableau suivant pour interpréter la sortie et déterminer les modifications de code de pilote nécessaires pour corriger les différents types d’incompatibilités d’intégrité de la mémoire.

Avertissement Échange

Exécuter le type de pool

L’appelant a spécifié un type de pool exécutable. Appel d’une fonction d’allocation de mémoire qui demande de la mémoire exécutable.

Assurez-vous que tous les types de pool contiennent un indicateur NX non exécutable.

Exécuter la protection de page

L’appelant a spécifié une protection de page exécutable.

Spécifiez un masque de protection de page « no execute ».

Exécuter le mappage de pages

L’appelant a spécifié un mappage MDL (Liste de descripteurs de mémoire exécutable).

Assurez-vous que le masque utilisé contient MdlMappingNoExecute. Pour plus d’informations, consultez MmGetSystemAddressForMdlSafe

section Execute-Write

L’image contient une section exécutable et accessible en écriture.

Échecs d’alignement de section

L’image contient une section qui n’est pas alignée sur la page.

L’alignement de section doit être un multiple de 0x1000 (PAGE_SIZE). Par exemple, DRIVER_ALIGNMENT=0x1000

IAT dans la section Exécutable

La table d’adresses d’importation (IAT) ne doit pas être une section exécutable de la mémoire.

Ce problème se produit lorsque l’IAT se trouve dans une section lecture et exécution (RX) uniquement de la mémoire. Cela signifie que le système d’exploitation ne sera pas en mesure d’écrire dans l’IAT pour définir les adresses correctes pour l’emplacement de la DLL référencée.

Cela peut se produire lors de l’utilisation de l’option /MERGE (Combiner des sections) dans la liaison de code. Par exemple, si .rdata (données initialisées en lecture seule) est fusionné avec des données .text (code exécutable), il est possible que l’IAT se retrouve dans une section exécutable de mémoire.


Relocs non pris en charge

Dans Windows 10, version 1507 à Windows 10, version 1607, en raison de l’utilisation de la randomisation de la disposition de l’espace d’adressage (ASLR), un problème peut se produire avec l’alignement des adresses et le déplacement de la mémoire. Le système d’exploitation doit déplacer l’adresse à partir de laquelle l’éditeur de liens a défini son adresse de base par défaut vers l’emplacement réel attribué par ASLR. Ce déplacement ne peut pas chevaucher une limite de page. Par exemple, considérez une valeur d’adresse 64 bits qui commence au décalage 0x3FFC dans une page. Sa valeur d’adresse se chevauche sur la page suivante à décalage 0x0003. Ce type de relocs qui se chevauchent n’est pas pris en charge avant Windows 10, version 1703.

Cette situation peut se produire lorsqu’un initialiseur de variable de type struct global a un pointeur mal aligné vers un autre global, disposé de telle sorte que l’éditeur de liens ne peut pas déplacer la variable pour éviter le déplacement chevauchant. L’éditeur de liens tente de déplacer la variable, mais il existe des situations où il peut ne pas être en mesure de le faire (par exemple, avec de grands struct mal alignés ou de grands structs mal alignés). Le cas échéant, les modules doivent être assemblés à l’aide de l’option /Gy (COMDAT) pour permettre à l’éditeur de liens d’aligner le code du module autant que possible.

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

Il existe d’autres situations impliquant l’utilisation du code d’assembleur, où ce problème peut également se produire.


Intégrité du code du vérificateur de pilotes

Utilisez l’indicateur d’option d’intégrité du code driver verifier (0x02000000) pour activer des vérifications supplémentaires qui valident la conformité à cette fonctionnalité. Pour l’activer à partir de la ligne de commande, utilisez la commande suivante.

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

Pour choisir cette option si vous utilisez l’interface graphique graphique du vérificateur, sélectionnez Créer des paramètres personnalisés (pour les développeurs de code ), suivant, puis sélectionnez Vérifications d’intégrité du code.

Vous pouvez utiliser l’option de ligne de commande /query du vérificateur pour afficher les informations actuelles du vérificateur du pilote.

verifier /query

Voir aussi

Liste de contrôle de sécurité des pilotes