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.