进程启动但在使用 CreateProcessLogonW 或类似方法启动时不起作用

Posted

技术标签:

【中文标题】进程启动但在使用 CreateProcessLogonW 或类似方法启动时不起作用【英文标题】:Processes Start but do not function when launched with CreateProcessLogonW or similar methods 【发布时间】:2011-12-02 21:24:54 【问题描述】:

我开始使用 C# 以编程方式运行我的应用程序,并且它在管理员帐户下运行良好,但是一旦我开始使用不同用户的凭据运行它们“在登录时可以正常运行这些控制台应用程序的普通用户” “,它们要么像一个没有输入或输出的无限循环一样运行,.net 会崩溃,java 会立即退出。

我需要在一个被监禁的用户下运行这些应用程序,除了它正在执行的应用程序之外,对系统没有最低限度的访问权限,重定向标准输入和输出以由在系统或管理员帐户下运行的主机应用程序处理,并且理想情况下隐藏这些创建的进程的控制台窗口。到目前为止,我已经在 C# 和 C++ 的各种示例中尝试过这个......

我的 C# 代码:

// Start the process
currentProcess = new Process();
currentProcess.StartInfo.FileName = AppFile;
currentProcess.StartInfo.Arguments = Args;
// No window and make sure all output is redirected to us
// TODO: Start process as a jailed user
currentProcess.StartInfo.CreateNoWindow = true;
currentProcess.StartInfo.UseShellExecute = false;
currentProcess.StartInfo.WorkingDirectory = AppPath;
currentProcess.StartInfo.UserName = User.Username;
currentProcess.StartInfo.Password = User.Password;
currentProcess.StartInfo.RedirectStandardInput = true;
currentProcess.StartInfo.RedirectStandardError = true;
currentProcess.StartInfo.RedirectStandardOutput = true;
currentProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
currentProcess.EnableRaisingEvents = true;
currentProcess.Exited += new EventHandler(ExitedHandler);
currentProcess.Start();

我的 C++ 代码:

PROCESS_INFORMATION pi;
STARTUPINFO si;

// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;// | STARTF_USESHOWWINDOW;
si.hStdOutput = hChildStdOut;
si.hStdInput  = hChildStdIn;
si.hStdError  = hChildStdErr;
// Use this if you want to hide the child:
//si.wShowWindow = SW_HIDE;
// Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
// use the wShowWindow flags.


// Launch the process that you want to redirect (in this case,
// Child.exe). Make sure Child.exe is in the same directory as
// redirect.c launch redirect from a command line to prevent location
// confusion.
//CreateProcessAsUser(hptoken, 0, cmd, 0, 0, FALSE, 0, 0, 0, &si, &pi )

HANDLE hTempUser;
//LogonUserA("tesy","TIM-WORK","test", LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &hTempUser);
//if (hTempUser == INVALID_HANDLE_VALUE || hTempUser == NULL)
//    DisplayError("LoginUser");
//else if (!DuplicateTokenEx(hTempUser, 0, NULL, SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation, TOKEN_TYPE::TokenPrimary, &hUserToken))
//    DisplayError("DuplicateUserToken");
//
//// Close the temporary handle to the user
//CloseHandle(hTempUser);

//if (GrantDesktopAccess(hUserToken) != S_OK)
//    DisplayError("GrantDesktop");

//if (!CreateProcessAsUserA(hUserToken,NULL,"C:\\test\\test.exe",NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi))
//   DisplayError("CreateProcessAsUser");

//CreateProcessWithTokenW(hUserToken, NULL, L"C:\\test\\test.exe", NULL, NULL, NULL, L"C:\\test\\", &si, &pi);
CreateProcessWithLogonW(L"tesy", L"TIM-WORK", L"test", LOGON_WITH_PROFILE, L"C:\\test\\test.exe", NULL, CREATE_NEW_CONSOLE, NULL, L"C:\\test\\", &si, &pi);
//if (GetLastError() > 0);
//    DisplayError("CreateProcessWithLogon");

// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess;

// Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");

C++ 对我来说是最好的解决方案,因为我能够隐藏进程窗口,一旦指定用户名和密码,该功能就会在 .net 中中断。 但在上述两种解决方案中,我仍然遇到应用程序无法正常运行的相同问题。

另外,我注意到当我不重定向输出时,我正在运行的这些进程将运行良好。所以问题似乎在于在用户之间传递输入、输出和错误的句柄......

【问题讨论】:

那么,它们怎么运行不正常? “它们要么像一个没有输入或输出的无限循环一样运行,.net 会崩溃,java 会立即退出。” 【参考方案1】:

尝试查找 ProcessInfo 然后创建对象并在那里分配您需要的属性。然后创建实际的 Process 对象将 processInfo 对象分配给该 Process 并创建一个 while 循环来检查退出代码

【讨论】:

这与使用进程本身创建的启动信息对象的结果相同。我的 java 进程仍然立即退出,.net 进程崩溃,而本地进程就像处于无限循环中一样。【参考方案2】:

好的,经过更多测试后,我发现“据我所知”,将在一个用户下运行的应用程序的输出和输入直接路由到在管理员类型用户下运行的主机应用程序是不可能的。

所以我用命名管道解决了这个问题,我在 c++ 中创建了一个基本应用程序,旨在在用户下运行,这个应用程序打开命名管道,其名称由命令行参数指定。这个“包装器”应用程序使用 CreateProcess 运行所需的应用程序,因为包装器已经在正确的用户下运行。包装器将输入、输出和错误流重定向到包装器启动时打开的命名管道。

然后,我的宿主应用程序可以通过包装器打开的管道与在不同用户下运行的应用程序通信。

效果很好,问题解决了:)

【讨论】:

以上是关于进程启动但在使用 CreateProcessLogonW 或类似方法启动时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

从 C# 启动远程进程的问题

让 MVC 网站以管理员身份启动进程

启动 Mozilla Firefox 时如何获取进程 ID?

Xamarin 应用程序无法在 iOS <= 10 上启动:“无法使用 bundleID 引导进程...”

CDH 5.3.2 - 需要从 shell/脚本重新启动 impala 守护进程

命令在控制台中能正常执行但在shell脚本中却无法执行?