1

我做了很多研究,不知道为什么这不起作用,可能缺少一些简单的东西。该代码确实启动了程序,但它以本地系统用户而不是预期用户的身份启动它。

执行代码的部分服务:

APIProcess.PROCESS_INFORMATION PI = new APIProcess.PROCESS_INFORMATION();
if (!APIProcess.Launch(@"C:\Windows\System32\notepad.exe", ".",
                "admin", "test", out string MSG, out PI))
            {
                logger.Debug(MSG);
            }
            else
            {
                logger.Debug(MSG);
                logger.Debug(PI.dwProcessID);
            }

具有后台功能的部分代码:

public static bool Launch(string appCmdLine, string Domain, string Username, string Password,out string MSG, out PROCESS_INFORMATION pi)
    {
        MSG = "";
        pi = new PROCESS_INFORMATION();
        bool ret = false;

        IntPtr Token = IntPtr.Zero;

        if (LogonUserA(Username,Domain,Password,LogonType.LOGON_NEW_CREDENTIALS,LogonProvider.PROVIDER_WINNT50,ref Token))
        {
            if (Token != IntPtr.Zero)
            {
                IntPtr envBlock = GetEnvironmentBlock(Token);
                ret = LaunchProcessAsUser(appCmdLine, Token, envBlock, out MSG, out pi);
                MSG = string.Join(", ",Token.ToString(),envBlock.ToString());
                if (envBlock != IntPtr.Zero)
                    DestroyEnvironmentBlock(envBlock);


                CloseHandle(Token);
            }

        }
        else
        {
            MSG = "Failed To Logon User";
        }
        return ret;
    }

[DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LogonUserA(
        string Username,
        string Domain,
        string Password,
        LogonType LogonType,
        LogonProvider LogonProvider,
        ref IntPtr Token);

private static bool LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock, out string Error, out PROCESS_INFORMATION pi)
    {
        bool result = false;
        Error = "";

        pi = new PROCESS_INFORMATION();
        SECURITY_ATTRIBUTES saProcess = new SECURITY_ATTRIBUTES();
        SECURITY_ATTRIBUTES saThread = new SECURITY_ATTRIBUTES();
        saProcess.nLength = (uint)Marshal.SizeOf(saProcess);
        saThread.nLength = (uint)Marshal.SizeOf(saThread);

        STARTUPINFO si = new STARTUPINFO();
        si.cb = (uint)Marshal.SizeOf(si);


        si.lpDesktop = @"WinSta0\Default"; //Modify as needed 
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
        si.wShowWindow = SW_SHOW;


        result = CreateProcessAsUser(
            token,
            null,
            cmdLine,
            ref saProcess,
            ref saThread,
            false,
            CREATE_UNICODE_ENVIRONMENT,
            envBlock,
            null,
            ref si,
            out pi);


        if (result == false)
        {
            int error = Marshal.GetLastWin32Error();
            string message = String.Format("CreateProcessAsUser Error: {0}", error);
            Error = message;
            //Debug.WriteLine(message);

        }

        return result;
    }

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

我有一些日志记录,看起来用户令牌和环境令牌创建得很好。它也确实启动了预期的应用程序,但它以系统用户而不是预期的模拟用户身份启动。如果该用户下已经有一个程序在运行,我可以让它工作。对于示例,我更改了要启动的所需程序以及域/用户名/密码。

4

1 回答 1

2

问题在于在对 LogonUser 的调用中使用了 LOGON_NEW_CREDENTIALS 类型。从文档中

此登录类型允许调用者克隆其当前令牌并为出站连接指定新凭据。新的登录会话具有相同的本地标识符,但对其他网络连接使用不同的凭据。

尝试改用 LOGON32_LOGON_BATCH。

于 2019-01-10T16:53:25.887 回答