You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CreateProcessAsUserW启动SYSTEM shell却显示父cmd.exe输出的问题

问题分析

你的核心问题是:使用CreateProcessAsUserW以SYSTEM身份创建cmd.exe后,无法在现有控制台看到SYSTEM进程的输出,反而显示父进程(本地管理员)的输出。这是因为:

  • 默认情况下,新进程的标准输入输出句柄未正确关联到父进程控制台,且跨用户身份(管理员→SYSTEM)时,直接继承父进程句柄会因权限限制无法访问。
  • 你的STARTUPINFO未配置标准句柄,导致新进程无法将输出定向到现有控制台。
解决方案

要让SYSTEM进程的输出显示在现有控制台,需要完成以下步骤:

  1. 获取父进程的标准输入、输出、错误句柄。
  2. 将这些句柄复制到SYSTEM令牌的上下文(解决跨用户权限问题)。
  3. 配置STARTUPINFO,指定新进程使用复制后的标准句柄,并启用句柄继承。
修改后的代码片段
std::wcout << "Impersonating the client..." << std::endl;
if (ImpersonateNamedPipeClient(serverPipe))
{
    printf("[+] Successfully Impersonated the client!!\n");
}
else
{
    printf("error: %i\n", GetLastError());
}

wchar_t command[] = L"C:\\Windows\\system32\\cmd.exe";
PROCESS_INFORMATION pi = {};
HANDLE threadToken;
HANDLE hDuppedToken;

if (OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, false, &threadToken))
{
    printf("[+] OpenThreadToken was a success!!\n");
}
else
{
    printf("[!] OpenThreadToken error: %i\n", GetLastError());
}

if (DuplicateTokenEx(threadToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hDuppedToken))
{
    printf("[+] DuplicateToken was a success!!\n");
}
else
{
    printf("[!] DuplicateToken error: %i\n", GetLastError());
}

// --- 新增:处理标准控制台句柄 ---
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE);

HANDLE hDupStdIn = NULL, hDupStdOut = NULL, hDupStdErr = NULL;
// 复制句柄到SYSTEM令牌上下文,确保新进程可访问
if (!DuplicateHandle(GetCurrentProcess(), hStdIn, hDuppedToken, &hDupStdIn, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
    printf("DuplicateHandle StdIn error: %x\n", GetLastError());
}
if (!DuplicateHandle(GetCurrentProcess(), hStdOut, hDuppedToken, &hDupStdOut, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
    printf("DuplicateHandle StdOut error: %x\n", GetLastError());
}
if (!DuplicateHandle(GetCurrentProcess(), hStdErr, hDuppedToken, &hDupStdErr, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
    printf("DuplicateHandle StdErr error: %x\n", GetLastError());
}

// 配置STARTUPINFO,指定标准句柄
STARTUPINFO si = { sizeof(STARTUPINFO) }; // 必须设置cb大小
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hDupStdIn;
si.hStdOutput = hDupStdOut;
si.hStdError = hDupStdErr;

// --- 创建进程:启用句柄继承(第5个参数为TRUE) ---
BOOL bRet = CreateProcessAsUserW(hDuppedToken, NULL, command, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);
if (bRet)
{
    printf("[+] CreateProcess was a success!!\n");
}
else
{
    printf("CreateProcess error: %x\n", GetLastError());
}

// 清理资源
RevertToSelf();
CloseHandle(threadToken);
if (hDupStdIn) CloseHandle(hDupStdIn);
if (hDupStdOut) CloseHandle(hDupStdOut);
if (hDupStdErr) CloseHandle(hDupStdErr);
if (pi.hProcess) CloseHandle(pi.hProcess);
if (pi.hThread) CloseHandle(pi.hThread);

return 0;
关键修改点说明
  • STARTUPINFO初始化:必须显式设置cb字段为结构体大小,避免API调用失败。
  • 句柄复制:使用DuplicateHandle将父进程的控制台句柄复制到SYSTEM令牌的进程上下文,解决跨用户权限访问问题。
  • 启用句柄继承:CreateProcessAsUserW的第5个参数设为TRUE,允许新进程继承复制后的标准句柄。
  • 指定标准句柄:通过STARTF_USESTDHANDLES标志和hStdInput/Output/Error字段,将新进程的IO定向到现有控制台。

内容的提问来源于stack exchange,提问作者g3tsyst3m

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 19:10:11