CreateProcessAsUser() not working - c++

I am trying to start GUI application using my service. I developed the service on VS2012 and running on windows 7. But CreateProcessAsUser function doesn't start application even though it returns successfully. following is my code:
PHANDLE hToken = NULL;
WTSQueryUserToken (WTSGetActiveConsoleSessionId (), hToken) ;
if( !CreateProcessAsUser( hToken,
NULL, // No module name (use command line)
pPath, // 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
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
what could be the issue?
Thanks,
KM.

After retrieving the user token from WTSQueryUserToken(), call DuplicateTokenEx() to convert it into a primary token, and pass that token to CreateProcessAsUser(). You also need to specify the "winsta0\default" (use: "winsta0\\default") desktop via the STARTUPINFO structure. You should also call CreateEnvironmentBlock() using the same token, and pass that environment to CreateProcessAsUser() as well.

There is not enough information to be sure of my answer but that kind of error often happen when the structures are not correctly initialized.
PHANDLE hToken = NULL;
WTSQueryUserToken (WTSGetActiveConsoleSessionId (), hToken) ;
//be sure that the handle is correct ! (can be the issue)
if (!hToken) printf("Token error.\n");
//init here !
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if( !CreateProcessAsUser( hToken,
NULL, // No module name (use command line)
pPath, // 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
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)

I faced a similar issue while using WTSQueryUserToken in windows 7, but the same function worked in windows 10.
So I took the explorer.exe token, called the DuplicateTokenEx function.
Set the corresponding values for startupinfo structure
si.lpDesktop = "winsta0\\default";
si.wShowWindow = SW_SHOWNORMAL;
si.dwFlags = STARTF_USESHOWWINDOW;
and called createprocessasuser

Related

How can I use CreateProcess method to refer to other 'ini' file to start 'exe' program?

I'm currently trying to execute 'ClientProc.exe'. This program uses 'SA_Client.ini' file from a same directory as a reference.
I'm using CreateProcess method to execute the .exe program as belows.
STARTUPINFO si;
PROCESS_INFORMATION pi;
// set the size of the structures
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
LPCSTR lpApplicationName = "C:\\projects\\Client\\ClientProc.exe";
LPSTR cmd = (char*)"./";
if (!CreateProcess(lpApplicationName, // the path
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
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
))
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
The problem is that I don't know how to make CreateProcess to refer to the 'ini' file even though the file exists in the same directory.
I've checked Microsoft document or other StackOverflow comments but couldn't find anything useful.
Does anyone know how to do it?
Thank you in advance!
--Edit--
I've also tried setting the lpCurrentDirectory parameter where ini file exists.
CreateProcess(lpApplicationName, // the path
NULL, // 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
"C:\\projects\\Client", // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
)
Then, I've got an error 267 which stands for 'ERROR_DIRECTORY'. I'm sure that the file exists in the directory. What am I doing wrong?

Create Process default browser

I'm currently using ShellExecute "open" to open a URL in the user's browser, but running into a bit of trouble in Win7 and Vista because the program runs elevated as a service.
I want to get thread id so ShellExecute is not possible to get thread id so i started using "CreateProcess" But i don't see any help on opening default browser whichever is it from CreateProcess.
You can use other features of the Shell API to figure out which browser is the default.
For instance, you can ask the shell for the executable name associated with .html files using AssocQueryString, and launch that via CreateProcess.
Here you can open the URL with your default browser.
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CStringA command_line;
command_line.Format("cmd.exe /c start \"link\" \"%s\"", "http://www.google.com");
if (!CreateProcessA(NULL, // No module name (use command line)
command_line.GetBuffer(),
NULL, // Process handle not inheritable
NULL, // Thread handle not inhberitable
FALSE, // Set handle inheritance to FALSE
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
TRACE("CreateProcess failed (%d).\n", GetLastError());
return;
}
Here is another answer as you wanted. As far as you want it open as a new window. You can expand it for IE, opera, and so on...
DWORD size = MAX_PATH;
char buff[MAX_PATH];
int err = AssocQueryStringA(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE, ".html", NULL, buff, &size);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CStringA command_line;
CStringA target_url( "http://google.com/" );
if( strcmp( "chrome.exe", PathFindFileNameA(buff)) == 0 )
command_line.Format("%s --new-window %s", buff, target_url);
else if( strcmp( "firefox.exe", PathFindFileNameA(buff)) == 0 )
command_line.Format("%s -new-instance %s", buff, target_url);
else
command_line.Format("%s %s", buff, target_url);
if (!CreateProcessA(NULL, // No module name (use command line)
command_line.GetBuffer(),
NULL, // Process handle not inheritable
NULL, // Thread handle not inhberitable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
//... error handling
return;
}

CreateProcessAsUser fails with ERROR_ELEVATION_REQUIRED for a process with UIAccess="true"

I'm trying to use the following code to run a user-mode process from my service application (running as a local system.)
The requirement for the user-mode process is to run without elevatation, but to have UIAccess="true" in its manifest to be able to display top-most windows correctly under Windows 8.
So I do this (from my service) to run my user-mode process:
//NOTE: Error checking is omitted for readability
//'dwSessionID' = user session ID to run user-mode process in
//'pUserProcPath' = L"C:\\Program Files (x86)\\Company\\Software\\user_process.exe"
HANDLE hToken = NULL;
WTSQueryUserToken(dwSessionID, &hToken);
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);
LPVOID pEnvBlock = NULL;
CreateEnvironmentBlock(&pEnvBlock, hToken2, FALSE);
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = L"winsta0\\default";
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
//ImpersonateLoggedOnUser(hToken2); //Not necessary as suggested below
PVOID OldRedir;
Wow64DisableWow64FsRedirection(&OldRedir);
BOOL bSuccess = CreateProcessAsUser(
hToken2, // client's access token
pUserProcPath, // file to execute
NULL, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, // creation flags
pEnvBlock, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
int nOSError = ::GetLastError();
Wow64RevertWow64FsRedirection(OldRedir);
//RevertToSelf(); //Not necessary as suggested below
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
DestroyEnvironmentBlock(pEnvBlock);
CloseHandle(hToken2);
CloseHandle(hToken);
This runs fine, if UIAccess="false" in the manifest for the user_process.exe.
But if I do the following:
Enable UIAccess="true" for the user_process.exe:
Sign it with my code-signing certificate and
Place it in the "C:\Program Files (x86)\Company\Software" folder.
What I get is that CreateProcessAsUser fails with the error ERROR_ELEVATION_REQUIRED.
Can someone suggest how to make it work?
PS. I tried adjusting my service's privileges to enable SE_DEBUG_NAME and SE_TCB_NAME, but neither helped.
PS2. If I simply double-click my user_process.exe process compiled with UIAccess="true", code-signed, and placed in the C:\Program Files (x86)\Company\Software folder, it starts & runs just fine (not elevated.).
I found the answer. Here it is for whoever runs into it as well:
Add this after DuplicateTokenEx call:
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);
//ONLY if requiring UIAccess!
DWORD dwUIAccess = 1;
::SetTokenInformation(hToken2, TokenUIAccess, &dwUIAccess, sizeof(dwUIAccess));

CreateProcess function issue

I'm trying to start an process from my code with createprocess function. The command line is ok, and the other exe, i can start it without problems from visual studio.
When I am trying to start it from the other process with createprocess it gives me - Runtime error this app has requested the runtime to terminate it in an unusual way.
What could be the problem ? How could I remove this problem ?
STARTUPINFO si;
PROCESS_INFORMATION pi;
bool bResult;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//Cast System::String* __gc to char*
char* chAppName = (char*)(void*)Marshal::StringToHGlobalAnsi(AppName);
char* chCmdLine = (char*)(void*)Marshal::StringToHGlobalAnsi(CmdLine);
//Start the child process.
bResult = CreateProcess( chAppName, // No module name (use command line)
chCmdLine, // 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
&si, // Pointer to STARTUPINFO structure
&pi); // Pointer to PROCESS_INFORMATION structure
Try eliminating the StringToHGlobalAnsi calls and hard coding them instead first. If that stops the problems, we can then sort out the StringToHGlobalAnsi calls.

Creating independent process!

I am trying to create a process from a service in C++. This new process is creating as a child process. I want to create an independent process and not a child process...
I am using CreateProcess function for the same. Since the new process i create is a child process when i try to kill process tree at the service level it is killing the child process too... I dont want this to happen. I want the new process created to run independent of the service.
Please advice on the same..
Thanks..
Code
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si); // Start the child process.
ZeroMemory( &pi, sizeof(pi) );
si.dwFlags = STARTF_USESHOWWINDOW;
if(bRunOnWinLogonDesktop)
{
if(csDesktopName.empty())
si.lpDesktop = _T("winsta0\\default");
else
_tcscpy(si.lpDesktop, csDesktopName.c_str());
}
if(bHide)
si.wShowWindow = SW_HIDE; /* maybe even SW_HIDE */
else
si.wShowWindow = SW_SHOW; /* maybe even SW_HIDE */
TCHAR szCmdLine[512];
_tcscpy(szCmdLine, csCmdLine.c_str());
if( !CreateProcess( NULL,
szCmdLine,
NULL,
NULL,
FALSE,
CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
&si,
&pi ) )
After closing thread and process handlers of the child process, it's still a child in the Process Explorer, but ending parent process doesn't cause termination of the child one.
CreateProcess( NULL,
szCmdLine,
NULL,
NULL,
FALSE,
CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
&si,
&pi );
if(pi.hThread)
CloseHandle(pi.hTread);
if(pi.hProcess)
CloseHandle(pi.hProcess);
I've found this decision in sources of cmd.exe of the ReactOS, in the procedure of executing 'start' command.
Create an intermediate process (use create_new_process_group), which then creates the real process.
Service
-> Intermediate Process
-> Real Process
The Intermediate process should exit as soon as it's launched the real process.