Compatibilité des pilotes avec l’intégrité de la mémoire et VBS

L’intégrité de la mémoire est une fonctionnalité de sécurité basée sur la virtualisation (VBS) disponible dans Windows 10, Windows 11 et Windows Server 2016 et versions ultérieures. L’intégrité de la mémoire et VBS améliorent le modèle de menace de Windows et fournissent des protections plus fortes contre les programmes malveillants qui tentent d’exploiter le noyau Windows. VBS utilise l’hyperviseur Windows pour créer un environnement virtuel isolé qui devient la racine de confiance du système d’exploitation qui suppose que le noyau peut être compromis. L’intégrité de la mémoire est un composant essentiel qui protège et renforce Windows en exécutant l’intégrité du code en mode noyau dans l’environnement virtuel isolé de VBS. L’intégrité de la mémoire limite également les allocations de mémoire du noyau qui peuvent être utilisées pour compromettre le système, en veillant à ce que les pages mémoire du noyau ne soient rendues exécutables qu’après avoir passé des vérifications d’intégrité du code dans l’environnement d’exécution sécurisé, et que les pages exécutables elles-mêmes ne sont jamais accessibles en écriture.

Remarque

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ée à l’hyperviseur, et a été initialement publiée 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.

L’intégrité de la mémoire est activée par défaut sur propre installations de Windows 10 en mode S et Windows 11 sur le matériel compatible, comme décrit dans Activation de l’intégrité de la mémoire. Sur d’autres systèmes qui ne répondent pas aux exigences d’activation automatique de l’intégrité de la mémoire, les clients peuvent choisir d’utiliser l’une des méthodes décrites dans Comment activer l’intégrité de la mémoire.

Compatibilité des applications

Bien que la compatibilité avec l’intégrité de la mémoire soit requise pour tous les pilotes depuis la mise à jour anniversaire Windows 10 (1607), certains pilotes d’applications et de périphériques matériels peuvent toujours être incompatibles. Cette incompatibilité peut entraîner un dysfonctionnement des appareils ou des logiciels et, dans de rares cas, peut entraîner un échec de démarrage (écran bleu). De tels problèmes peuvent se produire après l’activation de la protection de l’intégrité de la mémoire ou pendant le processus d’activation lui-même. Si vous êtes développeur d’applications et souhaitez vérifier que vos pilotes et packages logiciels sont compatibles avec l’intégrité de la mémoire, procédez comme suit.

Voici quelques exemples où nous avons observé des incompatibilités avec l’intégrité de la mémoire :

  • Solutions anti-triche avec le jeu
  • Méthodes d’entrée tierces
  • Protection par mot de passe bancaire tiers

Nous avons travaillé dur pour atténuer les expériences impactées. Ainsi, si une incompatibilité existe pour un pilote critique au démarrage, la protection de l’intégrité de la mémoire sera désactivée en mode silencieux si elle avait été activée automatiquement. Si vous rencontrez des incompatibilités avec d’autres applications, nous vous conseillons de case activée pour les mises à jour de l’application spécifique et de la version qui rencontrent le problème avant de désactiver la protection de l’intégrité de la mémoire.

Comment créer des pilotes compatibles

Étant donné que les pages et les sections mémoire ne peuvent jamais être accessibles en écriture et exécutables, la première étape consiste à garantir une séparation claire des données et du code et à ne pas tenter de modifier directement les pages de code.

  • S’inscrire à NX par défaut
  • Utiliser des API/indicateurs NX pour l’allocation de mémoire - NonPagedPoolNx
  • N’utilisez pas de sections accessibles en écriture et exécutables
  • N’essayez pas de modifier directement la mémoire système exécutable
  • N’utilisez pas de code dynamique dans le noyau
  • Ne pas charger les fichiers de données en tant qu’exécutables
  • L’alignement de section doit être un multiple de 0x1000 (PAGE_SIZE). Par exemple, DRIVER_ALIGNMENT=0x1000

Utilisez la dernière version de WDK et de Visual Studio pour produire des pilotes compatibles lors de l’utilisation des paramètres par défaut.

