Implementieren von speicherintegritätskompatiblem Code

In diesem Abschnitt wird beschrieben, wie Sie mit der Speicherintegrität kompatiblen Code implementieren.

Hinweis

Die Speicherintegrität wird manchmal als hypervisorgeschützte Codeintegrität (Hypervisor-Protected Code Integrity, HVCI) oder durch Hypervisor erzwungene Codeintegrität bezeichnet und wurde ursprünglich als Teil von Device Guard veröffentlicht. Device Guard wird nicht mehr verwendet, außer zum Suchen nach Speicherintegritäts- und VBS-Einstellungen in Gruppenrichtlinie oder der Windows-Registrierung.

Um kompatiblen Code zu implementieren, stellen Sie sicher, dass Ihr Treibercode die folgenden Schritte ausführt:

  • Aktiviert sich standardmäßig für NX.
  • Verwendet NX-APIs/Flags für die Speicherzuordnung (NonPagedPoolNx)
  • Verwendet keine Abschnitte, die sowohl beschreibbar als auch ausführbar sind.
  • Versucht nicht, den ausführbaren Systemspeicher direkt zu ändern.
  • Verwendet keinen dynamischen Code im Kernel
  • Lädt keine Datendateien als ausführbare Datei
  • Die Abschnittsausrichtung ist ein Vielfaches von 0x1000 (PAGE_SIZE). Z.B. DRIVER_ALIGNMENT=0x1000

Die folgende Liste der DDIs, die nicht für die Systemnutzung reserviert sind, kann beeinträchtigt werden:

DDI-Name
ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithQuotaTag
ExAllocatePoolWithTag
ExAllocatePoolWithTagPriority
ExInitializeNPagedLookasideList
ExInitializeLookasideListEx
MmAllocateContiguousMemory
MmAllocateContiguousMemorySpecifyCache
MmAllocateContiguousMemorySpecifyCacheNode
MmAllocateContiguousNodeMemory
MmCopyMemory
MmMapIoSpace
MmMapLockedPages
MmMapLockedPagesSpecifyCache
MmProtectMdlSystemAddress
ZwAllocateVirtualMemory
ZwCreateSection
ZwMapViewOfSection
NtCreateSection
NtMapViewOfSection
ClfsCreateMarshallingArea
NDIS
NdisAllocateMemoryWithTagPriority
Speicher
StorPortGetDataInBufferSystemAddress
StorPortGetSystemAddress
ChangerClassAllocatePool
Anzeige
DxgkCbMapMemory
VideoPortAllocatePool
Audio-Miniport
IMiniportDMus::NewStream
IMiniportMidi::NewStream
IMiniportWaveCyclic::NewStream
IPortWavePci::NewMasterDmaChannel
IMiniportWavePci::NewStream
Audioportklasse
PcNewDmaChannel
PcNewResourceList
PcNewResourceSublist
IFS
FltAllocatePoolAlignedWithTag
FltAllocateContext
WDF
WdfLookasideListCreate
WdfMemoryCreate
WdfDeviceAllocAndQueryProperty
WdfDeviceAllocAndQueryPropertyEx
WdfFdoInitAllocAndQueryProperty
WdfFdoInitAllocAndQueryPropertyEx
WdfIoTargetAllocAndQueryTargetProperty
WdfRegistryQueryMemory

Verwenden sie die Codeintegritätstests im HLK, um die Kompatibilität des Speicherintegritätstreibers zu testen.

Weitere Informationen zu den zugehörigen Systemgrundlagen-Sicherheitstests finden Sie unter HyperVisor Code Integrity Readiness Test und Arbeitsspeicherintegrität und VBS.

Weitere Informationen zu den zugehörigen Gerätegrundlagentests finden Sie unter Device.DevFund-Tests.

Verwenden Sie die folgende Tabelle, um die Ausgabe zu interpretieren und zu ermitteln, welche Treibercodeänderungen erforderlich sind, um die verschiedenen Arten von Inkompatibilitäten der Speicherintegrität zu beheben.

Warnung Erlösung

Pooltyp ausführen

Der Aufrufer hat einen ausführbaren Pooltyp angegeben. Aufrufen einer Speicherzuweisungsfunktion, die ausführbaren Speicher anfordert.

Stellen Sie sicher, dass alle Pool-Typen ein nicht ausführbares NX-Flag enthalten.

