首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何使用CreateProcess()和CreatePipe()从cmd.exe读取输出

CreateProcess()CreatePipe() 是 Windows API 中的两个函数,用于创建新进程并与其进行通信。CreateProcess() 用于启动一个新进程,而 CreatePipe() 用于创建一个管道,以便在新进程和父进程之间传输数据。

基础概念

  1. CreateProcess():
    • 用于创建一个新的进程和它的主线程。
    • 可以指定要执行的程序文件和命令行参数。
    • 返回一个 PROCESS_INFORMATION 结构体,包含新进程的句柄等信息。
  • CreatePipe():
    • 用于创建一个匿名管道,用于进程间通信。
    • 返回两个句柄,一个用于读取,一个用于写入。
    • 管道是单向的,通常需要创建两个管道来实现双向通信。

相关优势

  • 进程隔离: 通过创建新进程,可以隔离主程序和新进程的资源,避免相互影响。
  • 数据传输: 使用管道可以在进程间安全地传输数据,支持异步读写。

类型

  • 匿名管道: 用于本地进程间通信,不支持跨网络传输。
  • 命名管道: 支持跨网络传输,但需要一个名称来标识管道。

应用场景

  • 自动化脚本执行: 通过读取命令行工具的输出,自动化执行一些任务。
  • 调试和监控: 实时获取进程的输出信息,进行调试和监控。

示例代码

以下是一个简单的示例,展示如何使用 CreateProcess()CreatePipe()cmd.exe 读取输出:

代码语言:txt
复制
#include <windows.h>
#include <iostream>

