Partilhar via


Implementar código compatível com integridade de memória

Esta seção descreve como implementar código compatível com integridade de memória.

Observação

A integridade de memória é por vezes referida como integridade de código protegida por hipervisor (HVCI) ou integridade de código imposta pelo hipervisor e foi originalmente lançada como parte do Device Guard. O Device Guard não é mais usado, exceto para localizar a integridade da memória e as configurações do VBS na Diretiva de Grupo ou no Registro do Windows.

Para implementar código compatível, certifique-se de que o código do driver faça o seguinte:

  • Opta pelo NX por padrão
  • Usa APIs/sinalizadores NX para alocação de memória (NonPagedPoolNx)
  • Não usa seções que são graváveis e executáveis
  • Não tenta modificar diretamente a memória executável do sistema
  • Não usa código dinâmico no kernel
  • Não carrega arquivos de dados como executáveis
  • O alinhamento da seção é um múltiplo de 0x1000 (PAGE_SIZE). Por exemplo, DRIVER_ALIGNMENT=0x1000

A seguinte lista de DDIs que não estão reservadas para uso do sistema pode ser afetada:

Nome 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
Armazenamento
StorPortGetDataInBufferSystemAddress
StorPortGetSystemAddress
ChangerClassAllocatePool
Ecrã
DxgkCbMapMemory
VideoPortAllocatePool
Miniporta de áudio
IMiniportDMus::NewStream
IMiniportMidi::NewStream
IMiniportWaveCyclic::NewStream
IPortWavePci::NewMasterDmaChannel
IMiniportWavePci::NewStream
Classe de porta de áudio
PcNewDmaChannel
PcNewResourceList
PcNewResourceSublist
IFS
FltAllocatePoolAlignedWithTag
FltAllocateContext
WDF
WdfLookasideListCriar
WdfMemoryCreate
WdfDeviceAllocAndQueryProperty
WdfDeviceAllocAndQueryPropertyEx
WdfFdoInitAllocAndQueryProperty
WdfFdoInitAllocAndQueryPropertyEx
WdfIoTargetAllocAndQueryTargetProperty
WdfRegistryQueryMemory

Use os testes de integridade de código no HLK para verificar a compatibilidade do driver de integridade de memória.

Para obter mais informações sobre o teste de segurança dos fundamentos relacionados do sistema, consulte HyperVisor Code Integrity Readiness Test e Memory integrity and VBS.

Para obter mais informações sobre o teste de fundamentos do dispositivo relacionado, consulte os testes Device.DevFund .

Use a tabela a seguir para interpretar a saída e determinar quais alterações de código de driver são necessárias para corrigir os diferentes tipos de incompatibilidades de integridade de memória.

Aviso Redenção

Executar tipo de piscina

O chamador especificou um tipo de pool executável. Chamando uma função de alocação de memória que solicita memória executável.

Certifique-se de que todos os tipos de pool contenham um sinalizador NX não executável.

Executar proteção de página

O chamador especificou uma proteção de página executável.

Especifique uma máscara de proteção de página "no execute".

Executar mapeamento de página

O chamador especificou um mapeamento de lista de descritores de memória executável (MDL).

Verifique se a máscara usada contém MdlMappingNoExecute. Para obter mais informações, consulte MmGetSystemAddressForMdlSafe

Secção Execute-Write

A imagem contém uma seção executável e gravável.

Falhas de alinhamento de seção

A imagem contém uma seção que não está alinhada à página.

O alinhamento da seção deve ser um múltiplo de 0x1000 (PAGE_SIZE). Por exemplo, DRIVER_ALIGNMENT=0x1000

IAT na seção executável

A tabela de endereços de importação (IAT) não deve ser uma seção executável da memória.

Esse problema ocorre quando o IAT, está localizado em uma seção somente leitura e execução (RX) da memória. Isso significa que o sistema operacional não será capaz de gravar no IAT para definir os endereços corretos da localização da DLL referenciada.

Uma forma de isso acontecer é ao usar a opção /MERGE (Combinar seções) na vinculação de código. Por exemplo, se .rdata (dados inicializados somente leitura) for mesclado com dados .text (código executável), é possível que o IAT acabe em uma seção executável da memória.


Relocações não suportadas

No Windows 10, versão 1507 até Windows 10, versão 1607, devido ao uso de Address Space Layout Randomization (ASLR), um problema pode surgir com o alinhamento de endereços e realocação de memória. O sistema operacional precisa realocar o endereço de onde o vinculador definiu seu endereço base padrão para o local real que a ASLR atribuiu. Essa realocação não pode ultrapassar um limite de página. Por exemplo, considere um endereço de 64 bits que começa no offset (deslocamento) 0x3FFC numa página. O valor do endereço sobrepõe-se à página seguinte no deslocamento 0x0003. Este tipo de relocações sobrepostas não é suportado antes do Windows 10, versão 1703.

Essa situação pode ocorrer quando um inicializador de variável do tipo struct global tem um ponteiro desalinhado para outra variável global, disposto de tal forma que o ligador não pode mover a variável para evitar a realocação entrelaçada. O vinculador tentará mover a variável, mas há situações em que pode não ser capaz de fazê-lo (por exemplo, com grandes estruturas desalinhadas ou grandes matrizes de estruturas desalinhadas). Quando apropriado, os módulos devem ser montados usando a opção /Gy (COMDAT) para permitir que o vinculador alinhe o código do módulo tanto quanto possível.

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

Existem outras situações envolvendo o uso do código assembler, onde esse problema também pode ocorrer.


Integridade do código do Verificador de Condutor

Use o sinalizador de opção de integridade de código do Verificador de Driver (0x02000000) para habilitar verificações adicionais que validam a conformidade com esse recurso. Para habilitar isso a partir da linha de comando, use o seguinte comando.

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

Para escolher essa opção se estiver usando a GUI do verificador, selecione Criar configurações personalizadas (para desenvolvedores de código), selecione Avançare, em seguida, selecione Verificações de integridade do código.

Você pode usar a opção de linha de comando /query do verificador para exibir as informações atuais do verificador de driver.

verifier /query

Ver também

Lista de verificação de segurança do condutor