Hi this is my first question on stack overflow (Im a junior programmer :P and french too...So apologies in advance for gramatical mistake I make)
Im trying to start a elevated process to attach back to the console of the parent to write its output
(no crash no error just plain nothingness)
Here is my code:
int main(int argc, char *argv[]) { HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); if (UAC::IsAppRunningAsAdminMode()) { printf("Process Already elevated\nChecking if self invocated from unprevileged previous run...\n"); if (argc > 1) { std::string consoleTextOutputBuffer("Elevated privileges session started...\n"); WriteConsoleA((HANDLE)argv[2], consoleTextOutputBuffer.c_str(), consoleTextOutputBuffer.size(), NULL, NULL); } } else { printf("Process need elevation...\n"); if (UAC::BeginPrivilegeElevationPrompt(consoleHandle)) { printf("Elevation succesfull!\n"); } else { printf("Elevation failed\n"); system("pause>nul"); exit(-1); } } }
And From the class UAC that I wrote:
BOOL BeginPrivilegeElevationPrompt(const HANDLE& oldConsoleHandle) { wchar_t szPath[MAX_PATH]; if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) { // Launch itself as admin std::string oldConsoleHandleToString = std::to_string((int)oldConsoleHandle); std::wstring wsConsoleString(oldConsoleHandleToString.begin(), oldConsoleHandleToString.end()); SHELLEXECUTEINFO sei = { sizeof(sei) }; sei.lpVerb = L"runas"; sei.lpFile = szPath; sei.hwnd = NULL; sei.lpParameters = wsConsoleString.c_str(); sei.nShow = SW_NORMAL; if (!ShellExecuteEx(&sei)) { DWORD dwError = GetLastError(); if (dwError == ERROR_CANCELLED) { // The user refused to allow privileges elevation. printf("User did not allow elevation.\n"); return false; } return false; } else { return true; _exit(1); // Quit itself } } printf("Could not load module name.\n"); return false; };
There are TWO ways that I know of to communicate with a child process directly.. One is to use pipes.. This allows you to write to the child process and also read from it: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
#include <windows.h> #include <string> #include <fstream> #include <thread> #include <chrono> PROCESS_INFORMATION CreateChildProcess(std::string CommandLine, std::string StartDirectory, DWORD WaitTime, HANDLE hInRead, HANDLE hOutWrite) { STARTUPINFO SI; PROCESS_INFORMATION PI; ZeroMemory(&SI, sizeof(SI)); ZeroMemory(&PI, sizeof(PI)); SI.cb = sizeof(SI); SI.hStdInput = hInRead; SI.hStdError = hOutWrite; SI.hStdOutput = hOutWrite; SI.dwFlags |= STARTF_USESTDHANDLES; bool success = CreateProcess(0, &CommandLine[0], 0, 0, true, NORMAL_PRIORITY_CLASS, 0, StartDirectory.c_str(), &SI, &PI); if (success) { if (WaitTime != 0) { WaitForSingleObject(PI.hProcess, WaitTime); CloseHandle(PI.hProcess); CloseHandle(PI.hThread); return {0}; } return PI; } return {0}; } void RedirectInputPipe(HANDLE& hRead, HANDLE& hWrite) { SECURITY_ATTRIBUTES attr; ZeroMemory(&attr, sizeof(attr)); attr.nLength = sizeof(attr); attr.bInheritHandle = true; CreatePipe(&hRead, &hWrite, &attr, 0); SetHandleInformation(hWrite, HANDLE_FLAG_INHERIT, 0); } void RedirectOutputPipe(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 ReadPipe(HANDLE hOutput, std::string& Buffer) { DWORD dwRead = 0; Buffer.clear(); Buffer.resize(256); bool Result = ReadFile(hOutput, &Buffer[0], Buffer.size(), &dwRead, NULL); Buffer.resize(dwRead); return Result && dwRead; } bool WritePipe(HANDLE hInput, const char* Buffer, unsigned int BufferSize) { DWORD dwWritten = 0; return WriteFile(hInput, Buffer, BufferSize, &dwWritten, NULL) && (dwWritten == BufferSize); } void HandleRead(HANDLE hOutputRead, bool &Termination) { std::string Buffer; HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); while(!Termination) { if (!ReadPipe(hOutputRead, Buffer)) { if (GetLastError() == ERROR_BROKEN_PIPE) break; } WritePipe(ConsoleOutput, Buffer.c_str(), Buffer.size()); if (output) { std::cout.write(Buffer.c_str(), Buffer.size()); } Buffer.clear(); } CloseHandle(ConsoleOutput); } int main() { std::string process = "ChildProcess.exe"; std::string startdir = "C:/Users/Brandon/Desktop/Test/bin"; HANDLE hInputRead, hInputWrite, hOutputRead, hOutputWrite; RedirectInputPipe(hInputRead, hInputWrite); RedirectOutputPipe(hOutputRead, hOutputWrite); PROCESS_INFORMATION PI = CreateChildProcess(process, startdir, 0, hInputRead, hOutputWrite); bool Termination = false; std::thread(HandleRead, hOutputRead, std::ref(Termination)).detach(); WaitForSingleObject(PI.hProcess, INFINITE); Termination = true; CloseHandle(PI.hProcess); CloseHandle(PI.hThread); CloseHandle(hInputRead); CloseHandle(hInputWrite); CloseHandle(hOutputRead); CloseHandle(hOutputWrite); return 0; }
It works by creating the child process with an input output handle to a pipe.. then create a thread that constantly polls/reads the pipe and prints out whatever it is writing.. cleanup when done..
The next way is to call AttachConsole(ATTACH_PARENT_PROCESS)
according to the WinAPI docs.. This will attach the child process to the parent process' console. You need to call FreeConsole
when done to detach from the parent process' console: https://docs.microsoft.com/en-us/windows/console/attachconsole
Finnaly I found a way to achieve what I wanted
I passed the parent PID to the child process by argument and then I used AttachConsole(PID)
voila!
Thank for the help of everyone