【问题标题】:Is there an API call to prompt user for UAC elevation?是否有 API 调用提示用户进行 UAC 提升?
【发布时间】:2015-10-28 22:36:26
【问题描述】:

我的应用程序需要写入 \ProgramData 中可能受保护的文件。这只会在安装后发生一次。

是否有 API 函数可以获取 ACL 信息并提示用户授权应用访问文件?换句话说,该应用程序会要求 Windows 提示用户进行确认和授权。这应该以交互方式发生,并允许应用程序在访问文件被授权后恢复执行。该应用程序以标准用户身份运行,不需要管理员权限。

文件通过 CreateFile() 打开。

编辑:我的查询与其他被称为重复的查询之间存在细微差别。我正在请求访问一个特定对象(文件)的权限。其他人则要求提升整个过程的特权。无论如何,我感谢所有包含解决方案的回复。

【问题讨论】:

  • 但是... 是不是有一些 GetNamedSecurityInfo、AllocateAndInitializeSid、SetEntriesInAcl、SetNamedSecurityInfo 等的组合可以让我只访问那个文件?我不希望整个过程以管理员身份运行。 CreateFile() 引用一个 SECURITY_ATTRIBUTES 事物。看来我可以获得一个 SECURITY_ATTRIBUTES 对象,将它传递给 CreateFile,然后就可以了!
  • 根据CreateFile() documentation: "一个指向 SECURITY_ATTRIBUTES 结构的指针,该结构包含两个独立但相关的数据成员:一个可选的安全描述符和一个布尔值,用于确定返回的句柄是否可以由子进程继承。... CreateFile 在打开现有文件或设备时忽略 lpSecurityDescriptor 成员,但继续使用 bInheritHandle 成员。"
  • 完全没有区别。这是一个骗局很多次。如果您不同意,那么您仍然不了解 UAC。重新开放的选民显然也不明白这一点。
  • 我只是重新打开它,以便发布我的解决方案,我立即再次关闭它。请向我展示另一个具有相同解决方案的 Stackoverflow 帖子,包括 ShellExecuteEx、lpFile = "cmd" 和 double 命令。
  • 20020450不算,也没有提到UAC,只有找到解决方案才能找到。

标签: winapi uac


【解决方案1】:

如果您不想提升整个应用,您有以下几种选择:

  1. 生成一个单独的提升进程,只是为了访问该文件。将ShellExecute/Ex()runas 动词或CreateProcessElevated() 一起使用,以运行您的应用程序的第二个副本或另一个帮助应用程序,并使用命令行参数告诉它要做什么。如果需要,主进程可以等待第二个进程退出。

  2. 创建一个 COM 对象来访问该文件,然后使用 COM Elevation Moniker 在提升的状态下运行该 COM 对象。

  3. 使用CredUIPromptForCredentials()CredUIPromptForWindowsCredentials() 提示用户输入凭据(有关详细信息,请参阅Asking the User for Credentials),然后使用LogonUser() 登录到指定帐户以获取令牌,使用@987654327 模拟该令牌@,根据需要访问该文件,然后停止使用RevertToSelf() 模拟并使用CloseHandle() 关闭令牌。

【讨论】:

  • #3 非常巧妙,但如果我理解正确,它需要应用程序知道管理员密码?恐怕大多数用户不会同意这一点。我会尝试#2。 (我的 COM 很简陋,需要一段时间)。谢谢。
  • #1 更容易实现,因为所有内容都可以保留在一个 exe 中。对于#3,用户需要知道管理员密码,因为对话框会询问用户名和密码,然后您的应用程序将使用该密码登录该帐户。与提示标准用户输入管理员凭据的 UAC 提升没有太大区别。如果管理员正在运行您的应用程序,他们可能已经有权访问该文件。因此,您应该尝试访问该文件一次,然后要求提供凭据并仅在收到类似 ERROR_ACCESS_DENIEDERROR_ELEVATION_REQUIRED 的错误代码时再试一次。
  • 我想我会尝试#1,因为它是最简单的。非常感谢。
  • 我认为#3 行不通,因为您没有模拟权限。 (默认情况下,LogonUser 也会为您提供受限令牌,但您可以使用“批量登录”选项来纠正它。)
【解决方案2】:

感谢 @Remy 的 ShellExecuteEx 建议,这里是肮脏的细节。注意 'cmd' 和双命令的使用,因此用户只需回复一次。此外,[1] 必须等待进程完成,否则您可能会发现自己在文件被删除之前创建了文件,并且 [2] 如果失败则不要等待进程。

// delete file with Admin privilege
// 'file_name' is path of file to be deleted
SHELLEXECUTEINFO shex;
char param[512];
char *cmd = "/C \"attrib -H \"%s\" && del /F /Q \"%s\"\""; // double command

_snprintf(param, sizeof(param), cmd, file_name, file_name);
ZeroMemory(&shex, sizeof(shex));
shex.cbSize = sizeof(shex);
shex.lpVerb = "runas";  // runas, open
shex.lpFile = "cmd";    // not 'del'
shex.lpParameters = param;
shex.nShow = SW_HIDE;
shex.fMask = SEE_MASK_NOCLOSEPROCESS;
BOOL retshx = ShellExecuteEx(&shex);
// wait otherwise could return before completed
if(retshx)
{   time_t st = clock();
    DWORD exitCode;
    do
    {   if(!GetExitCodeProcess(shex.hProcess, &exitCode))
            break;
        if(clock() - st > CLOCKS_PER_SEC * 5)       // max 5 seconds
            break;
    } while(exitCode != STATUS_WAIT_0); // STILL_ACTIVE
    CloseHandle(shex.hProcess);
}

【讨论】:

  • 为什么是“-1”?这段代码花了几个小时才弄好。我希望有人在我寻找答案时发布了这样的内容。我希望它能帮助遇到同样问题的人。 “-1”如何帮助社区?
【解决方案3】:

进程只能使用提升的令牌启动,事后他们无法获得它。因此,您可以使用命令行参数重新启动提升的应用程序,告诉它要做什么(简单的解决方案),或者实现一个进程外 COM 服务器,您可以创建提升的 COM 服务器并将指令传递给它(更难)。

第三种解决方案是利用 IFileOperation 接口的内置 UAC 支持,但这不会让您读/写,只能复制。因此,您可以复制需要修改的文件,修改副本,然后使用IFileOperation 将临时文件复制到原始文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 2010-10-29
    • 2010-09-10
    相关资源
    最近更新 更多