Winsock, command line on a remote server - c++

I'm new with winsock, i work in linux enviroment, I am trying to write a program where the client will connect on a shell server, I am having trouble sending output to client, I have not develope the full client yet, I'm using netcat for testing,
but do not get the data in the output...
someone can give help to improve this code?
what should I do so that the client receives the output of cmd command ?
int Socket_Manip::SHELL() {
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset((void *)&si, 0, sizeof(si));
memset((void *)&pi, 0, sizeof(pi));
si.wShowWindow = SW_HIDE;
si.hStdInput = (HANDLE)ClientSocket;
si.hStdOutput = (HANDLE)ClientSocket;
si.hStdError = (HANDLE)ClientSocket;
CreateProcess(NULL,"cmd", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
return 0;
}

You cannot use a socket to redirect CreateProcess() I/O. Use pipes from CreatePipe() instead. Refer to MSND for an example:
Creating a Child Process with Redirected Input and Output
You will have to write some monitoring code that passes data back and forth between the pipes and socket as needed. Try something like this:
struct sThreadInfo
{
SOCKET Socket;
HANDLE hStdIn;
HANDLE hStdOut;
bool Stop;
};
DWORD WINAPI ClientSocketToShell(LPVOID lpParameter)
{
sThreadInfo *ti = (sThreadInfo*) lpParameter;
BYTE buffer[1024];
DWORD BytesWritten;
fd_set rds;
while (!ti->Stop)
{
FD_ZERO(&rds);
FD_SET(ti->Socket, &rds);
timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
int ret = select(0, &rds, NULL, NULL, &timeout);
if (ret < 0)
break;
if (ret > 0)
{
ret = recv(ti->Socket, buffer, sizeof(buffer), 0);
if (ret <= 0)
break;
if (!WriteFile(ti->hStdIn, buffer, ret, &BytesWritten, NULL))
break;
}
}
return 0;
}
DWORD WINAPI ShellToClientSocket(LPVOID lpParameter)
{
sThreadInfo *ti = (sThreadInfo*) lpParameter;
BYTE buffer[1024];
DWORD BytesAvailable, BytesRead;
while (!ti->Stop)
{
if (!PeekNamedPipe(ti->hStdOut, NULL, 0, NULL, &BytesAvailable, NULL))
break;
if (BytesAvailable != 0)
{
if (!ReadFile(ti->hStdOut, buffer, min(sizeof(buffer), BytesAvailable), &BytesRead, NULL))
break;
ret = send(ti->Socket, buffer, BytesRead, 0);
if (ret <= 0)
break;
}
else
Sleep(1000);
}
return 0;
}
int Socket_Manip::SHELL()
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
HANDLE hStdIn_Rd = NULL;
HANDLE hStdIn_Wr = NULL;
HANDLE hStdOut_Rd = NULL;
HANDLE hStdOut_Wr = NULL;
if (!CreatePipe(&hStdOut_Rd, &hStdOut_Wr, &saAttr, 0))
return 0;
SetHandleInformation(hStdOut_Rd, HANDLE_FLAG_INHERIT, 0);
if (!CreatePipe(&hStdIn_Rd, &hStdIn_Wr, &saAttr, 0))
{
CloseHandle(hStdOut_Rd);
CloseHandle(hStdOut_Wr);
return 0;
}
SetHandleInformation(hStdIn_Wr, HANDLE_FLAG_INHERIT, 0);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdError = hStdOut_Wr;
si.hStdOutput = hStdOut_Wr;
si.hStdInput = hStdIn_Rd;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
TCHAR cmd[] = TEXT("cmd");
if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
sThreadInfo ti;
ZeroMemory(&ti, sizeof(ti));
ti.Socket = ClientSocket;
ti.hStdIn = hStdIn_Wr;
ti.hStdOut = hStdOut_Rd;
ti.Stop - false;
HANDLE Handles[3];
DWORD dwThreadID;
ZeroMemory(Handles, sizeof(Handles));
Handles[0] = pi.hProcess;
Handles[1] = CreateThread(NULL, 0, &ClientSocketToShell, &ti, 0, &dwThreadID);
Handles[2] = CreateThread(NULL, 0, &ShellToClientSocket, &ti, 0, &dwThreadID);
DWORD ret = WaitForMultipleObjects(3, Handles, FALSE, INFINITE);
ti.Stop = true;
if (ret != WAIT_OBJECT_0)
TerminateProcess(pi.hProcess, 0);
WaitForMultipleObjects(2, &Handles[1], TRUE, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(Handles[1]);
CloseHandle(Handles[2]);
}
CloseHandle(hStdIn_Rd);
CloseHandle(hStdIn_Wr);
CloseHandle(hStdOut_Rd);
CloseHandle(hStdOut_Wr);
return 0;
}

