Привет это мой первый вопрос по переполнению стека
(Я младший программист: P и французский тоже … Так что заранее извиняюсь за грубую ошибку, которую я делаю)
Я пытаюсь запустить процесс с повышенными правами, чтобы прикрепить обратно к консоли родителя, чтобы записать свой вывод
(без сбоев, без ошибок, просто простота)
Вот мой код:
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);
}
}
}
И из класса UAC, который я написал:
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;
};
Есть два способа, которыми я знаю, чтобы общаться с дочерним процессом напрямую. Один из них — использовать каналы. Это позволяет вам писать дочернему процессу, а также читать из него: 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;
}
Он работает, создавая дочерний процесс с дескриптором ввода-вывода в канал … затем создайте поток, который постоянно опрашивает / читает канал и выводит на печать все, что он пишет … очистка после завершения …
Следующий способ — позвонить AttachConsole(ATTACH_PARENT_PROCESS)
в соответствии с документацией WinAPI. Это прикрепит дочерний процесс к консоли родительского процесса. Вам нужно позвонить FreeConsole
когда сделано, чтобы отсоединиться от консоли родительского процесса: https://docs.microsoft.com/en-us/windows/console/attachconsole
В конце концов я нашел способ добиться того, чего хотел
Я передал родительский PID дочернему процессу по аргументу, а затем использовал AttachConsole (PID)
вуаля!
Спасибо всем за помощь