如何提升应用程序启动权限

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何提升应用程序启动权限相关的知识,希望对你有一定的参考价值。

1、手动提升权限

手动提升其实也很简单,用 ShellExecuteEx 函数就可以做到:

BOOL ShellExecuteEx(LPSHELLEXECUTEINFO pExecInfo);
typedef struct _SHELLEXECUTEINFO
DWORD cbSize;
ULONG fMask;
HWND hwnd;
PCTSTR lpVerb; // 必须设为runas
PCTSTR lpFile; // 提升后的权限启动一个可执行文件路径
PCTSTR lpParameters;
PCTSTR lpDirectory;
int nShow;
HINSTANCE hInstApp;
PVOID lpIDList;
PCTSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union
HANDLE hIcon;
HANDLE hMonitor;
DUMMYUNIONNAME;
HANDLE hProcess;
SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;
这样运行程序时就会弹出UAC对话框。

2、自动提升权限

《Windows核心编程(第五版)》 4.5.1也讲到如何实现自动提升权限,但他只是提了一下,如果真要来实现,不同的环境下的具体操作可能会有所差异,它上面是这样讲的:

如果在应用程序中可执行文件中嵌入一种特殊资源(RT_MANIFEST),其中系统会检查<trustInfo>段,下面是示例清单文件的<trustInfo>段。我们可以将清单保存到可知性文件所在目录中,名称和可执行文件相同且扩展名使用 *.manifest那么效果也是一样的。
不过这个清单须要在注销系统后生效,可知性文件嵌入清单的优先权会比外部清单文件大。
...
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
/>
</requestedPrivileges>
</security>
</trustInfo>
...

本质上是通过加一个.manifest清单文件,里面加上requestedExecutionLevel标签。这个标签可能有三个值:
<requestedExecutionLevel level="asInvoker|highestAvailable|requireAdministrator" uiAccess="true|false"/>
asInvoker:应用程序使用与主调程序一样的权限来启动。(对于标准用户程序来说,这是推荐做法)
highestAvailable:应用误用与当前用户所能获得的最高权限来运行。(管理员就是管理员权限,标准用户就是标准用户的权限)
requireAdministrator:应用程序必须以管理员权限来启动。

这一段是从《Windows核发编程(第五版)》上面摘抄过来的。前面说过,它只是大概说了一下,不是很具体。

我在实现的过程中,参考了微软给的步骤,http://msdn.microsoft.com/en-us/library/bb756929.aspx
manifest文件的内容:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0"
processorArchitecture="X86"
name="IsUserAdmin"
type="win32"/>
<description>Description of your application</description>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

然后在资源文件中加入:

#define MANIFEST_RESOURCE_ID 1
MANIFEST_RESOURCE_ID RT_MANIFEST "IsUserAdmin.exe.manifest"

或者在把这个.manifest文件添加到工程设置中:

Open your project in Microsoft Visual Studio 2005.
Under Project, select Properties.
In Properties, select Manifest Tool, and then select Input and Output.
Add in the name of your application manifest file under Additional manifest files.
Rebuild your application.
参考技术A 你好,
请先说您的系统
如果是Windows NT6系列(VIsta以后)右键应用程序或者快捷方式,点击以管理员身份运行,点后如果有弹框,点是。
Windows NT5系列(2K,XP,03)右键以其他用户身份运行,选administrator。
linux 启动终端,cd到应用程序目录,sudo xx.run/bundle 如果之前没有加权限,先chmod +x xx.run/bundle

以提升的权限运行时如何正确检测网络驱动器

【中文标题】以提升的权限运行时如何正确检测网络驱动器【英文标题】:How to correctly detect Network drive when running with elevated privileges 【发布时间】:2017-03-13 15:36:31 【问题描述】:

我正在开发一个需要正确检测 Windows 上所有使用过的驱动器号的应用程序。我为此使用了GetLogicalDrives() 函数。此功能工作得很好,除非用户以提升的权限启动我的应用程序(即,使用属于“管理员”组的帐户登录的用户并通过选择“以管理员身份运行”选项启动我的应用程序)。在这种情况下,GetLogicalDrives() 无法检测到机器上映射的网络驱动器。