Related

C++ on Windows: Pipe to stdin not properly transferring data + ReadFile stucks when reading from pipe

I tried to create a pwntools-like program for windows. I implemented a send and recv to send data to stdin of a and to receive data from stdout. I did that using pipes.
#include <iostream>
#include <cstdio>
#include <windows.h>
void spawn();
void pwn_send(CONST CHAR chBuf[]);
CHAR* pwn_recv(SIZE_T sz);
CHAR* pwn_recv();
HANDLE stdout_write = NULL;
HANDLE stdout_read = NULL;
HANDLE stdin_write = NULL;
HANDLE stdin_read = NULL;
int main() {
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if(!CreatePipe(&stdout_read, &stdout_write, &saAttr, 0)) return -1;
if(!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) return -1;
if(!CreatePipe(&stdin_read, &stdin_write, &saAttr, 0)) return -1;
if(!SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0)) return -1;
spawn();
CHAR chBuf[] = "mkdir C:\\Users\\comma\\Desktop\\x\r\n";
pwn_send(chBuf);
std::cout << pwn_recv(20) << std::endl;
return 0;
}
void spawn() {
TCHAR cmd[] = TEXT("cmd.exe");
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.hStdError = stdout_write;
si.hStdOutput = stdout_write;
si.hStdInput = stdin_read;
si.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&pi, sizeof(pi));
if(!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) exit(-1);
return;
}
void pwn_send(CONST CHAR chBuf[]) {
DWORD dwRead = 0, dwWritten = 0;
BOOL bSuccess = FALSE;
while(1) {
bSuccess = WriteFile(stdin_write, chBuf, strlen(chBuf), &dwWritten, NULL);
if (bSuccess) break;
}
CloseHandle(stdin_write);
return;
}
CHAR* pwn_recv(SIZE_T sz) {
HANDLE hHeap = GetProcessHeap();
DWORD dwRead = 0, dwWritten = 0;
BOOL bSuccess = FALSE;
CHAR* chBuf = (CHAR*)HeapAlloc(hHeap, 0, sz+1);
while (1) {
std::cout << "XXX" << std::endl;
bSuccess = ReadFile(stdout_read, chBuf, sz, &dwRead, NULL);
std::cout << "YYY" << std::endl;
if (bSuccess) break;
}
return chBuf;
}
CHAR* pwn_recv() {
HANDLE hHeap = GetProcessHeap();
DWORD dwRead = 0, dwWritten = 0;
BOOL bSuccess = FALSE;
CHAR* chBuf = (CHAR*)HeapAlloc(hHeap, 0, 0x1000);
while (1) {
bSuccess = ReadFile(stdout_read, chBuf, 0x1000, &dwWritten, NULL);
if (bSuccess) break;
}
return chBuf;
}
So the first issue here is that the program I started with spawn(cmd.exe) doesn't properly receive the command I send to stdin. No folder is created anywhere. CreateProcess succeeds. Receiving output doesn't work either, because ReadFile seems to stuck. XXX is displayed in the console, butYYY never. Any ideas?

WINAPI CreateProcess child process is not running

