Exemple #1
0
bool ConsoleHandler::StartShellProcess
(
	const wstring& strCustomShell, 
	const wstring& strInitialDir, 
	const wstring& strUser,
	const wstring& strPassword,
	const wstring& strInitialCmd, 
	const wstring& strConsoleTitle, 
	DWORD dwStartupRows, 
	DWORD dwStartupColumns, 
	bool bDebugFlag
)
{
	wstring strUsername(strUser);
	wstring strDomain;

//	shared_ptr<void> userProfileKey;
//	shared_ptr<void> userEnvironment;
//	shared_ptr<void> userToken;

	if (strUsername.length() > 0)
	{
		size_t pos = strUsername.find(L'\\');
		if (pos != wstring::npos)
		{
			strDomain	= strUsername.substr(0, pos);
			strUsername	= strUsername.substr(pos+1);
		}
/*
		// logon user
		HANDLE hUserToken = NULL;
		::LogonUser(
			strUsername.c_str(), 
			strDomain.length() > 0 ? strDomain.c_str() : NULL, 
			strPassword.c_str(), 
			LOGON32_LOGON_INTERACTIVE, 
			LOGON32_PROVIDER_DEFAULT, 
			&hUserToken);

		userToken.reset(hUserToken, ::CloseHandle);
*/

/*
		::ImpersonateLoggedOnUser(userToken.get());

		wchar_t	szComspec[MAX_PATH];
		::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH);
*/


/*
		// load user's profile
		// seems to be necessary on WinXP for environment strings' expainsion to work properly
		PROFILEINFO userProfile;
		::ZeroMemory(&userProfile, sizeof(PROFILEINFO));
		userProfile.dwSize = sizeof(PROFILEINFO);
		userProfile.lpUserName = const_cast<wchar_t*>(strUser.c_str());
		
		::LoadUserProfile(userToken.get(), &userProfile);
		userProfileKey.reset(userProfile.hProfile, bind<BOOL>(::UnloadUserProfile, userToken.get(), _1));
*/
/*		// load user's environment
		void*	pEnvironment	= NULL;
		::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE);
		userEnvironment.reset(pEnvironment, ::DestroyEnvironmentBlock);
		::RevertToSelf();
*/
	}

	wstring	strShellCmdLine(strCustomShell);
	
	if (strShellCmdLine.length() == 0)
	{
		wchar_t	szComspec[MAX_PATH];

		::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t));

		if (strUsername.length() > 0)
		{
/*			// resolve comspec when running as another user
			wchar_t* pszComspec = reinterpret_cast<wchar_t*>(userEnvironment.get());

			while ((pszComspec[0] != L'\x00') && (_wcsnicmp(pszComspec, L"comspec", 7) != 0)) pszComspec += wcslen(pszComspec)+1;

			if (pszComspec[0] != L'\x00')
			{
				strShellCmdLine = (pszComspec + 8);
			}
*/
			if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe";
		}
		else
		{
			if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0)
			{
				strShellCmdLine = szComspec;		
			}

			if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe";
		}
	}

	if (strInitialCmd.length() > 0)
	{
		strShellCmdLine += L" ";
		strShellCmdLine += strInitialCmd;
	}

	wstring	strStartupTitle(strConsoleTitle);

	if (strStartupTitle.length() == 0)
	{
		strStartupTitle = L"Console2 command window";
//		strStartupTitle = str(wformat(L"Console2 command window 0x%08X") % this);
	}