Seitenschutz ausführen

Der Aufrufer hat einen ausführbaren Seitenschutz angegeben.

Geben Sie eine Seitenschutzmaske "keine Ausführung" an.

Seitenzuordnung ausführen

Der Aufrufer hat eine MDL-Zuordnung (Executable Memory Descriptor List) angegeben.

Stellen Sie sicher, dass die verwendete Maske MdlMappingNoExecute enthält. Weitere Informationen finden Sie unter MmGetSystemAddressForMdlSafe

Execute-Write-Abschnitt

Das Image enthält einen ausführbaren und einen beschreibbaren Abschnitt.

Abschnittsausrichtungsfehler

Das Bild enthält einen Abschnitt, der nicht seitenausgerichtet ist.

Abschnittsausrichtung muss ein Vielfaches von 0x1000 (PAGE_SIZE) sein. Z.B. DRIVER_ALIGNMENT=0x1000

IAT im ausführbaren Abschnitt

Die Importadressentabelle (IAT) sollte kein ausführbarer Speicherabschnitt sein.

Dieses Problem tritt auf, wenn sich das IAT in einem Nur-Lese- und Ausführungsbereich (RX) befindet. Dies bedeutet, dass das Betriebssystem nicht in die IAT schreiben kann, um die richtigen Adressen für den Speicherort der referenzierten DLL festzulegen.

Eine Möglichkeit, wie dies auftreten kann, ist die Verwendung der Option /MERGE (Abschnitte kombinieren) in Codeverknüpfung. Wenn z. B. Rdata (Schreibgeschützte initialisierte Daten) mit TEXT-Daten (ausführbarer Code) zusammengeführt wird, ist es möglich, dass das IAT möglicherweise in einem ausführbaren Speicherabschnitt endet.


Nicht unterstützte Relocs

In Windows 10, Version 1507 bis Windows 10, Version 1607, kann aufgrund der Verwendung von ASLR (Address Space Layout Layout Randomization) ein Problem bei der Adressausrichtung und Speicherverschiebung auftreten. Das Betriebssystem muss die Adresse, von der der Linker seine standardmäßige Basisadresse festgelegt hat, an den tatsächlichen Speicherort verschieben, den ASLR zugewiesen hat. Diese Verschiebung kann eine Seitengrenze nicht überschreiten. Betrachten Sie beispielsweise einen 64-Bit-Adresswert, der mit offset 0x3FFC auf einer Seite beginnt. Der Adresswert überlappen sich mit der nächsten Seite beim Offset 0x0003. Diese Art von überlappenden Verlagerungen wird vor Windows 10 Version 1703 nicht unterstützt.

Diese Situation kann auftreten, wenn ein globaler Strukturtypvariablen-Initialisierer einen falsch ausgerichteten Zeiger auf einen anderen globalen Zeiger aufweist, der so ausgelegt ist, dass der Linker die Variable nicht verschieben kann, um die Verlagerung von Verschiebungen zu vermeiden. Der Linker versucht, die Variable zu verschieben, aber es gibt Situationen, in denen dies möglicherweise nicht möglich ist (z. B. bei großen falsch ausgerichteten Strukturen oder großen Arrays von falsch ausgerichteten Strukturen). Gegebenenfalls sollten Module mit der Option /Gy (COMDAT) zusammengestellt werden, damit der Linker den Modulcode so weit wie möglich ausrichten kann.

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

Es gibt andere Situationen, die die Verwendung von Assemblercode betreffen, in denen dieses Problem ebenfalls auftreten kann.


Codeintegrität der Treiberüberprüfung

Verwenden Sie das Codeintegritäts-Optionsflag der Treiberüberprüfung (0x02000000), um zusätzliche Überprüfungen zu aktivieren, die die Konformität mit diesem Feature überprüfen. Verwenden Sie den folgenden Befehl, um dies über die Befehlszeile zu aktivieren.

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

Wenn Sie diese Option bei Verwendung der Überprüfungs-GUI auswählen möchten, wählen Sie Benutzerdefinierte Einstellungen erstellen (für Codeentwickler), Weiter und dann Codeintegritätsprüfungen aus.

Sie können die Befehlszeilenoption /query verwenden, um die aktuellen Treiberüberprüfungsinformationen anzuzeigen.

verifier /query

Weitere Informationen

Sicherheitscheckliste für Treiber