【问题标题】:CreateProcessAsUser vs ShellExecuteCreateProcessAsUser 与 ShellExecute
【发布时间】:2010-09-07 05:02:17
【问题描述】:

我需要ShellExecute 作为另一个用户,目前我使用CreateProcessAsUser 启动一个调用ShellExecute 的辅助进程,但这似乎太过分了(错误的父进程等)有没有更好的如何做到这一点?

@PabloG:ImpersonateLoggedOnUser 不起作用:

处理 hTok; VERIFY(LogonUser("otheruser",0,"password",LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&hTok)); 验证(ImpersonateLoggedOnUser(hTok)); ShellExecute(0,0,"calc.exe",0,0,SW_SHOW); RevertToSelf(); 关闭句柄(hTok);

将以登录用户身份启动 calc,而不是“其他用户”

@1800 信息:CreateProcess/CreateProcessAsUserShellExecute 不同,在 Vista 上使用 UAC,CreateProcess 在您无法控制用户正在执行的程序时毫无用处 (@987654328 @ 将返回一个错误,如果你给它一个带有标记为 requireAdmin 的清单的 exe 文件)

@Brian R. Bondy:我已经知道这个信息(别误会,它的好东西),但它是题外话(恕我直言)我要求ShellExecuteAsUser,而不是启动进程作为另一个用户,我已经知道该怎么做了。

【问题讨论】:

    标签: winapi windows-nt


    【解决方案1】:

    您可以在 ImpersonateLoggedOnUser / RevertToSelf 之间包装 ShellExecute

    链接: ImpersonateLoggedOnUser:http://msdn.microsoft.com/en-us/library/aa378612(VS.85).aspx RevertToSelf:http://msdn.microsoft.com/en-us/library/aa379317.aspx

    抱歉,不能用“()”超链接网址

    【讨论】:

    • 我很确定我试过了,但它不起作用,因为新进程是用当前进程的令牌而不是它的线程产生的
    • 如果在进程的主线程中完成这可能会起作用,但如果在单独的线程中完成则不会起作用,因为 ShellExecute 使用主线程的令牌/安全上下文。去搞清楚。现在...如果您的应用程序有多个线程,在主线程中执行模拟/还原可能会导致应用程序的其他部分中断。
    【解决方案2】:

    你为什么不直接用 CreateProcessAsUser 指定你想运行的进程呢?

    您也可以使用 SHCreateProcessAsUserW。

    【讨论】:

    • 因为我需要ShellExecute对非可执行文件的处理
    • SHCreateProcessAsUserW 未在 XP 及更高版本上实现。
    【解决方案3】:

    解决方案实际上取决于您的需求,并且可能非常复杂(完全感谢 Windows Vista)。这可能超出您的需要,但这将有助于其他通过搜索找到此页面的人。

    1. 如果您不需要使用 GUI 运行该过程并且您不需要提升
    2. 如果您要运行的用户已经登录到会话中
    3. 如果您需要使用 GUI 运行进程,并且用户可能已登录,也可能未登录
    4. 如果您需要使用海拔运行流程

    关于1: 在 Windows Vista 中,存在一种称为 session 0 隔离的东西。所有服务都作为会话 0 运行,并且您不应该在会话 0 中有 GUI。第一个登录的用户登录到会话 1。在 Windows 的早期版本(Vista 之前)中,第一个登录的用户也完全运行在会话 0。

    您可以在同一个会话中使用不同的用户名运行多个不同的进程。你可以找到关于 session 0 隔离here 的好文档。

    由于我们正在处理选项 1),因此您不需要 GUI。因此,您可以在会话 0 中开始您的流程。

    您需要一个类似这样的调用序列: LogonUser、ExpandEnvironmentStringsForUser、GetLogonSID、LoadUserProfile、CreateEnvironmentBlock、CreateProcessAsUser。

    可以通过任何搜索引擎或Google code search找到此示例代码

    关于 2: 如果您希望运行进程的用户已经登录,您可以简单地使用:WTSEnumerateSessions 和 WTSQuerySessionInformation 获取会话 ID,然后使用 WTSQueryUserToken 获取用户令牌。从那里您可以在 CreateProcessAsUser Win32 API 中使用用户令牌。

    这是一个很好的方法,因为您甚至不需要以用户身份登录,也不知道用户的用户名/密码。我相信这只能通过服务作为本地系统帐户运行。

    您可以通过 WTSGetActiveConsoleSessionId 获取当前会话。

    关于 3: 您将按照与 #1 相同的步骤进行操作,但另外您将使用 STARTUPINFO 的 lpDesktop 字段。将此设置为 winsta0\Default。您还需要尝试使用 OpenDesktop Win32 API,如果失败,您可以使用 CreateDesktop。在使用工作站和桌面句柄之前,您应该使用 SE_WINDOW_OBJECT 和 GROUP_SECURITY_INFORMATION | 在每个句柄上使用 SetSecurityInfo。 DACL_SECURITY_INFORMATION。

    如果有问题的用户稍后尝试登录,他实际上会看到正在运行的进程。

    关于 4: 这也可以完成,但它要求您已经在运行提升的进程。作为本地系统帐户运行的服务确实以提升的身份运行。我也只能通过我想要启动的验证码签名过程来让它工作。您要启动的进程还必须有一个与其关联的清单文件,其中 requestedExecutionLevel level="requireAdministrator"

    其他说明:

    • 您可以通过 SetTokenInformation 和 TokenSessionId 设置令牌的会话
    • 您不能更改已运行进程的会话 ID。
    • 如果Vista 不在等式中,整个过程将大大简化。

    【讨论】:

    • 如果您能详细说明一下如何在案例 4 中可以做到这一点,那就太好了。是否需要使用ShellExecute?结合ImpersonateLoggedOnUser?
    • WTSQueryUserToken() 需要“本地系统”帐户权限。这意味着,应用程序应该作为服务启动。
    【解决方案4】:

    如果您需要 ShellExecute 语义,您可以提供以下内容:

    C:\windwos\system32\cmd.exe /k" start <your_target_to_be_ShellExecuted>"CreateProcessAsUser,你就完成了。

    【讨论】:

    • 我已经在使用一个辅助进程,这就是我想要删除的,所以我得到了正确的父进程等
    猜你喜欢
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 2012-06-25
    • 2017-01-11
    • 2014-09-04
    • 2020-07-26
    • 2010-12-01
    • 1970-01-01
    相关资源
    最近更新 更多