Comment vérifier la compatibilité des pilotes avec l’intégrité de la mémoire

Il existe trois étapes pour vérifier la compatibilité des pilotes :

  1. Utilisez Driver Verifier (voir la section ci-dessous) avec les vérifications de compatibilité de l’intégrité du code activées.
  2. Testez le pilote sur un système avec l’intégrité de la mémoire activée.
  3. Exécutez le test de préparation de l’intégrité du code HyperVisor dans windows HLK.

Vérifications de compatibilité du vérificateur de pilotes

Driver Verifier a un indicateur d’option Intégrité du code (0x02000000) pour activer des vérifications supplémentaires qui valident la conformité avec l’intégrité de la mémoire. 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, choisissez Créer des paramètres personnalisés (pour les développeurs de code),suivant , puis sélectionnez Vérifications d’intégrité du code.

Pour la réussite, il n’y a pas de sortie. Voici un exemple de sortie d’échec.

Driver Verifier: Enabled for DvCi.sys, flags 0x2000000, build 16299, key o4Dbg8OVJqaBYlqWQ2QvRH

\*\*\*\*\*\*\*\*\*\*\* Verifier Detected a Code Integrity Issue \*\*\*\*\*\*\*\*\*\*\*\*

\*\* The caller 0xFFFFF8094B9852F0 specified an executable page protection 0x40.

\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

\*\*\* Verifier assertion failed \*\*\*

(B)reak, (I)gnore, (W)arn only, (R)emove assert? B

Tester le pilote avec l’intégrité de la mémoire activée

Bien que Windows active l’intégrité de la mémoire par défaut pour la plupart des systèmes, plusieurs raisons peuvent empêcher cela. Pour activer l’intégrité de la mémoire, consultez Comment activer l’intégrité de la mémoire. Ensuite, testez les fonctionnalités de votre pilote. Veillez à exercer tous les chemins de code dans votre pilote pour vous assurer que votre pilote n’effectue pas d’opérations incompatibles avec l’intégrité de la mémoire au moment de l’exécution.

Test HLK (Bureau et serveur)

Le test HLK HyperVisor Code Integrity Readiness Test doit réussir pour que les pilotes soient approuvés pour la signature Microsoft. Les pilotes compatibles avec l’intégrité de la mémoire sont requis pour les éditions Desktop et Server. Le test HLK est un test de base écrit pour s’assurer que les pilotes compatibles avec l’intégrité de la mémoire sont correctement chargés et exécutés par le système d’exploitation.

Bien que le simple fait de réussir le test HLK soit suffisant pour une signature Microsoft pour le pilote, nous vous recommandons vivement d’effectuer des tests fonctionnels approfondis avec l’intégrité de la mémoire activée. Par exemple, il peut y avoir des allocations de mémoire mal codées violant les protections NX qui provoquent des échecs qui ne seraient pas interceptés par le test. L’auteur du pilote doit tester minutieusement le pilote tout en gardant l’intégrité de la mémoire activée.

Pendant le développement du pilote et pendant les tests HLK, l’intégrité de la mémoire peut devoir être désactivée, car cela peut empêcher le chargement du pilote.

Le test de préparation de l’intégrité du code de l’hyperviseur HLK est requis dans le cadre de l’AQ Windows Server Assurance et les indicateurs permettant d’activer les vérifications d’intégrité du code sont également définis lors de l’activation du vérificateur de pilote lors d’autres tests HLK.

Foire aux questions

Qu’en est-il des pilotes existants ? Dois-je recréer ces pilotes pour qu’ils fonctionnent avec Windows 10 ?

Cela dépend. De nombreux pilotes seront déjà compatibles. Si vous utilisez des paramètres standard avec les anciennes versions de WDK et Visual Studio, un problème connu est que la section INIT est marquée comme RWX. Dans Windows 10, toutefois, le W est automatiquement supprimé. Ainsi, s’il s’agit du seul problème, le pilote sera compatible.

Comment faire vérifier que l’intégrité de la mémoire est activée ?

