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:
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