int main() {
    HANDLE hChildStdOutRead, hChildStdOutWrite;
    SECURITY_ATTRIBUTES saAttr;

    // Set the bInheritHandle flag so pipe handles are inherited.
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create a pipe for the child process's STDOUT.
    if (!CreatePipe(&hChildStdOutRead, &hChildStdOutWrite, &saAttr, 0)) {
        std::cerr << "CreatePipe Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if (!SetHandleInformation(hChildStdOutRead, HANDLE_FLAG_INHERIT, 0)) {
        std::cerr << "SetHandleInformation Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Create the child process.
    PROCESS_INFORMATION piProcInfo;
    STARTUPINFO siStartInfo;
    BOOL bSuccess = FALSE;

    // Set up members of the PROCESS_INFORMATION structure.
    ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

    // Set up members of the STARTUPINFO structure.
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.hStdOutput = hChildStdOutWrite;
    siStartInfo.hStdError = hChildStdOutWrite;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    // Create the child process.
    bSuccess = CreateProcess(NULL,
                             "cmd.exe /c dir",     // command line 
                             NULL,                   // process security attributes 
                             NULL,                   // primary thread security attributes 
                             TRUE,                   // handles are inherited 
                             0,                      // creation flags 
                             NULL,                   // use parent's environment 
                             NULL,                   // use parent's current directory 
                             &siStartInfo,           // STARTUPINFO pointer 
                             &piProcInfo);           // receives PROCESS_INFORMATION 

    // If an error occurs, exit the application. 
    if (!bSuccess) {
        std::cerr << "CreateProcess Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Close the write end of the pipe before reading from the read end of the pipe.
    CloseHandle(hChildStdOutWrite);

    // Read output from the child process's pipe for STDOUT.
    CHAR chBuf[4096];
    DWORD dwRead;
    std::string strOutput;

    while (ReadFile(hChildStdOutRead, chBuf, sizeof(chBuf), &dwRead, NULL) && dwRead != 0) {
        strOutput.append(chBuf, dwRead);
    }

    // Close the read handle.
    CloseHandle(hChildStdOutRead);

    // Wait until child process exits.
    WaitForSingleObject(piProcInfo.hProcess, INFINITE);

    // Close process and thread handles.
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProc::hThread);

    // Output the result.
    std::cout << "Output from cmd.exe:\n" << strOutput << std::endl;

    return 0;
}

参考链接

常见问题及解决方法

  1. 管道句柄继承问题:
    • 确保在 CreatePipe() 后调用 SetHandleInformation() 来防止读取句柄被继承。
    • 示例代码中已包含此步骤。
  • 读取管道数据时的阻塞问题:
    • 使用 ReadFile() 读取管道数据时,可能会阻塞等待数据。可以使用超时参数或异步读取来解决。
    • 示例代码中使用循环读取直到没有数据。
  • 进程等待问题:
    • 在读取完管道数据后,需要等待子进程结束,否则可能会导致子进程成为僵尸进程。
    • 示例代码中使用 WaitForSingleObject() 等待子进程结束。

通过以上步骤和示例代码,你可以实现从 cmd.exe 读取输出的功能。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

17.1 隐藏执行CMD命令

执行本地CMD实现使用CreateProcess函数创建一个新的CMD进程,并将标准输入、输出错误输出重定向到当前进程的标准输入、输出错误输出。...首先来实现一个CMD命令行运行功能,通过使用CreatePipe创建匿名管道,并使用CreateProcess函数创建一个新的CMD进程,然后将标准输入、输出错误输出重定向到当前进程的标准输入、输出错误输出...创建匿名管道后,可以使用ReadFile函数管道的读端读取数据,使用WriteFile函数将数据写入管道的写端。在使用完管道后,应使用CloseHandle函数关闭管道的句柄,以释放资源。...如下RunCommand函数所示,该函数传入一个字符串类型的命令参数,并返回一个字符串执行结果,在函数内部,使用 CreatePipe() 函数创建了一个匿名管道,并使用 CreateProcess()...接着使用 ReadFile() 函数管道的读取读取输出数据,并将读取到的数据存储到一个缓冲区中。最后,它将缓冲区的内容拼接成一个完整的输出结果返回给调用者。

41740
  • WindowsAPI 之 CreatePipeCreateProcess

    一个进程在向管道写入数据后,另 一进程就可以管道的另一端将其读取出来。...匿名管道(Anonymous Pipes)是在父进程子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。...,那么还必须在父进程中创建一个子进程,同时,这个子进程必须能够继承使用父进程的一些公开的句柄,因为在子进程中必须要使用父进程创建的匿名管道的读写句柄,通过这个匿名管道才能实现父子进程的通信,所以必须继承父进程的公开句柄...下面来讲CreatePipe: CreatePipe时会获取两个句柄,一个是读句柄,一个是写句柄(这里的读句柄表示要从哪里读取数据,写句柄表示要把数据写到哪里)。...当父进程向子进程发送数据时,用SetStdHandle()将 管道的读句柄赋予标准输入句柄(这样就不会标准输入读入数据,而读句柄所表示的位置读取数据);在从子进程接收数据时,则用SetStdHandle

    4K10

    1.6 编写双管道ShellCode后门

    在管道创建时,操作系统会为管道分配一段内存区域,该内存区域由创建管道的进程与其通信的进程共享。当进程往管道中写入数据时,数据会被存储在管道的内存缓冲区中,然后等待另一个进程管道中读取数据。...); 其中,hReadPipehWritePipe是PHANDLE类型的指针,用于接收读取写入管道的句柄。...nSize是管道缓冲区的大小,若为0则使用默认大小。在使用CreatePipe函数创建匿名管道后,读者可以使用WriteFile函数往管道中写入数据,也可以使用ReadFile函数管道中读取数据。...读取写入管道的操作需要使用相应的句柄。...如果CMD进程中有可读数据,则使用ReadFile函数读取该数据并使用send函数发送回远程客户端。如果没有数据可读,则程序接收远程客户端发来的命令,并将命令写入管道2,即传给CMD进程。

    16920

    1.6 编写双管道ShellCode后门

    在管道创建时,操作系统会为管道分配一段内存区域,该内存区域由创建管道的进程与其通信的进程共享。当进程往管道中写入数据时,数据会被存储在管道的内存缓冲区中,然后等待另一个进程管道中读取数据。...nSize是管道缓冲区的大小,若为0则使用默认大小。在使用CreatePipe函数创建匿名管道后,读者可以使用WriteFile函数往管道中写入数据,也可以使用ReadFile函数管道中读取数据。...读取写入管道的操作需要使用相应的句柄。...0, NULL, NULL, &si, &ProcessInformation);当CMD子进程启动后,则下一步则是远程攻击机之间建立通信,如下代码通过使用PeekNamedPiperecv函数不断检查远程客户端或...如果CMD进程中有可读数据,则使用ReadFile函数读取该数据并使用send函数发送回远程客户端。如果没有数据可读,则程序接收远程客户端发来的命令,并将命令写入管道2,即传给CMD进程。

    27841

    CreatePipeCreateProcess函数

    一个进程在向管道写入数据后,另 一进程就可以管道的另一端将其读取出来。...匿名管道(Anonymous Pipes)是在父进程子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。...备注 CreatePipe创建管道,将指定的管道大小分配给存储缓冲区。 CreatePipe还会在随后的ReadFileWriteFile函数调用中创建该进程用于读取写入缓冲区的句柄。...要从管道读取,一个进程在调用ReadFile函数时使用读取句柄。当以下任一条件为真时,ReadFile返回:写操作在管道的写入端完成,请求的字节数已被读取或发生错误。...如果CreatePipe失败,输出参数的内容是不确定的。在这个事件中,不应该假设他们的内容。

    1.3K30

    Windows进程通信之一看就懂的匿名管道通信

    分别是父进程读取的管道.以及 子进程读取的管道.相应的.子进程也可以对父进程读取的管道进行传输数据.父进程就可以读取了. 这段话可能难以理解.你可以这样想. 我父进程读取子进程使用第一个管道....那么反正子进程写的话也是使用第一个管道.因为子进程写.我们父进程才能读. 1.3 创建匿名管道需要的步骤 首先你需要了解创建匿名管道的API WINBASEAPI BOOL WINAPI CreatePipe...父读->子写 子读->父写的 3.重定向输出,将子进程的读 以及子进程的写重定向. 4.创建子进程 5.读取\写入数据给子进程. 1.4代码例子 #include #include...父进程读 -> 子进程写入 BOOL bRet = CreatePipe(&hParentRead, &hChildWrite, &sa, 0);...= STARTF_USESTDHANDLES; //设置窗口隐藏启动 bRet = CreateProcess(NULL, "cmd.exe",

    2.1K30

    1.6 编写双管道ShellCode

    在管道创建时,操作系统会为管道分配一段内存区域,该内存区域由创建管道的进程与其通信的进程共享。当进程往管道中写入数据时,数据会被存储在管道的内存缓冲区中,然后等待另一个进程管道中读取数据。...nSize是管道缓冲区的大小,若为0则使用默认大小。在使用CreatePipe函数创建匿名管道后,读者可以使用WriteFile函数往管道中写入数据,也可以使用ReadFile函数管道中读取数据。...读取写入管道的操作需要使用相应的句柄。...0, NULL, NULL, &si, &ProcessInformation);当CMD子进程启动后,则下一步则是远程攻击机之间建立通信,如下代码通过使用PeekNamedPiperecv函数不断检查远程客户端或...如果CMD进程中有可读数据,则使用ReadFile函数读取该数据并使用send函数发送回远程客户端。如果没有数据可读,则程序接收远程客户端发来的命令,并将命令写入管道2,即传给CMD进程。

    35110

    1.6 编写双管道ShellCode

    在管道创建时,操作系统会为管道分配一段内存区域,该内存区域由创建管道的进程与其通信的进程共享。当进程往管道中写入数据时,数据会被存储在管道的内存缓冲区中,然后等待另一个进程管道中读取数据。...); 其中,hReadPipehWritePipe是PHANDLE类型的指针,用于接收读取写入管道的句柄。...nSize是管道缓冲区的大小,若为0则使用默认大小。在使用CreatePipe函数创建匿名管道后,读者可以使用WriteFile函数往管道中写入数据,也可以使用ReadFile函数管道中读取数据。...读取写入管道的操作需要使用相应的句柄。...如果CMD进程中有可读数据,则使用ReadFile函数读取该数据并使用send函数发送回远程客户端。如果没有数据可读,则程序接收远程客户端发来的命令,并将命令写入管道2,即传给CMD进程。

    18430

    gh0st源码分析与远控的编写(三)

    我们在gh0st进程中,开启一个cmd进程,并使用管道,向cmd.exe传送信息,而cmd.exe也利用管道将信息发送给gh0st的进程。管道通信又分三种,双管道、单管道与无管道。...CreatePipe这个API前两个参数是该管道的读句柄写句柄。读句柄就是该管道的入口,写句柄就是该管道的出口。...到此,创建了一个进程(cmd.exe)两根管道了。...如果有内容我们就使用ReadFile读取管道中内容,并Send到主控端去。     说到这里,有些人就要问了。...你只说了怎么管道里读取内容发送给主控端,但我们被控端怎么主控端接收内容并发送给管道呢?     上节课最后我们说了,“OnReceive函数在CManager中定义,但并未实现”。

    1.1K30

    CreatePipe匿名管道通信

    一个进程在向管道写入数据后,另一进程就可以管道的另一端将其读取出来。...匿名管道(Anonymous Pipes)是在父进程子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。     ...匿名管道实施细则     匿名管道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:管道读句柄管道写句柄。...然后,父进程调用ReadFile()管道读取出数据(传递管道读句柄给函数)。     ...匿名管道并不支持异步读、写操作,这也就意味着不能在匿名管道中使用ReadFileEx()WriteFileEx(),而且ReadFile()WriteFile()中的lpOverLapped参数也将被忽略

    1K10

    如何在父进程中读取子(外部)进程的标准输出标准错误输出结果

    最近接手一个小项目,要求使用谷歌的aapt.exe获取apk软件包中的信息。依稀记得去年年中时,有个同事也问过我如何获取被调用进程的输出结果,当时还研究了一番,只是没有做整理。...比如我文前提到的问题:别人提供了一个Console控制台程序,我们将如何获取其执行的输出结果呢?...这个问题,微软以为为我们考虑过了,我们可以从一个API中可以找到一些端倪——CreateProcess。...那么如何使用这些参数呢?         我们选用的还是老方法——管道。...我们使用STARTF_USESTDHANDLES的原因是:我们使用了标准输出标准错误输出句柄。

    3.9K10
    领券