La méthode la plus simple consiste à exécuter l’application Informations système (msinfo32). Recherchez la ligne suivante : « Services de sécurité basés sur la virtualisation en cours d’exécution ». Il doit signaler : « Intégrité du code appliquée à l’hyperviseur ». Il existe également une interface WMI pour la vérification à l’aide des outils de gestion. Consultez Valider les fonctionnalités VBS et d’intégrité de la mémoire activées.

L’intégrité de la mémoire peut également être vérifiée dans l’application Sécurité Windows dans Paramètres>Mettre à jour & Sécurité> Sécurité Windows Sécurité>de l’appareil>Détails de l’isolation> principaleIntégrité de la mémoire. Pour plus d’informations, consultez KB4096339.

Puis-je vérifier que l’intégrité de la mémoire est activée par programmation à partir du noyau afin de modifier le comportement du pilote ?

Oui, vous pouvez utiliser NtQuerySystemInformation : https://msdn.microsoft.com/library/windows/desktop/ms724509(v=vs.85).aspx

La structure SYSTEM_CODEINTEGRITY_INFORMATION a une valeur 0x400 exposée, ce qui indique que l’intégrité de la mémoire est activée.

Comment faire résoudre les problèmes de compatibilité ?

En plus de vérifier qu’il n’y a pas de pages W+X et que les sections de pilote sont alignées correctement comme mentionné ci-dessus, le problème le plus probable sera une allocation de mémoire incorrecte. Les informations sur les avertissements d’analyse du code liés à l’allocation de mémoire émis sont disponibles sur MSDN sur la page suivante :

Avertissements de l'analyse du code pour les pilotes

Les liens MSDN suivants montrent quelques exemples d’API couramment utilisées qui entraînent l’allocation de mémoire exécutable, ainsi que des exemples de correctifs :

Utilisez le tableau suivant pour interpréter la sortie afin de déterminer les modifications de code de pilote nécessaires pour résoudre les différents types d’incompatibilités HVCI.

Avertissement Résolution
Type de pool d’exécution 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 « sans exécution ».
Exécuter le mappage de page 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
Relocs non pris en charge Dans Windows 10 version 1507 à la 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 tableaux de 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.

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.

