Partilhar via


Escrevendo drivers para diferentes versões do Windows

Ao criar um projeto de driver, você especifica o sistema operacional de destino mínimo, que é a versão mínima do Windows na qual o driver será executado. Por exemplo, você pode especificar que o Windows 7 é o sistema operacional de destino mínimo. Nesse caso, o driver seria executado no Windows 7 e versões posteriores do Windows.

Observação

Se você desenvolver um driver para uma versão mínima específica do Windows e quiser que o driver funcione em versões posteriores do Windows, não deverá usar nenhuma função não documentada e não deverá usar funções documentadas de outra forma que não seja a descrita na documentação. Caso contrário, o driver pode falhar ao ser executado nas versões posteriores do Windows. Mesmo se você tiver tido o cuidado de usar apenas funções documentadas, você deve testar seu driver na nova versão do Windows cada vez que um é lançado.

Escrevendo um driver de várias versões usando apenas recursos comuns

Quando você cria um driver que será executado em várias versões do Windows, a abordagem mais simples é permitir que o driver use apenas funções DDI e estruturas que são comuns a todas as versões do Windows em que o driver será executado. Nessa situação, você define o sistema operacional de destino mínimo para a versão mais antiga do Windows que o driver suportará.

Por exemplo, para oferecer suporte a todas as versões do Windows, começando com o Windows 7, você deve:

  1. Projete e implemente o driver para que ele use apenas os recursos que estão presentes no Windows 7.

  2. Ao criar o driver, especifique o Windows 7 como o sistema operacional de destino mínimo.

Embora esse processo seja simples, ele pode restringir o driver a usar apenas um subconjunto da funcionalidade que está disponível em versões posteriores do Windows. Em muitos casos, convém fazer uso da funcionalidade mais recente do sistema operacional quando ela estiver disponível para melhorar a segurança, melhorar a confiabilidade ou habilitar recursos mais recentes.

Escrevendo um driver de várias versões que usa recursos dependentes da versão

Um driver de modo kernel pode determinar dinamicamente se uma API fornecida pelo sistema operacional está disponível ou em qual versão do Windows o driver está sendo executado e optar por usar os recursos disponíveis nesse ambiente de tempo de execução. Por exemplo, um driver que deve oferecer suporte a todas as versões do Windows, começando com o Windows 7, pode determinar, em tempo de execução, a versão do Windows em que ele está sendo executado. Se o driver estiver sendo executado no Windows 7, ele deve usar apenas as funções DDI que o Windows 7 suporta. No entanto, o mesmo driver pode usar funções DDI adicionais que são exclusivas do Windows 8, por exemplo, quando sua verificação de tempo de execução determina que essas APIs estão presentes no momento ou determina que ele está sendo executado no Windows 8.

Observação

É recomendável que você verifique a disponibilidade de recursos ou API sempre que possível, em vez de tentar verificar se o driver está sendo executado em uma determinada versão do sistema operacional ou posterior.

Chamando condicionalmente funções dependentes da versão do Windows

Um driver de modo kernel pode usar as funções MmGetSystemRoutineAddress ou MmGetSystemRoutineAddressEx para verificar dinamicamente se uma API específica que deseja usar está disponível no ambiente de tempo de execução atual e para obter um ponteiro de função a ser usado para chamar essa API.

Observação

Para ajudar a preservar a verificação de tipo e evitar erros não intencionais, você deve criar um typedef que espelhe o tipo de função original.

Exemplo: Determinando a disponibilidade da API e chamando condicionalmente a API

typedef
NTSTATUS
(*PFN_IoOpenDriverRegistryKey)(
    PDRIVER_OBJECT     DriverObject,
    DRIVER_REGKEY_TYPE RegKeyType,
    ACCESS_MASK        DesiredAccess,
    ULONG              Flags,
    PHANDLE            DriverRegKey
    );

VOID ExampleFunction(VOID) {
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    HANDLE persistentStateKey = NULL;
    PFN_IoOpenDriverRegistryKey pfnIoOpenDriverRegistryKey = NULL;
    UNICODE_STRING functionName = {0};

    RtlInitUnicodeString(&functionName, L"IoOpenDriverRegistryKey");
    pfnIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&functionName);

    if (pfnIoOpenDriverRegistryKey != NULL) {
        // Open a key to where state can be stored under the driver service
        status = pfnIoOpenDriverRegistryKey(g_GlobalStructure.DriverObject,
                                            DriverRegKeyPersistentState,
                                            KEY_WRITE,
                                            0,
                                            &persistentStateKey);
    } else {
        // Fall back to opening up a different location to store state in
    }

    // Use the opened registry key
}

Determinando a versão do Windows

Um driver de modo kernel pode usar a função RtlVerifyVersionInfo para verificar dinamicamente em qual versão do Windows ele está sendo executado no momento.

Observação

É recomendável que você verifique a disponibilidade de recursos ou API sempre que possível, em vez de tentar verificar se o driver está sendo executado em uma determinada versão do sistema operacional ou posterior.

Exemplo: Determinando a versão do Windows

O exemplo a seguir detecta se a versão do sistema operacional em execução no momento é maior ou igual à versão 10.0 e detecta se o número de compilação é maior ou igual à compilação 22000 (Windows 11, versão 21H2).

...

NTSTATUS Status = STATUS_SUCCESS;
RTL_OSVERSIONINFOEXW VersionInfo = {0};
ULONG TypeMask = 0;
ULONGLONG ConditionMask = 0;

VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
VersionInfo.dwMajorVersion = 10;
VersionInfo.dwMinorVersion = 0;
VersionInfo.dwBuildNumber = 22000;

TypeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
VER_SET_CONDITION(ConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);

Status = RtlVerifyVersionInfo(&VersionInfo,
                              TypeMask,
                              ConditionMask);

if (NT_SUCCESS(Status)) {

    //
    // The call to RtlVerifyVersionInfo succeeded, so the running OS
    // version and build number is greater than or equal to the value
    // specified. Do appropriate action for newer OS versions.
    //

} else if (Status == STATUS_REVISION_MISMATCH) {

    //
    // The running OS version is less than the value specified. Do
    // appropriate action for older OS versions.
    //

} else {

    //
    // There was an error comparing to the running OS version. Do
    // appropriate action for when the OS version is not known.
    //

}
...