0

使用调用 GUI 应用程序

[DllImport(
    "advapi32.dll",
    EntryPoint = "CreateProcessAsUser",
    SetLastError = true,
    CharSet = CharSet.Ansi,
    CallingConvention = CallingConvention.StdCall)]
private static extern bool CreateProcessAsUser(
    IntPtr hToken,
    string lpApplicationName,
    string lpCommandLine,
    ref SECURITY_ATTRIBUTES lpProcessAttributes,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    bool bInheritHandle,
    int dwCreationFlags,
    IntPtr lpEnvironment,
    string lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    out PROCESS_INFORMATION lpProcessInformation);


bool result = CreateProcessAsUser(
    hUserTokenDup,
    null,
    applicationName + " " + arguments,
    ref sa,                 // pointer to process SECURITY_ATTRIBUTES
    ref sa,                 // pointer to thread SECURITY_ATTRIBUTES
    false,                  // handles are not inheritable
    NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,        // creation flags
    IntPtr.Zero,            // pointer to new environment block 
    null,                   // name of current directory 
    ref si,                 // pointer to STARTUPINFO structure
    out procInfo);          // receives information about new process

从 LocalSystem Windows 服务工作。窗口在用户屏幕中弹出,但进程用户仍然是LocalSystem。有什么办法可以改变吗?

PS根据要求,我hUserTokenDup

[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
private static extern bool DuplicateTokenEx(
    IntPtr ExistingTokenHandle,
    uint dwDesiredAccess,
    ref SECURITY_ATTRIBUTES lpThreadAttributes,
    int TokenType,
    int ImpersonationLevel,
    ref IntPtr DuplicateTokenHandle);

 DuplicateTokenEx(
     hPToken,
     MAXIMUM_ALLOWED,
     ref sa,
     (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
     (int)TOKEN_TYPE.TokenPrimary,
     ref hUserTokenDup);
4

3 回答 3

3

在我的服务中,我在调用之前使用WTSGetActiveConsoleSessionId(),WTSQueryUserToken()和,它对我来说很好用。生成的进程在用户帐户中运行,而不是在服务帐户中运行。DuplicationTokenEx()CreateProcessAsUser()

于 2011-02-08T23:04:38.103 回答
2

看起来您需要调用 LogonUser 来获取代表目标用户的令牌,而不是使用 DuplicateTokenEx 来复制当前令牌。如果我正确理解您的代码片段,只需调用 DuplicateTokenEx 将为本地系统用户创建一个令牌。

此外,由于您的目标是交互式用户,因此请考虑使用CreateProcessWithLogonW函数。

于 2011-02-08T22:43:45.710 回答
0

感谢 Remy Lebeau 提示使用WTSGetActiveConsoleSessionId()

下面的函数必须像 win-service 一样从“系统”用户调用,并且需要一个正在运行的物理控制台(一个普通的用户登录会话,没有远程终端会话)。您可以使用此用户安全属性在正在运行的登录会话中从 win-service 启动一个新进程。如果调用者不是“系统”,则无法使用模拟用户启动新进程。

 public static bool StartProcessAndBypassUAC(ProcessStartInfo ps, out PROCESS_INFORMATION procInfo)
 {
 // code based on http://www.codeproject.com/Articles/35773/Subverting-Vista-UAC-in-Both-32-and-64-bit-Archite
    uint winlogonPid = 0;
    IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
    procInfo = new PROCESS_INFORMATION();

    // obtain the currently active session id; every logged on user in the system has a unique session id
    uint dwSessionId = WTSGetActiveConsoleSessionId();

    if (dwSessionId == 0xFFFFFFFF)
    {
        // no  physical console
        return false;
    }

    if (!WTSQueryUserToken(dwSessionId, ref hPToken))
    {
        return false ;
    }

    // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
    // I would prefer to not have to use a security attribute variable and to just 
    // simply pass null and inherit (by default) the security attributes
    // of the existing token. However, in C# structures are value types and therefore
    // cannot be assigned the null value.
    SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
    sa.Length = Marshal.SizeOf(sa);

    // copy the access token of the winlogon process; the newly created token will be a primary token
    if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
    {
        CloseHandle(hProcess);
        CloseHandle(hPToken);
        return false;
    }

    // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
    // the window station has a desktop that is invisible and the process is incapable of receiving
    // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user 
    // interaction with the new process.
    STARTUPINFO si = new STARTUPINFO();
    si.cb = (int)Marshal.SizeOf(si);
    si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop

    // flags that specify the priority and creation method of the process
    int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

    // create a new process in the current user's logon session
    bool result = CreateProcessAsUser(hUserTokenDup,        // client's access token
                                    null,                   // file to execute
                                    ps.FileName,            // command line
                                    ref sa,                 // pointer to process SECURITY_ATTRIBUTES
                                    ref sa,                 // pointer to thread SECURITY_ATTRIBUTES
                                    true,                  // handles are not inheritable
                                    dwCreationFlags,        // creation flags
                                    IntPtr.Zero,            // pointer to new environment block 
                                    ps.WorkingDirectory,    // name of current directory 
                                    ref si,                 // pointer to STARTUPINFO structure
                                    out procInfo            // receives information about new process
                                    );

    // invalidate the handles
    CloseHandle(hProcess);
    CloseHandle(hPToken);
    CloseHandle(hUserTokenDup);

    return result; // return the result
 }
于 2014-01-20T14:28:05.450 回答