You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++的ShellExecute()中强制触发UAC对话框?

解决方案

要解决高权限进程无法触发UAC切换到其他管理员账户的问题,核心是先从高权限进程启动一个低权限的辅助进程,再通过该辅助进程调用ShellExecuteEx("runas")触发UAC凭据输入框。以下是具体实现方案:

一、通过Windows API创建低权限进程

从高权限进程生成低权限进程的关键是获取当前用户的受限令牌(Restricted Token),并以此令牌启动进程:

步骤说明

  1. 获取当前进程的访问令牌:调用OpenProcessToken获取当前高权限进程的令牌句柄。
  2. 创建受限令牌:调用CreateRestrictedToken,移除令牌中的管理员SID权限,生成仅拥有普通用户权限的受限令牌。
  3. 用受限令牌启动辅助进程:调用CreateProcessAsUser,传入受限令牌,启动你的辅助程序(仅负责触发UAC的轻量进程)。
  4. 辅助进程触发UAC:在辅助进程中调用ShellExecuteEx,指定"runas"动词和需要执行重启操作的目标程序路径,此时系统会弹出UAC对话框,允许用户输入拥有重启权限的管理员账户凭据。

代码示例(C++)

#include <windows.h>
#include <sddl.h>

BOOL LaunchLowPrivilegeProcess(LPCWSTR lpExePath) {
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, &hToken)) {
        return FALSE;
    }

    // 定义要移除的管理员SID
    PSID pAdminSid = NULL;
    SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
    if (!AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSid)) {
        CloseHandle(hToken);
        return FALSE;
    }

    HANDLE hRestrictedToken = NULL;
    // 创建受限令牌,移除管理员权限
    if (!CreateRestrictedToken(hToken, 0, 1, &pAdminSid, 0, NULL, 0, NULL, &hRestrictedToken)) {
        FreeSid(pAdminSid);
        CloseHandle(hToken);
        return FALSE;
    }

    FreeSid(pAdminSid);
    CloseHandle(hToken);

    // 启动低权限进程
    STARTUPINFO si = { sizeof(STARTUPINFO) };
    PROCESS_INFORMATION pi = { 0 };
    BOOL result = CreateProcessAsUser(hRestrictedToken, lpExePath, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

    CloseHandle(hRestrictedToken);
    if (result) {
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    return result;
}

// 辅助进程中的代码,用于触发UAC
void TriggerUACForRestart() {
    SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
    sei.lpVerb = L"runas";
    sei.lpFile = L"你的重启程序路径.exe"; // 替换为实际执行重启的程序
    sei.nShow = SW_SHOWNORMAL;
    ShellExecuteEx(&sei);
}

二、替代方案:使用任务计划程序

如果API调用过于复杂,可以借助Windows任务计划程序实现:

  • 创建一个任务,设置其运行上下文为当前用户的最低权限级别(不勾选"以最高权限运行")。
  • 在高权限进程中调用schtasks.exe /run /tn "你的任务名称"触发该任务。
  • 任务的操作是执行ShellExecuteEx("runas")启动重启程序,同样会弹出UAC凭据框。

关键注意事项

  • 辅助进程必须是独立的可执行文件,不能是高权限进程的线程,因为线程无法脱离父进程的权限上下文。
  • 确保受限令牌的创建正确,否则辅助进程仍会保留高权限,无法触发UAC。
  • 重启程序需要明确请求SeShutdownPrivilege权限,确保执行重启操作的有效性。

内容的提问来源于stack exchange,提问作者Rodrigo Castro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 20:20:18