I read a couple of posts on how to check if a process has exited from a different process (I realize some people get hung up on semantics here, but just humor me) and I tried to implement it but am running into the error code 5 ("ERROR_ACCESS_DENIED") all over the place.
Here is what I do.
1) Process 1 (P1) launches process 2 and writes to a shared memory location its own PID.
2) Process 2 (P2) reads the PID from shared memory
3) P2 calls OpenProcess(...) with P1's PID to save a handle that it can check later.
4) P2 calls GetExitCodeProcess(...) with P1's PID repeatedly and checks for a STILL_ACTIVE code.
In the above method, I keep getting the ACCESS_DENIED error on GetExitCodeProcess. I've tried modifying P2's privileges by using the below code from MSDN's docs:
HANDLE proc_h = OpenProcess(SYNCHRONIZE, FALSE, GetCurrentProcessId());
HANDLE hToken;
OpenProcessToken(proc_h, TOKEN_ADJUST_PRIVILEGES, &hToken);
LookupPrivilegeValue(NULL, lpszPrivilege, &luid );
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Enable the privilege
AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL);
But I keep getting the ACCESS_DENIED error on the call to OpenProcessToken(...) method. So does this indicate some sort of system level hurdle? I do have admin rights on my machine and I'm running XP.
Thanks in advance for any help.
The handle passed to GetExitCodeProcess requires PROCESS_QUERY_INFORMATION access right.
The following works fine:
int main(int a_argc, char** a_argv)
{
int pid = atoi(*(a_argv + 1));
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (NULL != h)
{
Sleep(2000);
DWORD exit_code;
if (FALSE == GetExitCodeProcess(h, &exit_code))
{
std::cerr << "GetExitCodeProcess() failure: " <<
GetLastError() << "\n";
}
else if (STILL_ACTIVE == exit_code)
{
std::cout << "Still running\n";
}
else
{
std::cout << "exit code=" << exit_code << "\n";
}
}
else
{
std::cerr << "OpenProcess() failure: " << GetLastError() << "\n";
}
return 0;
}
Instead of polling on GetExitCodeProcess open the handle with SYNCHRONIZE and wait for it to exit:
int main(int a_argc, char** a_argv)
{
int pid = atoi(*(a_argv + 1));
HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (NULL != h)
{
WaitForSingleObject(h, 5000); // Change to 'INFINITE' wait if req'd
DWORD exit_code;
if (FALSE == GetExitCodeProcess(h, &exit_code))
{
std::cerr << "GetExitCodeProcess() failure: " <<
GetLastError() << "\n";
}
else if (STILL_ACTIVE == exit_code)
{
std::cout << "Still running\n";
}
else
{
std::cout << "exit code=" << exit_code << "\n";
}
}
else
{
std::cerr << "OpenProcess() failure: " << GetLastError() << "\n";
}
return 0;
}
OpenProcesstoken requires PROCESS_QUERY_INFORMATION you are opening the process with only SYNCHRONIZE access. See if you add | PROCESS_QUERY_INFORMATION if it works.
If you just want P2 to do something when P1 exits, there's another way that's probably rather easier: have P1 create a pipe and let P2 inherit a handle to that pipe. In P2, execute a read from the pipe. When P2's call to ReadFile returns with an error of ERROR_BROKEN_PIPE, P1 has exited.
Related
My problem is that I can't get output from the command line using pipes.
My task: "Redirect the command input stream to cmd.exe | output the result of the cmd.exe command to the main process."
#include <iostream>
#include <windows.h>
using namespace std;
#define deffBuffSize 1024
int funSC() {
HANDLE writeToCL, readFromCL, writeToProcess, readFromProcess;
char lpCmdLine[] = "cmd.exe /k ipconfig";
STARTUPINFOA siA;
PROCESS_INFORMATION piApp;
SECURITY_ATTRIBUTES secAttr;
ZeroMemory(&secAttr, sizeof(SECURITY_ATTRIBUTES));
ZeroMemory(&siA, sizeof(STARTUPINFOA));
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.lpSecurityDescriptor = NULL;
secAttr.bInheritHandle = TRUE;
if (CreatePipe(&readFromCL, &writeToProcess, &secAttr, 0) == 0) {
cout << "Create pipe error :: " << GetLastError() << endl;
return 1;
}
if (!SetHandleInformation(writeToProcess, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
if (CreatePipe(&readFromProcess, &writeToCL, &secAttr, 0) == 0) {
cout << "Create pipe error :: " << GetLastError() << endl;
return 1;
}
if (!SetHandleInformation(readFromProcess, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
siA.cb = sizeof(STARTUPINFOA);
siA.hStdInput = readFromProcess;
siA.hStdOutput = writeToProcess;
siA.hStdError = writeToProcess;
siA.dwFlags = STARTF_USESTDHANDLES;
if (CreateProcessA(NULL, lpCmdLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siA, &piApp) == 0) {
cout << "CreateProcessA error :: " << GetLastError() << endl;
return 1;
}
else {
CloseHandle(readFromProcess);
CloseHandle(writeToProcess);
}
DWORD dRead = 0;
char chBuff[deffBuffSize];
bool bSuccess = FALSE;
memset(chBuff, '\0', deffBuffSize);
string outStd;
bSuccess = ReadFile(readFromCL, chBuff, deffBuffSize, &dRead, NULL);
cout << "bSuccess: " << bSuccess << endl;
cout << "GetLastError: " << GetLastError() << endl;
cout << "Message: " << chBuff;
//CloseHandle(writeToCL);
//CloseHandle(readFromCL);
CloseHandle(piApp.hProcess);
CloseHandle(piApp.hThread);
return 0;
}
int main() {
int result = 0;
result = funSC();
system("pause");
return result;
}
When I execute ReadFile (), I get the result.
ERROR_BROKEN_PIPE (109) - The pipe has been ended.
As I understand it, the pipe is closed at the end of the recording => Question: "Why should CreateProcess() execute "ipconfig" and not output it to an overridden output stream."
I read MSDN, tried to use the ready-made code (for understanding), but this did not lead to a positive result.
Help me please, I will be very happy if I understand how to solve this problem =)
PS: I cannot "close" the console window, because I must have a valid directory (For example: cd anyFolder) If I close the process, I will lose the directory to which the user passed.
This is how I tried to read from the pipe
for (;;) {
bSuccess = ReadFile(readFromCL, chBuff, deffBuffSize, &dRead, NULL);
if (!bSuccess || dRead == 0) {
break;
}
else {
cout << "Message: " << chBuff;
}
}
This endless loop didn't read anything.
P.S : This is the output of a running program, but it only outputs one line of the "ipconfig" command
First, the error of ERROR_BROKEN_PIPE(109) caused by the cmd.exe exit unexpectedly. According to the sample Creating a Child Process with Redirected Input and Output:
The parent process uses the opposite ends of these two pipes to write
to the child process's input and read from the child process's output.
As specified in the STARTUPINFO structure, these handles are also
inheritable. However, these handles must not be inherited. Therefore,
before creating the child process, the parent process uses the
SetHandleInformation function to ensure that the write handle for
the child process's standard input and the read handle for the child
process's standard output cannot be inherited.
You have set the other two handles to be un-inherited, so that cmd.exe exits without an available standard handle.
Set the pipe side of child process instead:
if (!SetHandleInformation(readFromCL, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
if (!SetHandleInformation(writeToCL, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
The issue of content size may because you need to wait for the output from cmd.exe. Add function like: Sleep(1000) before ReadFile Simply could solve it. Then, you could choose the most suitable method to synchronize the input and output of the two processes. Such as read in a for loop:
for (;;) {
memset(chBuff, '\0', deffBuffSize);
bSuccess = ReadFile(readFromCL, chBuff, deffBuffSize, &dRead, NULL);
if (!bSuccess || dRead == 0) {
break;
}
else {
cout << chBuff;
}
}
Trying to retrieve the running directory of a process using the PID. I am obtaining the PID using FindWindow() and GetWindowThreadProcessId() which results in the same process ID as shown in task manager, so I assume it to be correct.
When using GetModuleFileNameEx(), instead of resulting in a path, I get what seems to be a memory address.
auto wnd = FindWindow(nullptr, L"prog");
while (wnd == nullptr)
{
wnd = FindWindow(nullptr, L"prog");
}
TCHAR fBuf[MAX_PATH]; // buffer for path
DWORD procId; // process id
GetWindowThreadProcessId(wnd, &procId); // get process id
std::cout << procId << std::endl; // results in correct pid
auto procHdl = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, procId); // create handle for process
if (procHdl != NULL) {
if (GetModuleFileNameEx(procHdl, 0, fBuf, MAX_PATH) == 0) {
std::cerr << "Failed to get module filename." << std::endl;
}
else {
std::cout << "Module filename is: " << fBuf << std::endl;
}
CloseHandle(procHdl);
}
Sample output is:
10488
Module filename is: 008CF93C
I have had the same result using GetProcessImageFileNname() too.
To get the directory of a program, first use GetModuleFileNameEx to get the program path, and your directory will start from the first character to the last backslash found.
Example:
Program is: "C:\Windows\notepad.exe";
Directory is: "C:\Windows";
In code:
DWORD pid = 104;
CHAR ProgramFile[MAX_PATH];
std::string DirectoryPath;
HANDLE hProcess = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, FALSE, pid);
GetModuleFileNameExA(hProcess, NULL, ProgramFile, MAX_PATH);
DirectoryPath = ProgramFile;
DirectoryPath = DirectoryPath.substr(0, DirectoryPath.find_last_of('\\'));
std::cout << "ProgramFile: " << ProgramFile << endl;
std::cout << "Directory: " << DirectoryPath.c_str();
When I try to check if some process is using data execution protection (DEP) I get error 87 (INVALID_PARAMETER). I checked my code and it seems to be okay but unfortunately I still have the same error.
Code:
BOOL var = true;
DWORD dwPolicy;
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, false, 3624);
if (hProc == NULL) {
cout << "Can't open Process because of the error " << GetLastError() << endl;
}
if (GetProcessDEPPolicy(hProc, &dwPolicy, 0) != FALSE) {
if (dwPolicy == PROCESS_DEP_ENABLE) {
cout << "For try.exe process data execution prevention is enabled" << endl;
}
else if (dwPolicy == NULL) {
cout << "For try.exe process data execution prevention is disabled" << endl;
}
else {
cout << "Data is thrunked and we can't change DEP value in future" << endl;
}
}
else {
cout << "There was an error with discovering DEP in try.exe process because of "<<GetLastError() << endl;
}
After compiling and execution I get:
There was an error with discovering DEP in try.exe process because of 87
Looking at the documentation, the function GetProcessDEPPolicy is defined:
BOOL WINAPI GetProcessDEPPolicy(
_In_ HANDLE hProcess,
_Out_ LPDWORD lpFlags,
_Out_ PBOOL lpPermanent
);
Notice that the last argument is an out parameter and it's not optional, but you're passing 0 aka NULL. The call should be:
BOOL permanent = FALSE;
if (GetProcessDEPPolicy(hProc, &dwPolicy, &permanent) != FALSE) {
for (int i = 0; i < n; i++)
{
const char* cstr = strings[i].c_str();
swprintf_s(fullCommandLine, L"\"%s\" \"%s\" %S", pathToModule, pathToFile, cstr);
if(CreateProcess(NULL,
(LPWSTR)fullCommandLine,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi))
{
cout << "succes";
}
else cout << "fail";
}
I'm creating n procesess to find string in given file like this, and In my module(wchich looks for given string in file) I want to send messages to other n-1 processes to quit
while (file >> readout)
{
if (readout == search)
{
cout << "I found string";
SendMessage(/*what should be here*/);
}
}
From where I could get handles to those other processes?
Please see my PostThreadMessage to Console Application.
I created that because it certainly is possible to send a message to a console program, we just must make a message loop, just as it is possible to show a window from a console program.
Note that PostThreadMessage needs a thread id, not a process id. Every process also has a thread id and a process's thread id is in the PROCESS_INFORMATION from CreateProcess.
The following is a larger example but easier to use for demonstrating that PostThreadMessage works in console programs. This program will call itself (passing its thread id) if there is no argument for it then it will wait for the new process to send messages. If there is an argument then it will assume the argument is a thread id and send a message to that thread followed by a WM_QUIT.
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szCmdline[300];
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = NULL;
siStartInfo.hStdOutput = NULL;
siStartInfo.hStdInput = NULL;
DWORD dwThread;
MSG Msg;
TCHAR ThreadIdBuffer[40];
// if no argument then execute ourself then wait for a message from that thread
if (argc == 1) {
_itot_s(GetCurrentThreadId(), ThreadIdBuffer, 40, 10);
szCmdline[0] = '"';
szCmdline[1] = 0;
_tcscat_s(szCmdline, 300, argv[0]); // ourself
int n = _tcslen(szCmdline);
szCmdline[n++] = '"';
szCmdline[n++] = ' ';
szCmdline[n++] = 0;
_tcscat_s(szCmdline, 300, ThreadIdBuffer); // our thread id
bSuccess = CreateProcess(argv[0], // execute ourself
szCmdline, // 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 (!bSuccess) {
std::cout << "Process not started\n";
return 0;
}
std::cout << "Waiting\n";
// Now wait for the other process to send us a message
while (GetMessage(&Msg, NULL, 0, WM_USER)) {
if (Msg.message == WM_COMMAND)
std::cout << "WM_COMMAND\n";
else
std::cout << "Message: " << Msg.message << '\n';
}
std::cout << "End of message loop\n";
return 0;
}
// if there is an argument then assume it is a threadid of another one of us
std::cout << "Press Enter to send the message\n";
if (std::wcin.get() != '\n')
return 0;
dwThread = _wtoi(argv[1]);
if (!PostThreadMessage(dwThread, WM_COMMAND, (WPARAM)0, (LPARAM)0))
std::cout << GetLastError() << " PostThreadMessage error\n";
if (!PostThreadMessage(dwThread, WM_QUIT, (WPARAM)0, (LPARAM)0))
std::cout << GetLastError() << " PostThreadMessage error\n";
return 0;
}
I'm trying to read from the memory of the MineSweeper to learn that kind of stuff, but I have a little problem.
When I try to print the modules it says to me I have no rights to do that. I know that's because the memory of that process is protected from write-read, and to read from it, I need to have debug rights.
And right there, my problem is when I call the OpenThreadToken(..), it fails with code 1008, and that's ERROR_NO_TOKEN.
Here you are the code, and sorry for the long intro:
int privileges(){
HANDLE token;
TOKEN_PRIVILEGES tp;
DWORD siz = sizeof(TOKEN_PRIVILEGES);
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE, &token) != 0){ //HERE IT FAILS
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(token, 0, &tp, siz, NULL ,NULL) != 0){
cout << "--Conseguido acceso debug.\n";
return TRUE;
}
else {
cout << "fail adjust\n";
return FALSE;
}
}
else {
cout << "fail if: " << GetLastError() << endl;
cin.get();
return FALSE;
}
I don't know why it fails. I've tried with the Microsoft example too, but same problem.
Does anybody know why it fails?
Threads only have their own tokens if you are using the impersonation APIs, otherwise there is only a process token. Simply fall back to OpenProcessToken if OpenThreadToken fails with ERROR_NO_TOKEN.