AssignProcessToJobObject Failing The Handle is Invalid - c++

Im creating a job with CreateJobObjectA(), then creating a new process with CreateProcessA(), and when I try to assign the new process to the job I have created with AssignProcessToJobObject() it returns 0. So I GetLastError() and im getting a value of 6. Which according to Windows systems error code means The Handle is invalid. Heres my code.
HANDLE job = CreateJobObjectA( NULL, "jobName" );
if( job == NULL )
{
printf( "Job is NULL" );
}
else
{
JOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if( 0 == SetInformationJobObject( job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
printf("Could not SetInformationJobObject\n");
}
}
if( CreateProcessA( "C:\\Windows\\SysWOW64\\cmd.exe", "/c server.bat", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
printf("CreateProcess succeeded.\n");
if( job != NULL )
{
HANDLE derp = processInfo.hProcess;
if( derp != NULL )
{
if( 0 == AssignProcessToJobObject( job, derp ))
{
printf("Could not AssignProcessToObject\n");
DWORD err = GetLastError();
printf("derp");
}
}
}
//Can we free handles now? Not sure about this.
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
The bat file is doing what it is supposed to be doing and launching a jar that runs a server. I just dont get how my Handle is invalid. Any help would be amazing. Or possibly a different way to do this?
I want to launch this new process and have it be a child process so when my main process crashes the server closes also.
Thank you.

You've got a race condition. If cmd.exe exits before you call AssignProcessToJobObject it won't work (I'm not sure what error code you get in that scenario).
Start the process suspended using the CREATE_SUSPENDED flag and don't resume it until you've already assigned it to the job.

Related

Call to WaitForSingleObject not clear in combination with CreateProcess

I came across the following code in a program that keeps track of processes:
void StartProcess(const std::wstring& processName, const CString& argument)
{
...
STARTUPINFO stInfo;
PROCESS_INFORMATION prInfo;
ZeroMemory( &stInfo, sizeof(stInfo) );
stInfo.cb = sizeof(stInfo);
stInfo.dwFlags=STARTF_USESHOWWINDOW;
stInfo.wShowWindow=SW_SHOWDEFAULT;
bRet = CreateProcess(NULL,
(LPTSTR)(LPCTSTR)sCmdline,
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
NULL,
_T("."),
&stInfo,
&prInfo);
// Create process has gone OK and we have to wait.
if (bRet)
{
bRet = FALSE;
int nRetWait = WaitForSingleObject(prInfo.hProcess,0);
if (nRetWait == WAIT_OBJECT_0)
{
// Get the exit code of the process
DWORD dwExitCode = 0;
::GetExitCodeProcess(prInfo.hProcess, &dwExitCode);
if (0 == dwExitCode)
{
// The program succeeded
m_StartedServices.push_back(prInfo.dwProcessId;);
bRet = TRUE;
}
}
}
}
The code should start a process and then in a later stadium terminate it (using m_StartedServices). However I am wondering what added value the calls to WaitForSingleObject and GetExitCodeProcess have. I have looked around a bit and it seems that the WaitForSingleObject with a timeout of 0 is used to check if a process is still running, but it is just created, so why check? And why check the exit code of a process that is still running?
Can anybody clear this up?
Also I found that calls:
CloseHandle(prInfo.hThread);
CloseHandle(prInfo.hProcess);
are missing in this function. Have I found a handle leak, or is there some magic that would automatically close the handles?

Running Process in system context

Is it possible to launch process in system context from a parent process thats running under administrator account with elevation(say a command prompt). The problem is similar to what psexec does but more of how it actually implements this.
I was thinking opening the crss.exe/winlogon.exe process duplicating the token and launching a new process using that process token. But I fail to even open the process handle (Getlasterror return 5). Can someone let me know if this is the right approach or the process should be launched differently ?
HANDLE hWinLogonProcess;
for(const auto& ps : running_processes)
{
if(ps.id == GetCurrentProcessId() ||
0 != ps.short_name.CompareNoCase(L"winlogon.exe"))
{
continue;
}
DWORD dwWinLogonSessionId(0);
if(FALSE == ProcessIdToSessionId(GetCurrentProcessId(), &dwWinLogonSessionId))
{
std::wcerr<<"Could not get Winlogon process session id"<<std::endl;
continue;
}
if(dwWinLogonSessionId != dwCurSessionId)
{
continue;
}
hWinLogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ps.id);
if(FALSE == hWinLogonProcess)
{
std::wcerr<<"Failed to get winlogon process handle"<<std::endl;
return;
}
else
{
std::wcout<<"Able to open process "<<ps.short_name.GetString()<<" handle"<<std::endl;
break;
}
}
I am sure its possible as there is a working tool (psexec) but I couldnt find any reference online to do this.
Also this is similar to question, but posting separately as there was details on how it had to be achieved.
Yes, this is possible (without any service help).
But I fail to even open the process handle
Does your process have the SE_DEBUG_PRIVILEGE privilege enabled?
With this privilege, you can open a system process with all access if it is not protected (smss.exe, csrss.exe, services.exe), and use that handle in CreateProcessAsUser(), or with UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS) if you also have SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_TCB_PRIVILEGE privileges enabled (for setting the token's SessionId to 0), which you can get in 2 ways:
open a thread from an unprotected system process and impersonate it, then open your own thread token and adjust privileges on it.
open a token from any system process (this works even for protected processes), duplicate the token, adjust privileges on it, and then impersonate with this token.
To "launch a process in the system context", if you want to run the process:
with the LocalSystem token.
in the System terminal session (0)
Both, as I say, are possible. And all you need is SE_DEBUG_PRIVILEGE.
more simply - open some system process with PROCESS_CREATE_PROCESS access right. Use this handle with UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS). As a result, your started process inherits a token from the system process. This will be not work on XP, but there it is possible to hook NtCreateProcess/Ex() to replace HANDLE ParentProcess with your opened handle.
Another way is to use CreateProcessAsUser(). Before creating the process, you will be need SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_TCB_PRIVILEGE privileges to set the token's TokenSessionId (if you want to run in session 0).
Thanks to RbMm answer I figured a way to accomplish this task.
For any of you who did not succeed, I leave below something that might help:
//First we need to add debug privilege to this process
HANDLE hToken;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
std::cout << "OpenProcessToken failed: " << GetLastError();
return 0;
}
TOKEN_PRIVILEGES tk;
tk.PrivilegeCount = 1;
tk.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tk.Privileges[0].Luid))
{
std::cout << "LookupPrivilegeValue failed: " << GetLastError();
return 0;
}
AdjustTokenPrivileges(hToken, FALSE, &tk, 0, NULL, 0);
if((DWORD res = GetLastError()) != ERROR_SUCCESS)
{
std::cout << "AdjustTokenPrivileges failed: " << res;
}
CloseHandle(hToken);
//Now we need a handle to a process that already runs as SYSTEM.
//You can choose any process that is not protected (if OpenProcess fails try with other process)
//pid of chosen process (you can get this by opening task manager and go to
//Details tab or by enumerating all processes and extract that one you need)
DWORD pid;
HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
if (!hProcess)
{
std::cout << "OpenProcess with pid " << pid << "failed: " << GetLastError();
return 0
}
//We need to initialize a list that contains PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
//to specify that parent process of the process we are going to start is the
//process we opened earlier (this will make the child process inherit the system context).
//This list will be specified in a STARTUPINFOEX object that CreateProcess will get
STARTUPINFOEX siex = { sizeof(STARTUPINFOEX) };
siex.StartupInfo.cb = sizeof(STARTUPINFOEXW);
//We need to initialize our list. To do this we call InitializeProcThreadAttributeList
//with a NULL list to get how big our list needs to be to store all attributes
//we want to specify, then we allocate our list with the size we got from first call
//and we call again the function to initialize the list.
SIZE_T cbAttributeListSize = 0;
if(!InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
siex.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize));
if(!InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
if(!UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), NULL, NULL))
{
std::cout << "UpdateProcThreadAttribute failed: " << GetLastError();
return 0
}
//path to program we want to run in system context
LPWSTR szCmdline = _wcsdup(TEXT("C:\\Windows\\System32\\notepad.exe"));
PROCESS_INFORMATION pi = { 0 };
if(!CreateProcess(NULL, szCmdline, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOW>(&siex), &pi))
{
std::cout << "CreateProcess failed: " << GetLastError();
return 0
}

