在没有新控制台的情况下使用 CreateProcessWithLogonW() 执行 CMD.EXE

Posted

技术标签:

【中文标题】在没有新控制台的情况下使用 CreateProcessWithLogonW() 执行 CMD.EXE【英文标题】:Execute CMD.EXE with CreateProcessWithLogonW() without a new console 【发布时间】:2020-04-06 20:28:01 【问题描述】:

我必须使用CreateProcessWithLogonW() 运行cmd.exe,但在我的程序上下文中无需创建另一个控制台,但MSDN 说CREATE_NEW_CONSOLE 标志已默认设置。如何取消设置此标志,以便此 API 不会为我的子进程创建新窗口?

以下代码显示了此 API 在我的程序中的使用方式。我不希望新程序在新控制台中运行,但我找不到解决方案。

BOOL status = FALSE;
DWORD process_flags = 0 | arg_process_flags;
DWORD logon_flags = 0 | arg_logon_flags;
PTSTR duplicate_command_Line;
PPROCESS_INFORMATION ptr_process_info;
STARTUPINFO startup_info;
RtlZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);

if (ptr_process_info = arg_process_infos ? arg_process_infos : (PPROCESS_INFORMATION)LocalAlloc(LPTR, sizeof(PROCESS_INFORMATION)))

    if (duplicate_command_Line = _wcsdup(arg_command_Line))
    
        switch (arg_type)
        
            case KULL_M_PROCESS_CREATE_NORMAL:
                status = CreateProcess(NULL, duplicate_command_Line, NULL, NULL, FALSE, process_flags, NULL, NULL, &startup_info, ptr_process_info);
                break;

            case KULL_M_PROCESS_CREATE_USER:
                status = CreateProcessAsUser(arg_user_token, NULL, duplicate_command_Line, NULL, NULL, FALSE, process_flags, NULL, NULL, &startup_info, ptr_process_info);
                break;

            case KULL_M_PROCESS_CREATE_LOGON:
                status = CreateProcessWithLogonW(arg_user, arg_domain, arg_password, logon_flags, NULL, duplicate_command_Line, process_flags, NULL, NULL, &startup_info, ptr_process_info);
                break;
        

        if (status && (arg_auto_close_handle || !arg_process_infos))
        
            CloseHandle(ptr_process_info->hThread);
            CloseHandle(ptr_process_info->hProcess);
        

        if (!arg_process_infos)
            LocalFree(ptr_process_info);

        free(duplicate_command_Line);
    

【问题讨论】:

附带说明,您可以在错误的地方调用LocalFree(ptr_process_info)。如果arg_process_infos 为空并且_wcsdup() 返回空,则您泄漏ptr_process_infoLocalFree() 需要在 if (ptr_process_info ...) 块内调用,而不是在 if (duplicate_command_Line ...) 块内调用。 当您通过CreateProcessWithLogonW 启动进程时,它将在另一个登录会话中运行,即使您使用与当前运行相同的用户名。从另一端系统执行/使用 conhost.exe 从与控制台应用程序相同的登录会话。因此新进程无法使用您的控制台 (conhost.exe)。因此,即使您没有设置CREATE_NEW_CONSOLE,系统也会像设置了一样运行。 【参考方案1】:

你可以redirected input and output of child process

这是我的测试程序(去掉错误检查)。

家长:

#include <windows.h>
#include <iostream>
#define BUFSIZE 4096 
void main()

    printf("in Parent \n");
    HANDLE R_In, R_Out, R_err, W_In, W_Out, W_err;
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
    SECURITY_ATTRIBUTES saAttr;
    BOOL bSuccess;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    CreatePipe(&R_In, &W_In, &saAttr, 0);
    CreatePipe(&R_Out, &W_Out, &saAttr, 0);
    CreatePipe(&R_err, &W_err, &saAttr, 0);
    PROCESS_INFORMATION process_info;
    STARTUPINFO startup_info;
    RtlZeroMemory(&startup_info, sizeof(STARTUPINFO));
    startup_info.cb = sizeof(STARTUPINFO);
    startup_info.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    startup_info.wShowWindow = SW_HIDE;
    startup_info.hStdInput = R_In;
    startup_info.hStdOutput = W_Out;
    startup_info.hStdError = W_err;

    BOOL ret = CreateProcessWithLogonW(L"username",L"domain",L"password", 0,L"ChildProcess.exe",NULL, CREATE_NO_WINDOW,NULL,NULL,&startup_info,&process_info);
    CloseHandle(R_In);
    CloseHandle(W_Out);
    CloseHandle(W_err);
    CHAR chBuf[BUFSIZE];
    DWORD dwRead, dwWritten;
    bSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
    bSuccess = WriteFile(W_In, chBuf, dwRead, &dwWritten, NULL);
    while (1)
    
        bSuccess = ReadFile(R_Out, chBuf, BUFSIZE, &dwRead, NULL);
        if (bSuccess == 0 & GetLastError() == ERROR_BROKEN_PIPE) // child process exit.
            break;
        bSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
    
    WaitForSingleObject(process_info.hProcess, INFINITE);
    printf("Parent exit\n");

孩子:

#include <windows.h>
#include <iostream>
#define BUFSIZE 4096 
#pragma warning(disable : 4996)
void main()

    CHAR chBuf[BUFSIZE];
    scanf("%s", chBuf);
    printf("in Child %s\n", chBuf);
    printf("Child exit\n");
    return;

结果:

【讨论】:

那么当控制台程序提示输入密码或要求逐个字符输入时会发生什么?【参考方案2】:

你的意思是你不想创建一个新窗口? 尝试startup_info.dwFlags = STARTF_USESHOWWINDOW;startup_info.wShowWindow = SW_HIDE; 则不会创建窗口。

【讨论】:

我希望新进程能够在父环境中执行,而不是创建另一个控制台。 啊,对不起,我没有正确理解。 @KLightning - 如果您使用 CreateProcessWithLogonW - 子进程将在 新登录会话 中执行。它不能在父环境中执行【参考方案3】:

已经有一段时间了,但是通过 DETACHED_PROCESS 应该可以工作。

如果没有,您可以调用CreateProcessWithLogonW 传递一个您提供的win32 二进制文件(可能是您自己的带有不同选项的),然后调用CreateProcess 打开cmd.exe 而不传递CREATE_NEW_CONSOLE

除非你已经是管理员,否则在同一个控制台中创建是完全不可能的,如果你是管理员,那么你最好不要使用它是一种神秘的技术。

【讨论】:

“通过 DETACHED_PROCESS 应该可以工作” - 不。 This value cannot be used with CREATE_NEW_CONSOLE. - 在这种情况下,我们得到错误参数无效。使用第二种变体,我们可以在没有控制台的情况下运行进程。但不使用与父级相同的控制台 @RbMm:从问题中 OP 想要与父级相同的控制台并不是很明显,但如果他这样做了,他需要重新考虑他想要做什么。

以上是关于在没有新控制台的情况下使用 CreateProcessWithLogonW() 执行 CMD.EXE的主要内容,如果未能解决你的问题,请参考以下文章

在没有“应用签名”的情况下为 Google Play 商店中的应用设置新的上传密钥

如何在没有动画的情况下将 UISearchController 设置为活动?

PresentModalViewController 视图在没有动画的情况下移动

如何在没有状态栏重叠的情况下在 iOS7 上呈现视图控制器

TSQL 何时为存储过程中的变量(和表变量)分配内存

如何在没有安装权限的情况下使用新的 Perl 模块?