I'm using the article in msdn creating child process because it's pretty close to what I want to achieve.
The questions in creating a child process c#, redirection using pipes
were helpful do find a few error on my approach but there are mostl likely more errors than what I was able to find.
I'm trying to create a connection between parent and child processes using pipes where they are able to write and read to each others StdOut. In my solution I created two console applications named ParentTalk and ChildTalk.
From what I was able to see the child process is not running the code I created for it so I might be creating the child process wrongly
Parent.cpp
#include <windows.h>
#include "pch.h"
#include <iostream>
#include <stdio.h>
HANDLE childInRead = NULL;
HANDLE childInWrite = NULL;
HANDLE childOutRead = NULL;
HANDLE childOutWrite = NULL;
HANDLE parentInRead = NULL;
#define BUFSIZE 4096
void CreateChildProcess() {
TCHAR applicationName[] = TEXT("ChildTalk.exe");
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL success = FALSE;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdError = childInRead;
si.hStdOutput = childInRead;
si.hStdInput = childOutWrite;
si.dwFlags |= STARTF_USESTDHANDLES;
success = CreateProcess(NULL, applicationName, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
if (!success) {
printf("Error creating child process \n");
}
else {
printf("Child process successfuly created \n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
int main()
{
printf("Parent process running.... \n");
DWORD dRead, dWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
SECURITY_ATTRIBUTES secAttr;
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.bInheritHandle = TRUE;
secAttr.lpSecurityDescriptor = NULL;
printf("Creating first pipe \n");
if (!CreatePipe(&parentInRead, &childInWrite, &secAttr, 0)) {
printf("\n error creating first pipe \n");
}
printf("Creating second pipe \n");
if (!CreatePipe(&childOutWrite, &childOutRead, &secAttr, 0)) {
printf("\n error creating second pipe \n");
}
if (!SetHandleInformation(parentInRead, HANDLE_FLAG_INHERIT, 0)) {
printf("\n parentInRead SetHandleInformation \n");
}
if (!SetHandleInformation(childInWrite, HANDLE_FLAG_INHERIT, 0)) {
printf("\n childInWrite SetHandleInformation \n");
}
childOutRead = GetStdHandle(STD_OUTPUT_HANDLE);
parentInRead = GetStdHandle(STD_INPUT_HANDLE);
printf("\n Creating child process..... \n");
CreateChildProcess();
for (;;){
printf("Inside for loop \n");
bSuccess = ReadFile(parentInRead, chBuf, BUFSIZE, &dRead, NULL);
if (!bSuccess) {
printf("error reading \n");
break;
}
bSuccess = WriteFile(childInWrite, chBuf,
dRead, &dWritten, NULL);
if (!bSuccess) {
printf("error writing \n");
break;
}
}
return 0;
}
ChildTalk.cpp
#include <windows.h>
#include <stdio.h>
#include "pch.h"
#define BUFSIZE 4096
int main()
{
DWORD dRead, dWritten;
CHAR chBuf[BUFSIZE];
BOOL success = FALSE;
HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
printf("Child process running....");
if (stdIn == INVALID_HANDLE_VALUE || stdOut == INVALID_HANDLE_VALUE) {
ExitProcess(1);
}
for (;;) {
success = ReadFile(stdIn, chBuf, BUFSIZE, &dRead, NULL);
if (!success || dRead == 0) break;
success = WriteFile(stdOut, chBuf, dRead, &dWritten, NULL);
if (!success) break;
}
return 0;
}
EDIT1: There's no errors while running the code, the program stays at
bSuccess = WriteFile(childStdOut, chBuf,
dRead, &dWritten, NULL);
if (!bSuccess) {
printf("error writing");
break;
}
because it's waiting for input but when I type anything it print the "error writing" message. The message that I added to the child code "Child process running...." isnt printed
EDIT2: Changed code because i think the Handles were incorrect now it's printing "Inside for loop" but still no child process. Do I need to launch the console application of the child process first?
There are some errors in your code.
First,
childOutRead = GetStdHandle(STD_OUTPUT_HANDLE);
parentInRead = GetStdHandle(STD_INPUT_HANDLE);
the 2 handle get from CreatePipe, have been reseted to stdhandle, and lost the pipe handle.
Second,
CreatePipe(&childOutWrite, &childOutRead, &secAttr, 0);
should be CreatePipe(&childOutRead, &childOutWrite, &secAttr, 0)
Third,
the handle in SetHandleInformation() is not correct.
Well, let's return your question.
For the hiding of child process, its stdin/stdout handle are seted to pipe handle, so you are not able see the console, but it does run in the background.
I did some change with your example(for simplicity, asynchrony is not used):
Parent.cpp
#include <windows.h>
#include <iostream>
#include <stdio.h>
HANDLE childInRead = NULL;
HANDLE W1 = NULL;
HANDLE W2 = NULL;
HANDLE R2 = NULL;
HANDLE R1 = NULL;
#define BUFSIZE 4096
void CreateChildProcess() {
TCHAR applicationName[] = TEXT("ChildTalk.exe");
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL success = FALSE;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdError = W1;
si.hStdOutput = W1;
si.hStdInput = R2;
si.dwFlags |= STARTF_USESTDHANDLES;
success = CreateProcess(NULL, applicationName, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if (!success) {
printf("Error creating child process \n");
}
else {
printf("Child process successfuly created \n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
int main()
{
printf("Parent process running.... \n");
DWORD dRead, dWritten;
CHAR chBuf[BUFSIZE] = "hello";
BOOL bSuccess = FALSE;
SECURITY_ATTRIBUTES secAttr;
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.bInheritHandle = TRUE;
secAttr.lpSecurityDescriptor = NULL;
printf("Creating first pipe \n");
if (!CreatePipe(&R1, &W1, &secAttr, 0)) {
printf("\n error creating first pipe \n");
}
printf("Creating second pipe \n");
if (!CreatePipe(&R2, &W2, &secAttr, 0)) {
printf("\n error creating second pipe \n");
}
if (!SetHandleInformation(R1, HANDLE_FLAG_INHERIT, 0)) {
printf("\n R1 SetHandleInformation \n");
}
if (!SetHandleInformation(W2, HANDLE_FLAG_INHERIT, 0)) {
printf("\n W1 SetHandleInformation \n");
}
printf("\n Creating child process..... \n");
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
CreateChildProcess();
for (;;) {
printf("Inside for loop \n");
//1. read from stdin
bSuccess = ReadFile(hStdIn, chBuf, BUFSIZE, &dRead, NULL);
if (!bSuccess) {
printf("error reading \n");
break;
}
//2. write to Pipe2
bSuccess = WriteFile(W2, chBuf, 100, &dWritten, NULL);
if (!bSuccess) {
printf("error reading \n");
break;
}
//3. read from Pipe1
bSuccess = ReadFile(R1, chBuf, BUFSIZE, &dRead, NULL);
if (!bSuccess) {
printf("error reading \n");
break;
}
//4. write to stdout
bSuccess = WriteFile(hStdOut, chBuf, 100, &dWritten, NULL);
if (!bSuccess) {
printf("error reading \n");
break;
}
}
return 0;
}
And Its logical process:

C ++ Inter Process Communication using redirected Input and Output not work with release build

I'm working on a project which needed to create a child process and re-directed its input and output to the parent process.
I'm following this example on MSDN (link). Currently it works with debug build, but not release build. I can't figure it out why. Please help me
The coding of the child process as follow (very similar to the example):
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string>
#include <Iepmapi.h>
#include <Wininet.h>
#include <vector>
#define BUFSIZE 4096
using namespace std;
vector<wstring> subStringByString(wstring input, wstring delimiter)
{
int pos = input.find(delimiter);
vector<wstring> arr;
while (pos != wstring::npos)
{
wstring token = input.substr(0, pos);
arr.push_back(token);
input = input.substr(pos + delimiter.size(), input.size());
pos = input.find(delimiter);
}
arr.push_back(input);
return arr;
}
int main(void)
{
WCHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL bSuccess;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (
(hStdout == INVALID_HANDLE_VALUE) ||
(hStdin == INVALID_HANDLE_VALUE)
)
ExitProcess(1);
// Send something to this process's stdout using printf.
printf("\n ** This is a message from the child process. ** \n");
// This simple algorithm uses the existence of the pipes to control execution.
// It relies on the pipe buffers to ensure that no data is lost.
// Larger applications would use more advanced process control.
int rc = 0;
for (;;)
{
// Read from standard input and stop on error or no data.
bSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
wstring input = wstring(chBuf);
wstring delimiter = L" ";
vector<wstring> arr = subStringByString(input, delimiter);
int rc = 0;
if (!bSuccess || dwRead == 0)
break;
if (IESetProtectedModeCookie(arr[0].c_str(), arr[1].c_str(), arr[2].c_str(), INTERNET_COOKIE_THIRD_PARTY) != S_OK)
{
DWORD error = GetLastError();
rc = -27;
}
// Write to standard output and stop on error.
if (rc == 0 )
bSuccess = WriteFile(hStdout, L"0", dwRead, &dwWritten, NULL);
else
bSuccess = WriteFile(hStdout, L"-27", dwRead, &dwWritten, NULL);
if (!bSuccess)
break;
}
return 0;
}
Thanks,
Vinh
Parent process code:
std::wstring invoke(const std::wstring input)
{
if (!CreateChildProcess())
return L"error";
DWORD dwRead, dwWritten;
WCHAR chBuf[BUFSIZE] ;
const WCHAR* temp = input.c_str();
wcscpy(chBuf, temp);
BOOL bSuccess = FALSE;
for (;;)
{
bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess) break;
}
CloseHandle(g_hChildStd_IN_Wr);
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess) break;
bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess) break;
}
//TerminateProcess(_processId, 0);
return std::wstring(&chBuf[0]);
}
bool CreateChildProcess(void)
{
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 STDIN.
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
return false;
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
{
cleanUpHandle();
return false;
}
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
{
cleanUpHandle();
return false;
}
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
{
cleanUpHandle();
return false;
}
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
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.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
HANDLE hToken = NULL;
HANDLE hNewToken = NULL;
bSuccess = OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE |
TOKEN_ADJUST_DEFAULT |
TOKEN_QUERY |
TOKEN_ASSIGN_PRIMARY,
&hToken);
if (!bSuccess) {
return 0;
}
hNewToken = CreateLowLevelToken(hToken);
wa_wstring deploymentPath;
if (WAAPI_FAILED(ProcessUtils::getDeploymentPath(deploymentPath)))
{
return false;
}
wa_wstring path = deploymentPath + wa_wstring(PROCESS_PATH);
LPTSTR szCmdline = wstring_to_LPTSTR(path);
if (_processId != 0)
{
TerminateProcess(_processId, 0);
}
TCHAR szCmdline2[] = PROCESS_PATH;
bSuccess = CreateProcessAsUser(hNewToken, NULL, szCmdline2, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo, &piProcInfo);
DWORD error = GetLastError();
if (!bSuccess)
{
cleanUpHandle();
return false;
}
else {
_processId = piProcInfo.dwProcessId;
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
return true;
}
I found the problem.
In "debug build, the value of dwRead, dwWritten are trash value, however, the value of those in relase build are 0. Which cause the parent hang.
To fix this :
DWORD dwRead = -1, dwWritten = -1;

read child process's output while it is alive

I have created two pipes with
saAttr.bInheritHandle = TRUE;
...
CreatePipe(&childStdOut_Rd, &childStdOut_Wr, &saAttr, 0);
CreatePipe(&childStdErr_Rd, &childStdErr_Wr, &saAttr, 0);
Then i have created child process with next STARTUPINFO:
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_MINIMIZE;
si.hStdError = childStdErr_Wr;
si.hStdOutput = childStdOut_Wr;
si.hStdInput = INVALID_HANDLE_VALUE;
si.dwFlags |= STARTF_USESTDHANDLES;
Then closed write handles in parent process:
CloseHandle(childStdErr_Wr);
CloseHandle(childStdOut_Wr);
I wait while child process finishes with
WaitForSingleObject(pi.hProcess, INFINITE);
As i read on MSDN i can read chil process's stdout with:
for (;;)
{
BOOL bSuccess = ReadFile(childStdOut_Rd, chBuf, bufsize, &dwRead, NULL);
if(!bSuccess || dwRead == 0) break;
bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess) break;
}
Q: But where i must put code to read child's output?
Why i can't read cout and printf with these pipes?
Like this I guess..
ChildProcess -- main.cpp:
#include <iostream>
#include <windows.h>
int main()
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hOut)
return 0;
DWORD WriteCount = 0;
char Buffer[1024] = {0};
strcat(&Buffer[0], "Hello? Momma?!");
int Length = strlen(Buffer);
for (int i = 0; i < 10; ++i)
{
if (!WriteFile(hOut, Buffer, Length, &WriteCount, 0))
break;
}
return 0;
}
ParentProcess -- main.cpp
#include <iostream>
#include <windows.h>
void RedirectIO(HANDLE &hRead, HANDLE &hWrite)
{
SECURITY_ATTRIBUTES attr;
ZeroMemory(&attr, sizeof(attr));
attr.nLength = sizeof(attr);
attr.bInheritHandle = true;
CreatePipe(&hRead, &hWrite, &attr, 0);
SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
}
bool CreateChild(std::string CommandLine, DWORD WaitTime, HANDLE hInRead, HANDLE hOutWrite)
{
STARTUPINFO SI;
PROCESS_INFORMATION PI;
ZeroMemory(&SI, sizeof(SI));
ZeroMemory(&PI, sizeof(PI));
SI.cb = sizeof(SI);
SI.hStdError = hOutWrite;
SI.hStdInput = hInRead;
SI.hStdOutput = hOutWrite;
SI.dwFlags |= STARTF_USESTDHANDLES;
bool success = CreateProcess(0, const_cast<char*>(CommandLine.c_str()), 0, 0, true, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, 0, 0, &SI,&PI);
if (success)
{
WaitForSingleObject(PI.hProcess, WaitTime);
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
}
return success;
}
int main()
{
HANDLE hRead = nullptr;
HANDLE hWrite = nullptr;
RedirectIO(hRead, hWrite);
CreateChild("C:/Users/School/Desktop/ChildProcess/bin/Debug/ChildProcess.exe", INFINITE, nullptr, hWrite);
DWORD ReadCount = 0;
char Buffer[1024] = {0};
std::string data = std::string();
while(true)
{
if (!ReadFile(hRead, Buffer, sizeof(Buffer) / sizeof(char), &ReadCount, 0))
break;
if (!ReadCount) break;
Buffer[ReadCount] = '\0';
data.append(&Buffer[0], ReadCount);
std::cout<<"Read From Child:\n\n"<<data<<"\n";
}
return 0;
}
It should print Hello? Momma?! 10 times.. Another option is the place the reading right after the WaitForSingleObject so that you don't close the process immediately and you can keep communicating with it. Maybe even create a thread and read in that thread or have the thread spawn the process and read.. Up to you.

CreateProcessAsUser memory leak

I have a service that runs the following code.
Every time that CreateProcessAsUser is hit, the memory is increased in 4K (I can see it in the Task Manager). That's not happening when I use in CreateProcess.
Why it's happening and how I can release this memory?
PWTS_SESSION_INFO pSessionInfo = 0;
DWORD dwCount = 0;
int dwSessionId = 0;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
for(DWORD i = 0; i < dwCount; ++i)
{
WTS_SESSION_INFO si = pSessionInfo[i];
if (WTSActive == si.State)
{
dwSessionId = si.SessionId;
break;
}
}
WTSFreeMemory(pSessionInfo);
HANDLE currentToken;
BOOL bRet = WTSQueryUserToken(dwSessionId, &currentToken);
if (bRet == false)
{
return 0;
}
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (CreateProcessAsUser(currentToken, "MY_EXE.exe", "MY_ARGS_STR", NULL, NULL, false, 0, NULL, NULL, &si, &pi))
{
if (pi.hProcess != NULL)
{
CloseHandle(pi.hProcess);
}
if (pi.hThread != NULL)
{
CloseHandle(pi.hThread);
}
}
CloseHandle(currentToken);
return 0;