问题的根本原因似乎是在这种情况下 Windows 并行运行 2 个用户会话。我的应用程序在“提升权限”会话中运行,而驱动器在“非提升”会话中映射:

https://support.microsoft.com/en-us/help/3035277/mapped-drives-are-not-available-from-an-elevated-prompt-when-uac-is-configured-to-prompt-for-credentials-in-windows

是否有针对此问题的任何程序化解决方法?我试图在“非提升”会话中重新启动我的应用程序,但不知道如何(或者是否可能)。我已经尝试过使用受限令牌重新启动我的应用程序(使用CreateRestrictedTokenDISABLE_MAX_PRIVILEGE 选项),希望Windows 会以某种方式发现它现在可以在“非提升”会话中重新启动我的应用程序,但确实如此不工作。

【问题讨论】:

您能解释一下为什么需要知道映射的驱动器号吗? 我需要映射一个新的驱动器号,并作为其中的一部分,试图找出已经映射的驱动器号。在我描述的上述场景中,我的应用程序未能检测到已映射的驱动器号(例如,“D”),并且实际上成功地将新驱动器映射到它(“D”)。问题是它不会出现在 Explorer 中,我想它会在未提升权限的用户会话中运行。 您希望您的程序(正在运行提升)映射驱动器,以便它显示在非提升进程中?充其量是很难的(我当然不知道怎么做)。在注册表中设置EnabledLinkedConnections(根据您发布的链接)是一个选项吗?它会一次解决你所有的问题。 你可能想看看这个问题***.com/questions/42762595/… for relaunch my application in the "non-elevated" session - 需要在驱动器映射的特定登录会话中重新启动。 CreateRestrictedToken 这里没有帮助,因为它没有更改令牌中的登录会话。需要从此登录会话中打开一些令牌并在调用CreateProcessAsUserW 中使用它 【参考方案1】:

为此,您可以使用链接令牌临时模拟 - 所以获取自己的链接令牌,如果它存在,将其设置为线程,调用 GetLogicalDrives() 并返回处理令牌(链接令牌有 SECURITY_IMPERSONATION_LEVEL == @ 987654324@ 因此它可以使用非常有限

#define BOOL_TO_ERR(b) ((b) ? NOERROR : GetLastError())

ULONG GetLogicalDrivesEx(PULONG pDrives)

    HANDLE hToken;

    ULONG err = BOOL_TO_ERR(OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));

    if (err != NOERROR)
    
        return err;
    

    union 
        TOKEN_ELEVATION_TYPE tet;
        TOKEN_LINKED_TOKEN tlt;
    ;

    ULONG rcb;

    err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb));

    if (err == NOERROR)
    
        if (tet == TokenElevationTypeFull)
        
            err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb));

            if (err == NOERROR)
            
                if (NOERROR == (err = BOOL_TO_ERR(SetThreadToken(0, tlt.LinkedToken))))
                
                    err = (rcb = GetLogicalDrives()) ? NOERROR : GetLastError();
                    SetThreadToken(0, 0);
                

                CloseHandle(tlt.LinkedToken);
            
        
        else
        
            err = (rcb = GetLogicalDrives()) ? NOERROR : GetLastError();
        
    

    *pDrives = rcb;
    return err;


void test()

    ULONG Drives, Drives0 = GetLogicalDrives();
    GetLogicalDrivesEx(&Drives);
    WCHAR sz[32];
    swprintf(sz, L"%08x %08x", Drives0, Drives);
    MessageBoxW(0, sz, L"", MB_OK);


如果没有错误(GetLogicalDrivesEx 返回 NOERRORDrives 是未提升会话的逻辑驱动器,当 Drives0 - 用于提升(如果您当然以提升身份运行)

【讨论】:

非常感谢,RbMm。

以上是关于如何提升应用程序启动权限的主要内容,如果未能解决你的问题,请参考以下文章

如何仅在需要时提升权限?

VC如何将自身进程提升至管理员权限

Vista/7 UAC:如何降低进程权限

以提升的权限运行时如何正确检测网络驱动器

MSI 是不是能够自动启动具有提升权限的程序/文件?

如何ubuntu下启动/停止/重启MySQL