Elevação Dinâmica de Privilégios UAC em C++ para Aplicações Win32 e Console

Em ambientes Windows, o Controle de Conta de Usuário (UAC) é uma camada de segurança essencial. No entanto, muitos desenvolvedores preferem gerenciar a elevação de privilégios de forma dinâmica via código, em vez de depender exclusivamente de arquivos de manifesto (.manifest) estáticos. Esta abordagem permite que um programa decida, em tempo de execução, se precisa solicitar permissões de administrador.

Para implementar essa funcionalidade, o processo geralmente segue dois passos: verificar se o processo atual já possui privilégios elevados e, caso contrário, reiniciar o executável utilizando o verbo "runas" através da API do Windows.

Abaixo, detalhamos a implementação técnica necessária, utilizando as bibliotecas nativas do Windows.

Bibliotecas Necessárias

Para manipular tokens de segurança e executar processos com privilégios, são necessários os seguintes cabeçalhos:

#include <windows.h>
#include <shellapi.h>
#include <iostream>

Verificação de Privilégios Administrativos

A função a seguir verifica se o token do processo atual pertence ao grupo de administradores locais. Diferente de uma simples checagem de usuário, ela valida se o privilégio está ativo no contexto de segurança atual.

BOOL ValidarStatusAdministrador() {
    BOOL status = FALSE;
    PSID sidGrupoAdmin = NULL;
    SID_IDENTIFIER_AUTHORITY autoridadeNT = SECURITY_NT_AUTHORITY;

    // Cria um SID para o grupo de Administradores
    if (AllocateAndInitializeSid(
            &autoridadeNT, 
            2, 
            SECURITY_BUILTIN_DOMAIN_RID, 
            DOMAIN_ALIAS_RID_ADMINS, 
            0, 0, 0, 0, 0, 0, 
            &sidGrupoAdmin)) {
        
        // Verifica se o SID está presente no token do processo
        CheckTokenMembership(NULL, sidGrupoAdmin, &status);
        FreeSid(sidGrupoAdmin);
    }
    return status;
}

Solicitando Elevação Dinamicamente

Caso o programa identifique que não possui as permissões necessárias, ele deve invocar a si mesmo novamente. O uso da estrtuura SHELLEXECUTEINFO com o parâmetro lpVerb definido como "runas" aciona o prompt do UAC para o usuário.

void ExecutarComoAdmin() {
    if (ValidarStatusAdministrador()) {
        // O programa já possui privilégios elevados
        return;
    }

    TCHAR caminhoExecutavel[MAX_PATH];
    if (GetModuleFileName(NULL, caminhoExecutavel, MAX_PATH)) {
        SHELLEXECUTEINFO sei = { sizeof(sei) };
        sei.fMask = SEE_MASK_DEFAULT;
        sei.lpVerb = TEXT("runas"); // Gatilho para o UAC
        sei.lpFile = caminhoExecutavel;
        sei.nShow = SW_NORMAL;

        if (ShellExecuteEx(&sei)) {
            // Se o novo processo foi iniciado com sucesso, encerramos o atual
            _exit(0);
        } else {
            // O usuário pode ter negado a permissão ou ocorreu um erro
            DWORD erro = GetLastError();
            // Tratar erro conforme necessário
        }
    }
}

Implementação em Aplicações de Console

Para aplicações via linha de comando (CMD), a lógica permanece a mesma. O ponto crucial é garantir que a verificação ocorra logo no início da função main, antes de qualquer operação que exija privilégios.

int main(int argc, char* argv[]) {
    // Tenta elevar os privilégios se necessário
    ExecutarComoAdmin();

    // Código principal que exige permissões de administrador
    printf("Executando com privilegios de administrador...\n");
    system("pause");

    return 0;
}

Esta técnica é particularmente útil para ferramentas de diagnóstico, instaladores personalizados ou utilitários de sistema que não devem exibir o "escudo" de administrador no ícone do arquivo de forma permanente, mas que precisam de acesso total ao sistema em momentos específicos da execução.

Tags: Win32 API C++ Windows Security UAC ShellExecuteEx

Publicado em 7-20 03:29