Windows prevent multiple instances code not working

I am using CreateEvent to prevent multiple instances of my application:
CreateEvent(NULL, TRUE, FALSE, "MyEvent");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
However, at startup I have noticed that this doesn't work:
After the desktop is shown I automatically run a batch script that attempts to launch multiple instances of my program. The batch script succeeds and I can indeed see multiple instances.
Investigation so far:
OutputDebug shows that each instance does not get ERROR_ALREADY_EXISTS
ProcessExplorer.exe shows that each instance was able to get a handle to the event "MyEvent".
Can anybody think why this might be happening, and how I could solve it?
We use the function below, which is in our common utility DLL. The method is derived from a Microsoft article explaining how to prevent multiple instances in WIN32.
#define STRICT
#include <stdheaders.h>
HANDLE ghSem;
BOOL IExist( LPSTR lpszWindowClass )
{
HWND hWndMe;
int attempt;
for( attempt=0; attempt<2; attempt++ )
{
// Create or open a named semaphore.
ghSem = CreateSemaphore( NULL, 0, 1, lpszWindowClass );
// Close handle and return NULL if existing semaphore was opened.
if( (ghSem != NULL) &&
(GetLastError() == ERROR_ALREADY_EXISTS) )
{ // Someone has this semaphore open...
CloseHandle( ghSem );
ghSem = NULL;
hWndMe = FindWindow( lpszWindowClass, NULL );
if( hWndMe && IsWindow(hWndMe) )
{ // I found the guy, try to wake him up
if( SetForegroundWindow( hWndMe ) )
{ // Windows says we woke the other guy up
return TRUE;
}
}
Sleep(100); // Maybe the semaphore will go away like the window did...
}
else
{ // If new semaphore was created, return FALSE.
return FALSE;
}
}
// We never got the semaphore, so we must
// behave as if a previous instance exists
return TRUE;
}
Just do something like this in your WinMain:
if( IExist("MyWindowClass") )
{
return 1;
}
Of course, you could replace the return with whatever you need to do when you are not the first instance (such as activating the existing instance).

C++: Deleting a printer queue

I'm trying to remove all the files in queue from a printer. I found this piece of code which seemed pretty straight forward.
I tried deleting the queue with the code below. It compiles, but SetPrinter returns false. The error message I got was 5, which I tried to decode to a "normal" error message using the approach from this question. But I wasn't able to compile with that, because STR_ELEMS is undefined. Searched google for "STR_ELEMS is undefined" but hit a dead end.
Can someone help me decode the error message and delete the printer queue?
BOOL bStatus = false;
HANDLE hPrinter = NULL;
DOC_INFO_1 DocInfo;
bStatus = OpenPrinter((LPTSTR)_T("CN551A"), &hPrinter, NULL);
if(bStatus) {
DWORD dwBufsize=0;
GetPrinterA(hPrinter, 2, NULL, 0, &dwBufsize); // Edit: Returns false
PRINTER_INFO_2* pinfo = (PRINTER_INFO_2*)malloc(dwBufsize);
long result = GetPrinterA(hPrinter, 2,
(LPBYTE)pinfo, dwBufsize, &dwBufsize);
if ( pinfo->cJobs==0 ) // Edit: pinfo->cJobs is not 0
{
printf("No printer jobs found.");
}
else
{
if ( SetPrinter(hPrinter, 0, 0, PRINTER_CONTROL_PURGE)==0 )
printf("SetPrinter call failed: %x\n", GetLastError() );
else printf("Number of printer jobs deleted: %u\n",
pinfo->cJobs);
}
ClosePrinter( hPrinter );
}
My includes are:
#include <windows.h>
#include <winspool.h>
The error code of 5 means "access is denied". (System Error Codes)
Try running with admin privileges.
To format a printable error message from the return value of GetLastError, use FormatMessage something like this:
TCHAR buffer[256];
if (0 == FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
GetLastError(), 0, buffer, 256, 0)) {
// FormatMessage failed.
}
Also, you can try passing a PRINTER_DEFAULTS struct to OpenPrinter, maybe like this:
PRINTER_DEFAULTS PrnDefs;
PrnDefs.pDataType = "RAW";
PrnDefs.pDevMode = 0;
PrnDefs.DesiredAccess = PRINTER_ALL_ACCESS;
bStatus = OpenPrinter((LPTSTR)_T("CN551A"), &hPrinter, &PrnDefs);

