Implementare il codice compatibile con l'integrità della memoria
Questa sezione descrive come implementare il codice compatibile con l'integrità della memoria.
Nota
L'integrità della memoria viene talvolta definita integrità del codice protetta da hypervisor (HVCI) o hypervisor applicata all'integrità del codice ed è stata originariamente rilasciata come parte di Device Guard. Device Guard non viene più usato tranne per individuare l'integrità della memoria e le impostazioni VBS in Criteri di gruppo o nel Registro di sistema di Windows.
Per implementare il codice compatibile, assicurarsi che il codice del driver faccia quanto segue:
- Opta per NX per impostazione predefinita
- Usa API/flag NX per l'allocazione della memoria (NonPagedPoolNx)
- Non usa sezioni sia scrivibili che eseguibili
- Non tenta di modificare direttamente la memoria del sistema eseguibile
- Non usa codice dinamico nel kernel
- Non carica i file di dati come eseguibile
- L'allineamento della sezione è un multiplo di 0x1000 (PAGE_SIZE). Ad esempio DRIVER_ALIGNMENT=0x1000
L'elenco seguente di DDI che non sono riservati all'uso del sistema può essere interessato:
Usare i test di integrità del codice in HLK per testare la compatibilità del driver di integrità della memoria
Per altre informazioni sul test di sicurezza dei concetti fondamentali del sistema correlato, vedere Test di conformità all'integrità del codice HyperVisor e integrità della memoria e VBS.
Per altre informazioni sul test dei concetti fondamentali dei dispositivi correlati, vedere Test device.DevFund.
Usare la tabella seguente per interpretare l'output e determinare quali modifiche apportate al codice driver sono necessarie per correggere i diversi tipi di incompatibilità di integrità della memoria.
Avviso | Redenzione |
Eseguire il tipo di pool |
Il chiamante ha specificato un tipo di pool eseguibile. Chiamata di una funzione di allocazione della memoria che richiede memoria eseguibile. Assicurarsi che tutti i tipi di pool contengano un flag NX non eseguibile. |
Esegui protezione pagina |
Il chiamante ha specificato una protezione della pagina eseguibile. Specificare una maschera di protezione della pagina "no execute". |
Eseguire il mapping di pagine |
Il chiamante ha specificato un mapping del descrittore di memoria eseguibile (MDL). Assicurarsi che la maschera usata contenga MdlMappingNoExecute. Per altre informazioni, vedere MmGetSystemAddressForMdlSafe |
sezione Execute-Write |
L'immagine contiene una sezione eseguibile e scrivibile. |
Errori di allineamento sezione |
L'immagine contiene una sezione non allineata alla pagina. L'allineamento della sezione deve essere un multiplo di 0x1000 (PAGE_SIZE). Ad esempio DRIVER_ALIGNMENT=0x1000 |
IAT nella sezione eseguibile |
La tabella degli indirizzi di importazione (IAT), non deve essere una sezione eseguibile della memoria. Questo problema si verifica quando l'IAT si trova in una sezione di sola lettura ed esecuzione (RX). Ciò significa che il sistema operativo non sarà in grado di scrivere nell'IAT per impostare gli indirizzi corretti per dove la DLL a cui si fa riferimento. Un modo in cui questo può verificarsi è quando si usa l'opzione /MERGE (sezioni combinate) nel collegamento del codice. Ad esempio, se .rdata (dati inizializzati di sola lettura) viene unito ai dati con estensione text (codice eseguibile), è possibile che l'IAT possa terminare in una sezione eseguibile di memoria. |
Relocs non supportato
In Windows 10, versione 1507 fino a Windows 10, versione 1607, a causa dell'uso del layout dello spazio indirizzi casuale (ASLR) può verificarsi un problema con la rilocazione di allineamento e memoria degli indirizzi. Il sistema operativo deve spostare l'indirizzo da cui il linker imposta l'indirizzo di base predefinito sulla posizione effettiva assegnata da ASLR. Questa rilocazione non può allontanarsi da un limite di pagina. Si consideri ad esempio un valore di indirizzo a 64 bit che inizia all'offset 0x3FFC in una pagina. Il valore dell'indirizzo si sovrappone alla pagina successiva in corrispondenza dell'offset 0x0003. Questo tipo di rilocazione sovrapposta non è supportato prima di Windows 10 versione 1703.
Questa situazione può verificarsi quando un inizializzatore di tipo struct globale ha un puntatore non allineato a un altro globale, disposto in modo che il linker non possa spostare la variabile per evitare la rilocazione stradling. Il linker tenterà di spostare la variabile, ma esistono situazioni in cui potrebbe non essere in grado di farlo (ad esempio con struct di grandi dimensioni o matrici di struct non allineati o grandi matrici di struct non allineati). Se appropriato, i moduli devono essere assemblati usando l'opzione /Gy (COMDAT) per consentire al linker di allineare il codice del modulo il più possibile.
#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
};
Esistono altre situazioni che coinvolgono l'uso del codice assembler, in cui questo problema può verificarsi anche.
Integrità del codice del verificatore driver
Usare il flag di opzione di integrità del codice di verifica driver (0x02000000) per abilitare controlli aggiuntivi che convalidano la conformità con questa funzionalità. Per abilitare questa operazione dalla riga di comando, usare il comando seguente.
verifier.exe /flags 0x02000000 /driver <driver.sys>
Per scegliere questa opzione se si usa la GUI del verificatore, selezionare Crea impostazioni personalizzate (per gli sviluppatori di codice), selezionare Avanti e quindi selezionare Controlli di integrità del codice.
È possibile usare l'opzione della riga di comando /query del verificatore per visualizzare le informazioni sul verificatore del driver corrente.
verifier /query