//	wstring strStartupDir((strUsername.length() > 0) ? Helpers::ExpandEnvironmentStringsForUser(userToken, strInitialDir) : Helpers::ExpandEnvironmentStrings(strInitialDir));
	wstring strStartupDir((strUsername.length() > 0) ? strInitialDir : Helpers::ExpandEnvironmentStrings(strInitialDir));

	if (strStartupDir.length() > 0)
	{
		if ((*(strStartupDir.end() - 1) == L'\"') && (*strStartupDir.begin() != L'\"'))
		{
			// startup dir name ends with ", but doesn't start with ", the user passed
			// something like "C:\" as the parameter, it got parsed to C:", remove the trailing "
			//
			// This is a common mistake, thus the check...
			strStartupDir = strStartupDir.substr(0, strStartupDir.length()-1);
		}

		// startup dir doesn't end with \, add it
		if (*(strStartupDir.end() - 1) != L'\\') strStartupDir += L'\\';

		// check if startup directory exists
		DWORD dwDirAttributes = ::GetFileAttributes(strStartupDir.c_str());

		if ((dwDirAttributes == INVALID_FILE_ATTRIBUTES) ||
			(dwDirAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
		{
			// no directory, use Console.exe directory
			strStartupDir = Helpers::GetModulePath(NULL);
		}
	}

	// setup the startup info struct
	STARTUPINFO si;
	::ZeroMemory(&si, sizeof(STARTUPINFO));

	si.cb			= sizeof(STARTUPINFO);
	si.lpTitle		= const_cast<wchar_t*>(strStartupTitle.c_str());

	if (g_settingsHandler->GetConsoleSettings().bStartHidden)
	{
		// Starting Windows console window hidden causes problems with 
		// some GUI apps started from Console that use SW_SHOWDEFAULT to 
		// initially show their main window (i.e. the window inherits our 
		// SW_HIDE flag and remains invisible :-)
		si.dwFlags		= STARTF_USESHOWWINDOW;
		si.wShowWindow	= SW_HIDE;
	}
	else
	{
		// To avoid invisible GUI windows, default settings will create
		// a Windows console window far offscreen and hide the window
		// after it has been created.
		//
		// This approach can flash console window's taskbar button and
		// taskbar button can sometimes remain visible, but nothing is perfect :)
		si.dwFlags		= STARTF_USEPOSITION;
		si.dwX			= 0x7FFF;
		si.dwY			= 0x7FFF;
	}
	
	PROCESS_INFORMATION pi;
	// we must use CREATE_UNICODE_ENVIRONMENT here, since s_environmentBlock contains Unicode strings
	DWORD dwStartupFlags = CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT;

	// TODO: not supported yet
	//if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS;

	
	if (strUsername.length() > 0)
	{
		if (!::CreateProcessWithLogonW(
			strUsername.c_str(), 
			strDomain.length() > 0 ? strDomain.c_str() : NULL, 
			strPassword.c_str(), 
			LOGON_WITH_PROFILE,
			NULL,
//			const_cast<wchar_t*>(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()),
			const_cast<wchar_t*>(strShellCmdLine.c_str()),
			dwStartupFlags,
//			userEnvironment.get(),
			NULL,
			(strStartupDir.length() > 0) ? const_cast<wchar_t*>(strStartupDir.c_str()) : NULL,
			&si,
			&pi))
		{
			throw ConsoleException(str(wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % strShellCmdLine % strUser));
		}
	}
	else
	{
		if (!::CreateProcess(
				NULL,
				const_cast<wchar_t*>(Helpers::ExpandEnvironmentStrings(strShellCmdLine).c_str()),
				NULL,
				NULL,
				FALSE,
				dwStartupFlags,
				s_environmentBlock.get(),
				(strStartupDir.length() > 0) ? const_cast<wchar_t*>(strStartupDir.c_str()) : NULL,
				&si,
				&pi))
		{
			throw ConsoleException(str(wformat(Helpers::LoadString(IDS_ERR_CANT_START_SHELL)) % strShellCmdLine));
		}
	}

	// create shared memory objects
	CreateSharedObjects(pi.dwProcessId, strUser);
	CreateWatchdog();

	// write startup params
	m_consoleParams->dwConsoleMainThreadId	= pi.dwThreadId;
	m_consoleParams->dwParentProcessId		= ::GetCurrentProcessId();
	m_consoleParams->dwNotificationTimeout	= g_settingsHandler->GetConsoleSettings().dwChangeRefreshInterval;
	m_consoleParams->dwRefreshInterval		= g_settingsHandler->GetConsoleSettings().dwRefreshInterval;
	m_consoleParams->dwRows					= dwStartupRows;
	m_consoleParams->dwColumns				= dwStartupColumns;
	m_consoleParams->dwBufferRows			= g_settingsHandler->GetConsoleSettings().dwBufferRows;
	m_consoleParams->dwBufferColumns		= g_settingsHandler->GetConsoleSettings().dwBufferColumns;

	m_hConsoleProcess = shared_ptr<void>(pi.hProcess, ::CloseHandle);

	// inject our hook DLL into console process
	if (!InjectHookDLL(pi)) return false;

	// resume the console process
	::ResumeThread(pi.hThread);
	::CloseHandle(pi.hThread);

	// wait for hook DLL to set console handle
	if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT) return false;

	::ShowWindow(m_consoleParams->hwndConsoleWindow, SW_HIDE);

	return true;
}
Exemple #2
0
bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstring& strInitialDir, const wstring& strInitialCmd, const wstring& strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns, bool bDebugFlag)
{
	wstring	strShellCmdLine(strCustomShell);
	
	if (strShellCmdLine.length() == 0)
	{
		wchar_t	szComspec[MAX_PATH];

		::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t));

		if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0)
		{
			strShellCmdLine = szComspec;		
		}
		else
		{
			strShellCmdLine = L"cmd.exe";
		}
	}

	if (strInitialCmd.length() > 0)
	{
		strShellCmdLine += L" ";
		strShellCmdLine += strInitialCmd;
	}

	wstring	strStartupTitle(strConsoleTitle);

	if (strStartupTitle.length() == 0)
	{
		strStartupTitle = L"Console2 command window";
//		strStartupTitle = str(wformat(L"Console2 command window 0x%08X") % this);
	}

	wstring strStartupDir(strInitialDir);

	if (strStartupDir.length())
	{
		// check if startup directory exists
		DWORD dwDirAttributes = ::GetFileAttributes(strStartupDir.c_str());

		if ((dwDirAttributes == INVALID_FILE_ATTRIBUTES) ||
			(dwDirAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
		{
			// no directory, use Console.exe directory
			strStartupDir = Helpers::GetModulePath(NULL);
		}
	}

	// setup the startup info struct
	STARTUPINFO si;
	::ZeroMemory(&si, sizeof(STARTUPINFO));
	si.dwFlags		= STARTF_USESHOWWINDOW;
	si.cb			= sizeof(STARTUPINFO);
	si.wShowWindow	= SW_HIDE;
	si.lpTitle		= const_cast<wchar_t*>(strStartupTitle.c_str());

	PROCESS_INFORMATION pi;
	DWORD				dwStartupFlags = CREATE_NEW_CONSOLE|CREATE_SUSPENDED;

	// TODO: not supported yet
	//if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS;

	if (!::CreateProcess(
			NULL,
			const_cast<wchar_t*>(Helpers::ExpandEnvironmentStrings(strShellCmdLine).c_str()),
			NULL,
			NULL,
			FALSE,
			dwStartupFlags,
			NULL,
			(strStartupDir.length() > 0) ? const_cast<wchar_t*>(Helpers::ExpandEnvironmentStrings(strStartupDir).c_str()) : NULL,
			&si,
			&pi))
	{
		return false;
	}

	// create shared memory objects
	CreateSharedObjects(pi.dwProcessId);

	// write startup params
	m_consoleParams->dwConsoleMainThreadId	= pi.dwThreadId;
	m_consoleParams->dwParentProcessId		= ::GetCurrentProcessId();
	m_consoleParams->dwNotificationTimeout	= g_settingsHandler->GetConsoleSettings().dwChangeRefreshInterval;
	m_consoleParams->dwRefreshInterval		= g_settingsHandler->GetConsoleSettings().dwRefreshInterval;
	m_consoleParams->dwRows					= dwStartupRows;
	m_consoleParams->dwColumns				= dwStartupColumns;
	m_consoleParams->dwBufferRows			= g_settingsHandler->GetConsoleSettings().dwBufferRows;
	m_consoleParams->dwBufferColumns		= g_settingsHandler->GetConsoleSettings().dwBufferColumns;

	m_hConsoleProcess = shared_ptr<void>(pi.hProcess, ::CloseHandle);

	// inject our hook DLL into console process
	if (!InjectHookDLL()) return false;

	// resume the console process
	::ResumeThread(pi.hThread);
	::CloseHandle(pi.hThread);

	// wait for hook DLL to set console handle
	if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT) return false;

	return true;
}
Exemple #3
0
void ConsoleHandler::StartShellProcess
(
	const wstring& strTitle,
	const wstring& strShell,
	const wstring& strInitialDir,
	const UserCredentials& userCredentials,
	const wstring& strInitialCmd,
	const wstring& strConsoleTitle,
	DWORD dwStartupRows,
	DWORD dwStartupColumns
)
{
	PROCESS_INFORMATION pi = {0, 0, 0, 0};

	bool runAsAdministrator = userCredentials.runAsAdministrator;

	if (runAsAdministrator)
	{
		try
		{
			if (Helpers::CheckOSVersion(6, 0))
			{
				if( Helpers::IsElevated() )
				{
					// process already running in elevated mode or UAC disabled
					runAsAdministrator = false;
				}
			}
			else
			{
				// UAC doesn't exist in current OS
				runAsAdministrator = false;
			}
		}
		catch(std::exception& err)
		{
			throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_CANT_GET_ELEVATION_TYPE)) % err.what()));
		}
	}

	SharedMemory<DWORD> pid;

	if (runAsAdministrator)
	{
		std::wstring strSyncName = (SharedMemNames::formatAdmin % ::GetCurrentProcessId()).str();

		pid.Create(strSyncName, 1, syncObjBoth, L"");

		RunAsAdministrator(
			strSyncName,
			strTitle,
			strInitialDir,
			strInitialCmd,
			pi
		);

		// wait for PID of shell launched in admin ConsoleZ
		if (::WaitForSingleObject(pid.GetReqEvent(), 10000) == WAIT_TIMEOUT)
			throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % L"timeout"));

		pi.dwProcessId = *pid.Get();
		pi.hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, pi.dwProcessId);
		if( pi.hProcess == NULL )
		{
			Win32Exception err(::GetLastError());
			throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % err.what()));
		}
	}
	else
	{
		CreateShellProcess(
			strShell,
			strInitialDir,
			userCredentials,
			strInitialCmd,
			strConsoleTitle,
			pi
		);
	}

	// create shared memory objects
	try
	{
		CreateSharedObjects(pi.dwProcessId, userCredentials.netOnly? L"" : userCredentials.strAccountName);
		CreateWatchdog();
	}
	catch(Win32Exception& err)
	{
		throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_CREATE_SHARED_OBJECTS_FAILED)) % err.what()));
	}

	// write startup params
	m_consoleParams->dwParentProcessId     = ::GetCurrentProcessId();
	m_consoleParams->dwNotificationTimeout = g_settingsHandler->GetConsoleSettings().dwChangeRefreshInterval;
	m_consoleParams->dwRefreshInterval     = g_settingsHandler->GetConsoleSettings().dwRefreshInterval;
	m_consoleParams->dwRows                = dwStartupRows;
	m_consoleParams->dwColumns             = dwStartupColumns;
	m_consoleParams->dwBufferRows          = g_settingsHandler->GetConsoleSettings().dwBufferRows;
	m_consoleParams->dwBufferColumns       = g_settingsHandler->GetConsoleSettings().dwBufferColumns;

	m_hConsoleProcess = std::shared_ptr<void>(pi.hProcess, ::CloseHandle);
	m_dwConsolePid    = pi.dwProcessId;

	if (runAsAdministrator)
	{
		::SetEvent(pid.GetRespEvent());
	}
	else
	{
		// inject our hook DLL into console process
		if (!InjectHookDLL(pi))
			throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % L"?"));

		// resume the console process
		::ResumeThread(pi.hThread);
		::CloseHandle(pi.hThread);
	}

	try
	{
		m_consoleMsgPipe.WaitConnect();
	}
	catch(Win32Exception& err)
	{
		throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % err.what()));
	}

	// wait for hook DLL to set console handle
	if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT)
		throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % L"timeout"));

	ShowWindow(SW_HIDE);
}