Can not kill process completely when application crashed?

I will describe my problem as below
I have two applications mainApp and supervisorApp.
The supervisorApp will run along with mainApp to supervise mainApp.
supervisorApp will check status of mainApp each 30s by sending KEEP_ALIVE message to mainApp.
And supervisorApp will restart mainApp if mainApp is not responding that KEEP_ALIVE message.
And more one rule, mainApp will not allow more than two processes "mainApp.exe" run together,
that mean when started, mainApp will close immediately if there is other process "mainApp.exe"is running.
And then I will posted some main code and show my problem.
//Code for supervisorApp - Begin
void Main()
{
while (true)
{
Sleep(30000);
if(SendKeepAliveMessage() == false) //MainApp is not responding -> Restart mainApp
{
TerminateMainApp();
Sleep(2000);
StartMainApp();
}
}
}
void TerminateMainApp()
{
TerminateProcess(MainAppProcessInfo.hProcess, 0);
CloseHandle( MainAppProcessInfo.hProcess );
CloseHandle( MainAppProcessInfo.hThread );
}
bool StartMainApp()
{
ZeroMemory( &MainAppStartUpInfo, sizeof(MainAppStartUpInfo) );
MainAppStartUpInfo.cb = sizeof(MainAppStartUpInfo);
ZeroMemory( &MainAppProcessInfo, sizeof(MainAppProcessInfo) );
char commandLine[STR_LENGTH_256];
sprintf(commandLine, "mainApp.exe");
LPSTR cmd = _T(commandLine);
//Start the child process
if( !CreateProcess
(NULL, // No module name (use command line)
cmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&MainAppStartUpInfo, // Pointer to STARTUPINFO structure
&MainAppProcessInfo // Pointer to PROCESS_INFORMATION structure
)
)
{
return false;
}
return true;
}
//Code for supervisorApp - End
//Code for mainApp - Begin
void Main()
{
if (IsThisProcessHasRun())
{
MessageBox.Show("The mainApp is running!");
return;
}
//Do something
}
bool IsThisProcessHasRun()
{
HANDLE SnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( SnapShot == INVALID_HANDLE_VALUE )
return false;
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof( PROCESSENTRY32 );
if( !Process32First( SnapShot, &procEntry ) )
{
CloseHandle(SnapShot);
return false;
}
int countProcess = 0;
do
{
if( strcmp( procEntry.szExeFile, "mainApp.exe" ) == 0 )
{
countProcess++;
if(countProcess == 2)
{
CloseHandle(SnapShot);
return true;
}
}
}
while( Process32Next( SnapShot, &procEntry ) );
CloseHandle(SnapShot);
return false;
}
//Code for mainApp - End
Everything is ok on windows 7, but on windows 8 I have encountered the following problem.
When mainApp.exe is crashed (Window will show the dialog with the message "the mainApp has stopped working" -> do not close it),
the supervisorMainApp send KEEP_ALIVE message and mainApp does not respond this message,
Then supervisorMainApp will call TerminateMainApp() and StartMainApp() to restart mainApp.
But when mainApp start, it will show the dialog "The mainApp is running!"...
I debug and see that, function TerminateMainApp() and StartMainApp() work fine.
When TerminateMainApp() called, in Task Manager's proceess list will remove "mainApp.exe" => it's ok
But when mainApp start, the function IsThisProcessHasRun() return true with countProcess=2, so it can not start.
And then I close Dialog's Crashed message of mainApp, IsThisProcessHasRun() false with countProcess=1, so it can start successfully!
I don't understand why? And I think if I can Dialog's Crashed message of mainApp automatically, then my problem can solve.
But maybe it is not good solution!
Someone can show me how to kill the process mainApp.exe completely?
Many thanks!
T&T