Quelles API sont potentiellement affectées ?

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

   
Nom de l’API Description
ExAllocatePool https://msdn.microsoft.com/library/windows/hardware/ff544501(v=vs.85).aspx
ExAllocatePoolWithQuota https://msdn.microsoft.com/library/windows/hardware/ff544506(v=vs.85).aspx
ExAllocatePoolWithQuotaTag https://msdn.microsoft.com/library/windows/hardware/ff544513(v=vs.85).aspx
ExAllocatePoolWithTag https://msdn.microsoft.com/library/windows/hardware/ff544520(v=vs.85).aspx
ExAllocatePoolWithTagPriority https://msdn.microsoft.com/library/windows/hardware/ff544523(v=vs.85).aspx
ExInitializeNPagedLookasideList https://msdn.microsoft.com/library/windows/hardware/ff545301(v=vs.85).aspx
ExInitializeLookasideListEx https://msdn.microsoft.com/library/windows/hardware/ff545298(v=vs.85).aspx
MmAllocateContiguousMemory https://msdn.microsoft.com/library/windows/hardware/ff554460(v=vs.85).aspx
MmAllocateContiguousMemorySpecifyCache https://msdn.microsoft.com/library/windows/hardware/ff554464(v=vs.85).aspx
MmAllocateContiguousMemorySpecifyCacheNode https://msdn.microsoft.com/library/windows/hardware/ff554464(v=vs.85).aspx
MmAllocateContiguousNodeMemory https://msdn.microsoft.com/library/windows/hardware/jj602795(v=vs.85).aspx
MmCopyMemory https://msdn.microsoft.com/library/windows/hardware/dn342884(v=vs.85).aspx
MmMapIoSpace https://msdn.microsoft.com/library/windows/hardware/ff554618(v=vs.85).aspx
MmMapLockedPages https://msdn.microsoft.com/library/windows/hardware/ff554622(v=vs.85).aspx
MmMapLockedPagesSpecifyCache https://msdn.microsoft.com/library/windows/hardware/ff554629(v=vs.85).aspx
MmProtectMdlSystemAddress https://msdn.microsoft.com/library/windows/hardware/ff554670(v=vs.85).aspx
ZwAllocateVirtualMemory https://msdn.microsoft.com/library/windows/hardware/ff566416(v=vs.85).aspx
ZwCreateSection https://msdn.microsoft.com/library/windows/hardware/ff566428(v=vs.85).aspx
ZwMapViewOfSection https://msdn.microsoft.com/library/windows/hardware/ff566481(v=vs.85).aspx
NtCreateSection https://msdn.microsoft.com/library/windows/hardware/ff556473(v=vs.85).aspx
NtMapViewOfSection https://msdn.microsoft.com/library/windows/hardware/ff556551(v=vs.85).aspx
StorPortGetDataInBufferSystemAddress https://msdn.microsoft.com/library/windows/hardware/jj553720(v=vs.85).aspx
StorPortGetSystemAddress https://msdn.microsoft.com/library/windows/hardware/ff567100(v=vs.85).aspx
DxgkCbMapMemory https://msdn.microsoft.com/library/windows/hardware/ff559533(v=vs.85).aspx
IMiniportDMus::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536701(v=vs.85).aspx
FltAllocatePoolAlignedWithTag https://msdn.microsoft.com/library/windows/hardware/ff541762(v=vs.85).aspx
FltAllocateContext https://msdn.microsoft.com/library/windows/hardware/ff541710(v=vs.85).aspx
ChangerClassAllocatePool https://msdn.microsoft.com/library/windows/hardware/ff551402(v=vs.85).aspx
IMiniportMidi::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536710(v=vs.85).aspx
IMiniportWaveCyclic::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536723(v=vs.85).aspx
IPortWavePci::NewMasterDmaChannel https://msdn.microsoft.com/library/windows/hardware/ff536916(v=vs.85).aspx
IMiniportWavePci::NewStream https://msdn.microsoft.com/library/windows/hardware/ff536735(v=vs.85).aspx
PcNewDmaChannel https://msdn.microsoft.com/library/windows/hardware/ff537712(v=vs.85).aspx
PcNewResourceList https://msdn.microsoft.com/library/windows/hardware/ff537717(v=vs.85).aspx
PcNewResourceSublist https://msdn.microsoft.com/library/windows/hardware/ff537718(v=vs.85).aspx
VideoPortAllocatePool https://msdn.microsoft.com/library/windows/hardware/ff570180(v=vs.85).aspx
ClfsCreateMarshallingArea https://msdn.microsoft.com/library/windows/hardware/ff541520(v=vs.85).aspx
WdfLookasideListCreate https://msdn.microsoft.com/library/windows/hardware/ff548694(v=vs.85).aspx
WdfMemoryCreate https://msdn.microsoft.com/library/windows/hardware/ff548706(v=vs.85).aspx
WdfDeviceAllocAndQueryProperty https://msdn.microsoft.com/library/windows/hardware/ff545882(v=vs.85).aspx
WdfDeviceAllocAndQueryPropertyEx https://msdn.microsoft.com/library/windows/hardware/dn265599(v=vs.85).aspx
WdfFdoInitAllocAndQueryProperty https://msdn.microsoft.com/library/windows/hardware/ff547239(v=vs.85).aspx
WdfFdoInitAllocAndQueryPropertyEx https://msdn.microsoft.com/library/windows/hardware/dn265612(v=vs.85).aspx
WdfIoTargetAllocAndQueryTargetProperty https://msdn.microsoft.com/library/windows/hardware/ff548585(v=vs.85).aspx
WdfRegistryQueryMemory https://msdn.microsoft.com/library/windows/hardware/ff549920(v=vs.85).aspx
NdisAllocateMemory https://msdn.microsoft.com/library/windows/hardware/ff550762(v=vs.85).aspx