📄 remoteshell.cpp
字号:
HANDLE hUser = NULL; STARTUPINFO saInfo; PROCESS_INFORMATION psInfo; void *pEnv=NULL; TCHAR tCmdLine[MAX_PATH]; TCHAR tSavedPath[MAX_PATH] = TEXT("."); TCHAR tAccount[256], tPassword[256], tDomain[256], *psztDomain; HANDLE hImpersonatedToken; HRESULT hr; try{ DLogMsg(TEXT("LaunchProcess called: %u\n"), this); DLogWMsg(L"\n Launching:\n %s\n %s\n\n", bCmdLine, bEnv);#ifdef UNICODE wcscpy(tCmdLine, bCmdLine); //swprintf(tCmdLine, L"cmd.exe /c %s", bCmdLine);#else wcstombs(tCmdLine, bCmdLine, wcslen(bCmdLine)+1); //char sTempBuffer[256]; //wcstombs(sTempBuffer, bCmdLine, wcslen(bCmdLine)+1); //sprintf(tCmdLine, "cmd.exe /c %s", sTempBuffer);#endif // Launching of the client processes must be synchronized because // stdin,out,err are redirected for the entire process, not just this thread. if (WaitForSingleObject(g_hLaunchSyncMutex, g_nLaunchTimeout) == WAIT_TIMEOUT) { *nError = 1; SysReAllocString(bErrorMsg, L"LaunchProcess: Timeout while waiting for syncronization object.\n"); LogMsg(TEXT("LaunchProcess: Timeout while waiting for syncronization object.\n")); return S_OK; } // Don't handle errors, just let the process die. // In the future this will be configurable to allow various debugging options. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); // Save stdin, stdout, and stderr hStdin = GetStdHandle(STD_INPUT_HANDLE); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); hStderr = GetStdHandle(STD_ERROR_HANDLE); if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE || hStderr == INVALID_HANDLE_VALUE) { *nError = GetLastError(); SysReAllocString(bErrorMsg, L"LaunchProcess: Unable to get standard handles.\n"); ReleaseMutex(g_hLaunchSyncMutex); return S_OK; } // Set the security attributes to allow handles to be inherited SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.lpSecurityDescriptor = NULL; saAttr.bInheritHandle = TRUE; // Create pipes for stdin, stdout, and stderr // Stdout if (!CreatePipe(&hTempPipe, &hStdoutPipeW, &saAttr, 0)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:CreatePipe failed "); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } // Make the read end of the stdout pipe not inheritable if (!DuplicateHandle(GetCurrentProcess(), hTempPipe, GetCurrentProcess(), &m_hStdoutPipeR, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:DuplicateHandle(StdoutPipeR) failed "); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } // Stderr if (!CreatePipe(&hTempPipe, &hStderrPipeW, &saAttr, 0)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:CreatePipe failed "); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } // Make the read end of the stderr pipe not inheritable if (!DuplicateHandle(GetCurrentProcess(), hTempPipe, GetCurrentProcess(), &m_hStderrPipeR, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:DuplicateHandle(StderrPipeR) failed "); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } // Stdin if (!CreatePipe(&hStdinPipeR, &hTempPipe, &saAttr, 0)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:CreatePipe failed"); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } // Make the write end of the stdin pipe not inheritable if (!DuplicateHandle(GetCurrentProcess(), hTempPipe, GetCurrentProcess(), &m_hStdinPipeW, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:DuplicateHandle(StdoutPipeR) failed "); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } // Set stdin, stdout, and stderr to the ends of the pipe the created process will use if (!SetStdHandle(STD_INPUT_HANDLE, hStdinPipeR)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:SetStdHandle(Input) failed "); SysReAllocString(bErrorMsg, error_msg); goto CLEANUP; } if (!SetStdHandle(STD_OUTPUT_HANDLE, hStdoutPipeW)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:SetStdHandle(Output) failed "); SysReAllocString(bErrorMsg, error_msg); goto RESTORE_CLEANUP; } if (!SetStdHandle(STD_ERROR_HANDLE, hStderrPipeW)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:SetStdHandle(Error) failed "); SysReAllocString(bErrorMsg, error_msg); goto RESTORE_CLEANUP; } // Set up the STARTINFO structure memset(&saInfo, 0, sizeof(STARTUPINFO)); saInfo.cb = sizeof(STARTUPINFO); saInfo.hStdInput = hStdinPipeR; saInfo.hStdOutput = hStdoutPipeW; saInfo.hStdError = hStderrPipeW; saInfo.dwFlags = STARTF_USESTDHANDLES; if (m_bLaunchOnDesktop) saInfo.lpDesktop = TEXT("WinSta0\\Default"); // Set the environment variables SetEnvironmentVariables(bEnv); pEnv = GetEnvironmentStrings(); // Get a handle to the user token either by logging in or impersonating the user. if (wcslen(bAccount)) { // An account was passed in so use it to get the user token. ParseAccountDomain(bAccount, tAccount, tDomain); if (_tcslen(tDomain) < 1) psztDomain = NULL; else psztDomain = tDomain;#ifdef UNICODE wcscpy(tPassword, bPassword);#else wcstombs(tPassword, bPassword, wcslen(bPassword)+1);#endif if (!LogonUser( tAccount, psztDomain, tPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hUser)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:LogonUser failed "); SysReAllocString(bErrorMsg, error_msg); LogWMsg(L"LaunchProcess: LogonUser failed: %d, %s\n", *nError, error_msg); goto RESTORE_CLEANUP; } } else { // No account was passed in so impersonate the client to get a user token hr = CoImpersonateClient(); if (FAILED(hr)) LogMsg(TEXT("LaunchProcess:CoImpersonateClient failed - launching process with process token")); //if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hImpersonatedToken)) if (!OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hImpersonatedToken)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:OpenThreadToken failed: "); SysReAllocString(bErrorMsg, error_msg); LogWMsg(L"LaunchProcess:OpenThreadToken failed: %d, %s\n", *nError, error_msg); goto RESTORE_CLEANUP; } CoRevertToSelf(); //if (!DuplicateTokenEx(hImpersonatedToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hUser)) if (!DuplicateTokenEx(hImpersonatedToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hUser)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:DuplicateTokenEx failed: "); SysReAllocString(bErrorMsg, error_msg); LogWMsg(L"LaunchProcess:DuplicateTokenEx failed: %d, %s\n", *nError, error_msg); goto RESTORE_CLEANUP; } } // Create the process //LogMsg(TEXT("impersonating user\n")); if (ImpersonateLoggedOnUser(hUser)) { // Attempt to change into the directory passed into the function GetCurrentDirectory(MAX_PATH, tSavedPath); if (!SetCurrentDirectoryW(bDir)) { int terror = GetLastError(); char terror_msg[256]; Translate_Error(terror, terror_msg, "LaunchProcess:SetCurrentDirectory failed "); LogMsg(terror_msg); } //LogMsg(TEXT("LaunchInteractiveProcess: about to launch %s.\n"), tCmdLine); if (CreateProcessAsUser( hUser, NULL, tCmdLine, NULL, NULL, TRUE, //DETACHED_PROCESS | IDLE_PRIORITY_CLASS, //CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS, CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP, //DETACHED_PROCESS | IDLE_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP, //CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS | CREATE_SUSPENDED, pEnv, NULL, &saInfo, &psInfo)) { m_hProcess = psInfo.hProcess; //ResumeThread(psInfo.hThread); CloseHandle(psInfo.hThread); LogMsg(TEXT("LaunchProcess: launched '%s'"), tCmdLine); bSuccess = TRUE; *nPid = psInfo.dwProcessId; m_dwProcessId = psInfo.dwProcessId; SysReAllocString(bErrorMsg, L"success"); *nError = 0; } else { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:CreateProcessAsUser failed: "); SysReAllocString(bErrorMsg, error_msg); LogWMsg(L"LaunchProcess: CreateProcessAsUser failed: error %d, %s", *nError, error_msg); LogMsg("LaunchProcess: failed to launch '%s'", tCmdLine); } RevertToSelf(); } else { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:ImpersonateLoggedOnUser failed "); SysReAllocString(bErrorMsg, error_msg); LogWMsg(L"LaunchProcess: ImpersonateLoggedOnUser failed: %d, %s\n", *nError, error_msg); } CloseHandle(hUser); FreeEnvironmentStrings((TCHAR*)pEnv); SetCurrentDirectory(tSavedPath); RemoveEnvironmentVariables(bEnv);RESTORE_CLEANUP: // Restore stdin, stdout, stderr if (!SetStdHandle(STD_INPUT_HANDLE, hStdin)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:SetStdHandle(restore Input) failed "); SysReAllocString(bErrorMsg, error_msg); } if (!SetStdHandle(STD_OUTPUT_HANDLE, hStdout)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:SetStdHandle(restore Output) failed "); SysReAllocString(bErrorMsg, error_msg); } if (!SetStdHandle(STD_ERROR_HANDLE, hStderr)) { *nError = GetLastError(); Translate_Error(*nError, error_msg, L"LaunchProcess:SetStdHandle(restore Error) failed "); SysReAllocString(bErrorMsg, error_msg); } if (bSuccess) { // start threads to monitor output of pipes DWORD dwThreadID; m_hStdoutThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)RedirectStdout, this, 0, &dwThreadID); if (m_hStdoutThread == NULL) SysReAllocString(bErrorMsg, L"Unable to create a thread to redirect standard out.\n"); m_hStderrThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)RedirectStderr, this, 0, &dwThreadID); if (m_hStderrThread == NULL) SysReAllocString(bErrorMsg, L"Unable to create a thread to redirect standard error.\n"); }CLEANUP: ReleaseMutex(g_hLaunchSyncMutex); CloseHandle(hStdoutPipeW); CloseHandle(hStderrPipeW); CloseHandle(hStdinPipeR); }catch(...){ *nError = 1; ReleaseMutex(g_hLaunchSyncMutex); SysReAllocString(bErrorMsg, L"LaunchProcess:Exception thrown"); LogWMsg(L"Exception thrown in LaunchProcess"); } return S_OK;}// Function name : CRemoteShell::GetProcessOutput// Description : // Return type : STDMETHODIMP // Argument : VARIANT *vOutput// Argument : long *nState// Argument : long *nError// Argument : BSTR *bErrorMsgSTDMETHODIMP CRemoteShell::GetProcessOutput(VARIANT *vOutput, long *nState, long *nError, BSTR *bErrorMsg){ SAFEARRAYBOUND bound; void *pBuf; ChunkNode *node; try{ VariantClear(vOutput); vOutput->vt = VT_UI1 | VT_ARRAY; // It may be worthy to put a timeout value here but as is, this would allow a user to leave // a session open for days without timing out. WaitForSingleObject(m_hOutputMutex, INFINITE); // After this block, m_pOutList is valid. if (m_pOutList == NULL) { // Nothing in the list so release the mutex and wait for something to be added to the list. // Release the mutex ReleaseMutex(m_hOutputMutex); // Wait for the event signalling new data has been added to the list WaitForSingleObject(m_hOutputEvent, INFINITE); // Wait for the mutex to syncronize access to the list WaitForSingleObject(m_hOutputMutex, INFINITE); } bound.lLbound = 0; bound.cElements = m_pOutList->dwSize; // Create an array to return the data in. vOutput->parray = SafeArrayCreate(VT_UI1, 1, &bound); // Copy the data in the list to the array if (m_pOutList->dwSize > 0) { SafeArrayAccessData(vOutput->parray, &pBuf); memcpy(pBuf, m_pOutList->pData, m_pOutList->dwSize); SafeArrayUnaccessData(vOutput->parray); } // Remove the node that has just been copied and signal whether there is potentially more data to come. node = m_pOutList; m_pOutList = m_pOutList->pNext; if (m_pOutList == NULL) { m_pOutListTail = NULL; ResetEvent(m_hOutputEvent); } if (node->bStdError) *nState = RSH_OUTPUT_STDERR; else *nState = RSH_OUTPUT_STDOUT; if (node->dwSize > 0) { delete node->pData; *nState = (*nState) | RSH_OUTPUT_MORE; } else { if (WaitForSingleObject(m_hStdoutThread, 5000) != WAIT_OBJECT_0) TerminateThread(m_hStdoutThread, 0); if (WaitForSingleObject(m_hStderrThread, 5000) != WAIT_OBJECT_0) TerminateThread(m_hStderrThread, 0); CloseHandle(m_hStdoutThread); CloseHandle(m_hStderrThread); m_hStdoutThread = NULL; m_hStderrThread = NULL; } m_dwExitCode = node->dwExitCode; delete node; ReleaseMutex(m_hOutputMutex); }catch(...){ *nError = 1; SysReAllocString(bErrorMsg, L"GetInteractiveOutput:Exception thrown"); LogWMsg(L"Exception thrown in GetInteractiveOutput.\n"); } return S_OK;}// Function name : CRemoteShell::PutProcessInput// Description : // Return type : STDMETHODIMP // Argument : VARIANT vInput// Argument : long *nError// Argument : BSTR *bErrorMsgSTDMETHODIMP CRemoteShell::PutProcessInput(VARIANT vInput, long *nError, BSTR *bErrorMsg){ LPVOID pBuf; DWORD size, num_written; if (vInput.vt == (VT_UI1 | VT_ARRAY)) { size = vInput.parray->rgsabound->cElements; SafeArrayAccessData(vInput.parray, &pBuf); WriteFile(m_hStdinPipeW, pBuf, size, &num_written, NULL); SafeArrayUnaccessData(vInput.parray); } return S_OK;}// Function name : CRemoteShell::Abort// Description : // Return type : STDMETHODIMP // Argument : long *nError// Argument : BSTR *bErrorMsgSTDMETHODIMP CRemoteShell::Abort(long *nError, BSTR *bErrorMsg){ if (m_hProcess != NULL) { *nError = 1; if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, m_dwProcessId)) { if (WaitForSingleObject(m_hProcess, 500) == WAIT_OBJECT_0) *nError = 0; } if (*nError) { if (TerminateProcess(m_hProcess, 1)) *nError = 0; else { *nError = GetLastError(); WCHAR error_msg[256]; Translate_Error(*nError, error_msg, L"Abort:TerminateProcess failed "); SysReAllocString(bErrorMsg, error_msg); LogWMsg(L"%d, %s", *nError, error_msg); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -