bool CGuiServer::Start() { // Запустить серверную нить // 120122 - теперь через PipeServer _wsprintf(ms_ServerPipe, SKIPLEN(countof(ms_ServerPipe)) CEGUIPIPENAME, L".", (DWORD)ghWnd); //-V205 mp_GuiServer->SetOverlapped(true); mp_GuiServer->SetLoopCommands(false); mp_GuiServer->SetDummyAnswerSize(sizeof(CESERVER_REQ_HDR)); // Issue 1828: FindWindowEx may fails in some cases, only PID will be working... _wsprintf(ms_ServerPipePID, SKIPLEN(countof(ms_ServerPipePID)) CESERVERPIPENAME, L".", GetCurrentProcessId()); mp_GuiServerPID->SetOverlapped(true); mp_GuiServerPID->SetLoopCommands(false); mp_GuiServerPID->SetDummyAnswerSize(sizeof(CESERVER_REQ_HDR)); PipeServer<CESERVER_REQ>::PipeServerConnected_t lpfnOnConnected = NULL; #ifdef _DEBUG lpfnOnConnected = CGuiServer::OnGuiServerConnected; #endif if (!mp_GuiServer->StartPipeServer(false, ms_ServerPipe, (LPARAM)this, LocalSecurity(), GuiServerCommand, GuiServerFree, lpfnOnConnected, NULL)) { // Ошибка уже показана return false; } mp_GuiServerPID->StartPipeServer(false, ms_ServerPipePID, (LPARAM)this, LocalSecurity(), GuiServerCommand, GuiServerFree, lpfnOnConnected, NULL); return true; }
bool PlugServerStart() { bool lbStarted = false; DWORD dwCurProcId = GetCurrentProcessId(); _wsprintf(gszPluginServerPipe, SKIPLEN(countof(gszPluginServerPipe)) CEPLUGINPIPENAME, L".", dwCurProcId); ghServerTerminateEvent = CreateEvent(NULL,TRUE,FALSE,NULL); _ASSERTE(ghServerTerminateEvent!=NULL); if (ghServerTerminateEvent) ResetEvent(ghServerTerminateEvent); if (!gpPlugServer) { gpPlugServer = (PipeServer<CESERVER_REQ>*)calloc(1, sizeof(*gpPlugServer)); } if (gpPlugServer) { gpPlugServer->SetMaxCount(3); gpPlugServer->SetOverlapped(true); gpPlugServer->SetLoopCommands(false); gpPlugServer->SetDummyAnswerSize(sizeof(CESERVER_REQ_HDR)); lbStarted = gpPlugServer->StartPipeServer(false, gszPluginServerPipe, NULL, LocalSecurity(), PlugServerCommand, PlugServerFree); } _ASSERTE(gpPlugServer!=NULL && lbStarted); return lbStarted; }
bool CGuiServer::Start() { // Запустить серверную нить // 120122 - теперь через PipeServer _wsprintf(ms_ServerPipe, SKIPLEN(countof(ms_ServerPipe)) CEGUIPIPENAME, L".", (DWORD)ghWnd); //-V205 mp_GuiServer->SetOverlapped(true); mp_GuiServer->SetLoopCommands(false); mp_GuiServer->SetDummyAnswerSize(sizeof(CESERVER_REQ_HDR)); PipeServer<CESERVER_REQ>::PipeServerConnected_t lpfnOnConnected = NULL; #ifdef _DEBUG lpfnOnConnected = CGuiServer::OnGuiServerConnected; #endif if (!mp_GuiServer->StartPipeServer(ms_ServerPipe, (LPARAM)this, LocalSecurity(), GuiServerCommand, GuiServerFree, lpfnOnConnected, NULL)) { // Ошибка уже показана return false; } //mh_GuiServerThreadTerminate = CreateEvent(NULL, TRUE, FALSE, NULL); //if (mh_GuiServerThreadTerminate) ResetEvent(mh_GuiServerThreadTerminate); //mh_GuiServerThread = CreateThread(NULL, 0, GuiServerThread, (LPVOID)this, 0, &mn_GuiServerThreadId); return true; }
// Do the attach procedure for the requested process bool CAttachDlg::StartAttach(HWND ahAttachWnd, DWORD anPID, DWORD anBits, AttachProcessType anType, BOOL abAltMode) { bool lbRc = false; wchar_t szPipe[MAX_PATH]; PROCESS_INFORMATION pi = {}; STARTUPINFO si = {sizeof(si)}; SHELLEXECUTEINFO sei = {sizeof(sei)}; CESERVER_REQ *pIn = NULL, *pOut = NULL; HANDLE hPipeTest = NULL; HANDLE hPluginTest = NULL; HANDLE hProcTest = NULL; DWORD nErrCode = 0; bool lbCreate; CESERVER_CONSOLE_MAPPING_HDR srv; DWORD nWrapperWait = -1; DWORD nWrapperResult = -1; if (!ahAttachWnd || !anPID || !anBits || !anType) { MBoxAssert(ahAttachWnd && anPID && anBits && anType); goto wrap; } if (gpSetCls->isAdvLogging) { wchar_t szInfo[128]; _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"CAttachDlg::StartAttach HWND=x%08X, PID=%u, Bits%u, Type=%u, AltMode=%u", (DWORD)(DWORD_PTR)ahAttachWnd, anPID, anBits, (UINT)anType, abAltMode); gpConEmu->LogString(szInfo); } if (LoadSrvMapping(ahAttachWnd, srv)) { pIn = ExecuteNewCmd(CECMD_ATTACH2GUI, sizeof(CESERVER_REQ_HDR)); pOut = ExecuteSrvCmd(srv.nServerPID, pIn, ghWnd); if (pOut && (pOut->hdr.cbSize >= (sizeof(CESERVER_REQ_HDR)+sizeof(DWORD))) && (pOut->dwData[0] != 0)) { // Our console server had been already started // and we successfully have completed the attach lbRc = true; goto wrap; } ExecuteFreeResult(pIn); ExecuteFreeResult(pOut); } // Is it a Far Manager with our ConEmu.dll plugin loaded? _wsprintf(szPipe, SKIPLEN(countof(szPipe)) CEPLUGINPIPENAME, L".", anPID); hPluginTest = CreateFile(szPipe, GENERIC_READ|GENERIC_WRITE, 0, LocalSecurity(), OPEN_EXISTING, 0, NULL); if (hPluginTest && hPluginTest != INVALID_HANDLE_VALUE) { CloseHandle(hPluginTest); goto DoPluginCall; } // May be there is already ConEmuHk[64].dll loaded? Either it is already in the another ConEmu VCon? _wsprintf(szPipe, SKIPLEN(countof(szPipe)) CEHOOKSPIPENAME, L".", anPID); hPipeTest = CreateFile(szPipe, GENERIC_READ|GENERIC_WRITE, 0, LocalSecurity(), OPEN_EXISTING, 0, NULL); if (hPipeTest && hPipeTest != INVALID_HANDLE_VALUE) { CloseHandle(hPipeTest); goto DoExecute; } wchar_t szSrv[MAX_PATH+64], szArgs[128]; wcscpy_c(szSrv, gpConEmu->ms_ConEmuBaseDir); wcscat_c(szSrv, (anBits==64) ? L"\\ConEmuC64.exe" : L"\\ConEmuC.exe"); if (abAltMode && (anType == apt_Console)) { _wsprintf(szArgs, SKIPLEN(countof(szArgs)) L" /ATTACH /CONPID=%u /GID=%u /GHWND=%08X", anPID, GetCurrentProcessId(), LODWORD(ghWnd)); } else { _wsprintf(szArgs, SKIPLEN(countof(szArgs)) L" /INJECT=%u", anPID); abAltMode = FALSE; } si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; if (anType == apt_Gui) { gpConEmu->CreateGuiAttachMapping(anPID); } hProcTest = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, anPID); // If the attaching process is running as admin (elevated) we have to run ConEmuC as admin too if (hProcTest == NULL) { nErrCode = GetLastError(); MBoxAssert(hProcTest!=NULL || nErrCode==ERROR_ACCESS_DENIED); sei.hwnd = ghWnd; sei.fMask = (abAltMode ? 0 : SEE_MASK_NO_CONSOLE)|SEE_MASK_NOCLOSEPROCESS|SEE_MASK_NOASYNC; sei.lpVerb = L"runas"; sei.lpFile = szSrv; sei.lpParameters = szArgs; sei.lpDirectory = gpConEmu->ms_ConEmuBaseDir; sei.nShow = SW_SHOWMINIMIZED; lbCreate = ShellExecuteEx(&sei); if (lbCreate) { MBoxAssert(sei.hProcess!=NULL); pi.hProcess = sei.hProcess; } } else { // Normal start DWORD dwFlags = 0 | (abAltMode ? CREATE_NO_WINDOW : CREATE_NEW_CONSOLE) | CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS; lbCreate = CreateProcess(szSrv, szArgs, NULL, NULL, FALSE, dwFlags, NULL, NULL, &si, &pi); } if (!lbCreate) { wchar_t szErrMsg[MAX_PATH+255], szTitle[128]; DWORD dwErr = GetLastError(); _wsprintf(szErrMsg, SKIPLEN(countof(szErrMsg)) L"Can't start %s server\n%s %s", abAltMode ? L"injection" : L"console", szSrv, szArgs); _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(szErrMsg, dwErr, 0, szTitle); goto wrap; } if (abAltMode) { lbRc = true; goto wrap; } nWrapperWait = WaitForSingleObject(pi.hProcess, INFINITE); nWrapperResult = -1; GetExitCodeProcess(pi.hProcess, &nWrapperResult); CloseHandle(pi.hProcess); if (pi.hThread) CloseHandle(pi.hThread); if (((int)nWrapperResult != CERR_HOOKS_WAS_SET) && ((int)nWrapperResult != CERR_HOOKS_WAS_ALREADY_SET)) { goto wrap; } DoExecute: // Not the attaching process has our ConEmuHk[64].dll loaded // and we can request to start console server for that console or ChildGui pIn = ExecuteNewCmd(CECMD_STARTSERVER, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_START)); pIn->NewServer.nGuiPID = GetCurrentProcessId(); pIn->NewServer.hGuiWnd = ghWnd; if (anType == apt_Gui) { _ASSERTE(ahAttachWnd && IsWindow(ahAttachWnd)); pIn->NewServer.hAppWnd = ahAttachWnd; } goto DoPipeCall; DoPluginCall: // Ask Far Manager plugin to do the attach pIn = ExecuteNewCmd(CECMD_ATTACH2GUI, sizeof(CESERVER_REQ_HDR)); goto DoPipeCall; DoPipeCall: pOut = ExecuteCmd(szPipe, pIn, 500, ghWnd); if (!pOut || (pOut->hdr.cbSize < pIn->hdr.cbSize) || (pOut->dwData[0] == 0)) { _ASSERTE(pOut && pOut->hdr.cbSize == (sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_START))); wchar_t szMsg[255], szTitle[128]; wcscpy_c(szMsg, L"Failed to start console server in the remote process"); if (hPluginTest && hPluginTest != INVALID_HANDLE_VALUE) wcscat_c(szMsg, L"\nFar ConEmu plugin was loaded"); if (hPipeTest && hPipeTest != INVALID_HANDLE_VALUE) wcscat_c(szMsg, L"\nHooks already were set"); _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(szMsg, (pOut && (pOut->hdr.cbSize >= pIn->hdr.cbSize)) ? pOut->dwData[1] : -1, 0, szTitle); goto wrap; } lbRc = true; wrap: SafeCloseHandle(hProcTest); UNREFERENCED_PARAMETER(nErrCode); UNREFERENCED_PARAMETER(nWrapperWait); ExecuteFreeResult(pIn); ExecuteFreeResult(pOut); return lbRc; }
// CIR_OK=0 - OK, CIR_AlreadyInjected=1 - Already injected, иначе - ошибка // Здесь вызывается CreateRemoteThread CINFILTRATE_EXIT_CODES InjectRemote(DWORD nRemotePID, bool abDefTermOnly /*= false */) { CINFILTRATE_EXIT_CODES iRc = CIR_GeneralError/*-1*/; bool lbWin64 = WIN3264TEST((IsWindows64()!=0),true); bool is32bit; int nBits; DWORD nWrapperWait = (DWORD)-1, nWrapperResult = (DWORD)-1; HANDLE hProc = NULL; wchar_t szSelf[MAX_PATH+16], szHooks[MAX_PATH+16]; wchar_t *pszNamePtr, szArgs[32]; wchar_t szName[64]; HANDLE hEvent = NULL; HANDLE hDefTermReady = NULL; bool bAlreadyHooked = false; HANDLE hSnap = NULL; MODULEENTRY32 mi = {sizeof(mi)}; HMODULE ptrOuterKernel = NULL; if (!GetModuleFileName(NULL, szSelf, MAX_PATH)) { iRc = CIR_GetModuleFileName/*-200*/; goto wrap; } wcscpy_c(szHooks, szSelf); pszNamePtr = (wchar_t*)PointToName(szHooks); if (!pszNamePtr) { iRc = CIR_GetModuleFileName/*-200*/; goto wrap; } // Hey, may be ConEmuHk.dll is already loaded? hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, nRemotePID); if (!hSnap || (hSnap == INVALID_HANDLE_VALUE)) { iRc = CIR_SnapshotCantBeOpened/*-113*/; goto wrap; } else if (hSnap && Module32First(hSnap, &mi)) { // 130829 - Let load newer(!) ConEmuHk.dll into target process. // 141201 - Also we need to be sure in kernel32.dll address LPCWSTR pszConEmuHk = WIN3264TEST(L"conemuhk.", L"conemuhk64."); size_t nDllNameLen = lstrlen(pszConEmuHk); // Out preferred module name wchar_t szOurName[40] = {}; wchar_t szMinor[8] = L""; lstrcpyn(szMinor, _CRT_WIDE(MVV_4a), countof(szMinor)); _wsprintf(szOurName, SKIPLEN(countof(szOurName)) CEDEFTERMDLLFORMAT /*L"ConEmuHk%s.%02u%02u%02u%s.dll"*/, WIN3264TEST(L"",L"64"), MVV_1, MVV_2, MVV_3, szMinor); CharLowerBuff(szOurName, lstrlen(szOurName)); // Go to enumeration wchar_t szName[64]; do { LPCWSTR pszName = PointToName(mi.szModule); // Name of ConEmuHk*.*.dll module may be changed (copied to %APPDATA%) if (!pszName || !*pszName) continue; lstrcpyn(szName, pszName, countof(szName)); CharLowerBuff(szName, lstrlen(szName)); if (!ptrOuterKernel && (lstrcmp(szName, L"kernel32.dll") == 0)) { ptrOuterKernel = mi.hModule; } // ConEmuHk*.*.dll? if (!bAlreadyHooked && (wmemcmp(szName, pszConEmuHk, nDllNameLen) == 0) && (wmemcmp(szName+lstrlen(szName)-4, L".dll", 4) == 0)) { // Yes! ConEmuHk.dll already loaded into nRemotePID! // But what is the version? Let don't downgrade loaded version! if (lstrcmp(szName, szOurName) >= 0) { // OK, szName is newer or equal to our build bAlreadyHooked = true; } } // Stop enumeration? if (bAlreadyHooked && ptrOuterKernel) break; } while (Module32Next(hSnap, &mi)); // Check done } SafeCloseHandle(hSnap); // Already hooked? if (bAlreadyHooked) { iRc = CIR_AlreadyInjected/*1*/; goto wrap; } if (!ptrOuterKernel) { iRc = CIR_OuterKernelAddr/*-112*/; goto wrap; } // Check, if we can access that process hProc = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, nRemotePID); if (hProc == NULL) { iRc = CIR_OpenProcess/*-201*/; goto wrap; } // Go to hook // Preparing Events _wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOK, nRemotePID); if (!abDefTermOnly) { // When running in normal mode (NOT set up as default terminal) // we need full initialization procedure, not a light one when hooking explorer.exe hEvent = OpenEvent(EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, szName); if (hEvent) { ResetEvent(hEvent); CloseHandle(hEvent); } } else { hEvent = CreateEvent(LocalSecurity(), FALSE, FALSE, szName); SetEvent(hEvent); _wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOKOK, nRemotePID); hDefTermReady = CreateEvent(LocalSecurity(), FALSE, FALSE, szName); ResetEvent(hDefTermReady); } // Creating as remote thread. // Resetting this event notify ConEmuHk about // 1) need to determine MainThreadId // 2) need to start pipe server _wsprintf(szName, SKIPLEN(countof(szName)) CECONEMUROOTTHREAD, nRemotePID); hEvent = OpenEvent(EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, szName); if (hEvent) { ResetEvent(hEvent); CloseHandle(hEvent); } // Определить битность процесса, Если он 32битный, а текущий - ConEmuC64.exe // Перезапустить 32битную версию ConEmuC.exe nBits = GetProcessBits(nRemotePID, hProc); if (nBits == 0) { // Do not even expected, ConEmu GUI must run ConEmuC elevated if required. iRc = CIR_GetProcessBits/*-204*/; goto wrap; } is32bit = (nBits == 32); if (is32bit != WIN3264TEST(true,false)) { // По идее, такого быть не должно. ConEmu должен был запустить соответствующий conemuC*.exe _ASSERTE(is32bit == WIN3264TEST(true,false)); PROCESS_INFORMATION pi = {}; STARTUPINFO si = {sizeof(si)}; _wcscpy_c(pszNamePtr, 16, is32bit ? L"ConEmuC.exe" : L"ConEmuC64.exe"); _wsprintf(szArgs, SKIPLEN(countof(szArgs)) L" /INJECT=%u", nRemotePID); if (!CreateProcess(szHooks, szArgs, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { iRc = CIR_CreateProcess/*-202*/; goto wrap; } nWrapperWait = WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &nWrapperResult); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if ((nWrapperResult != CERR_HOOKS_WAS_SET) && (nWrapperResult != CERR_HOOKS_WAS_ALREADY_SET)) { iRc = CIR_WrapperResult/*-203*/; SetLastError(nWrapperResult); goto wrap; } // Значит всю работу сделал враппер iRc = CIR_OK/*0*/; goto wrap; } // Поехали _wcscpy_c(pszNamePtr, 16, is32bit ? L"ConEmuHk.dll" : L"ConEmuHk64.dll"); if (!FileExists(szHooks)) { iRc = CIR_ConEmuHkNotFound/*-250*/; goto wrap; } if (abDefTermOnly) { CINFILTRATE_EXIT_CODES iFRc = PrepareHookModule(szHooks); if (iFRc != 0) { iRc = iFRc; goto wrap; } } iRc = InfiltrateDll(hProc, ptrOuterKernel, szHooks); // Если создавали временную копию - запланировать ее удаление if (abDefTermOnly && (lstrcmpi(szHooks, szSelf) != 0)) { MoveFileEx(szHooks, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } wrap: if (hProc != NULL) CloseHandle(hProc); // But check the result of the operation //_ASSERTE(FALSE && "WaitForSingleObject(hDefTermReady)"); if ((iRc == 0) && hDefTermReady) { _ASSERTE(abDefTermOnly); DWORD nWaitReady = WaitForSingleObject(hDefTermReady, CEDEFAULTTERMHOOKWAIT/*==0*/); if (nWaitReady == WAIT_TIMEOUT) { iRc = CIR_DefTermWaitingFailed/*-300*/; // Failed to start hooking thread in remote process } } return iRc; }
// nTimeout - таймаут подключения HANDLE ExecuteOpenPipe(const wchar_t* szPipeName, wchar_t (&szErr)[MAX_PATH*2], const wchar_t* szModule, DWORD nServerPID, DWORD nTimeout) { HANDLE hPipe = NULL; DWORD dwErr = 0, dwMode = 0; BOOL fSuccess = FALSE; DWORD dwStartTick = GetTickCount(); DWORD nSleepError = 10; int nTries = 10; // допустимое количество обломов, отличных от ERROR_PIPE_BUSY. после каждого - Sleep(nSleepError); DWORD nOpenPipeTimeout = nTimeout ? max(nTimeout,EXECUTE_CMD_OPENPIPE_TIMEOUT) : EXECUTE_CMD_OPENPIPE_TIMEOUT; BOOL bWaitPipeRc = FALSE, bWaitCalled = FALSE; DWORD nWaitPipeErr = 0; DWORD nDuration = 0; #ifdef _DEBUG wchar_t szDbgMsg[512], szTitle[128]; #endif _ASSERTE(LocalSecurity()!=NULL); #ifdef _DEBUG BOOL lbServerIsDebugged = FALSE; // WinXP SP1 и выше typedef BOOL (WINAPI* CheckRemoteDebuggerPresent_t)(HANDLE hProcess, PBOOL pbDebuggerPresent); static CheckRemoteDebuggerPresent_t _CheckRemoteDebuggerPresent = NULL; if (nServerPID) { if (!_CheckRemoteDebuggerPresent) _CheckRemoteDebuggerPresent = (CheckRemoteDebuggerPresent_t)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "CheckRemoteDebuggerPresent"); if (_CheckRemoteDebuggerPresent) { HANDLE hProcess = OpenProcess(MY_PROCESS_ALL_ACCESS, FALSE, nServerPID); if (hProcess) { BOOL lb = FALSE; if (_CheckRemoteDebuggerPresent(hProcess, &lb) && lb) lbServerIsDebugged = TRUE; CloseHandle(hProcess); } } } #endif // Try to open a named pipe; wait for it, if necessary. while (1) { hPipe = CreateFile( szPipeName, // pipe name GENERIC_READ|GENERIC_WRITE, 0, // no sharing LocalSecurity(), // default security attributes OPEN_EXISTING, // opens existing pipe 0, // default attributes NULL); // no template file dwErr = GetLastError(); // Break if the pipe handle is valid. if (hPipe != INVALID_HANDLE_VALUE) break; // OK, открыли #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); msprintf(szDbgMsg, countof(szDbgMsg), L"Can't open pipe, ErrCode=%u\n%s\nWait: %u,%u,%u", dwErr, szPipeName, bWaitCalled, bWaitPipeRc, nWaitPipeErr); int nBtn = ::MessageBox(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL|MB_RETRYCANCEL); if (nBtn == IDCANCEL) return NULL; } #endif nDuration = GetTickCount() - dwStartTick; if (dwErr == ERROR_PIPE_BUSY) { if ((nTries > 0) && (nDuration < nOpenPipeTimeout)) { bWaitCalled = TRUE; // All pipe instances are busy, so wait for 500 ms. bWaitPipeRc = WaitNamedPipe(szPipeName, 500); nWaitPipeErr = GetLastError(); UNREFERENCED_PARAMETER(bWaitPipeRc); UNREFERENCED_PARAMETER(nWaitPipeErr); // -- 120602 раз они заняты (но живы), то будем ждать, пока не освободятся //nTries--; continue; } else { _ASSERTEX(dwErr != ERROR_PIPE_BUSY); } } // Сделаем так, чтобы хотя бы пару раз он попробовал повторить if ((nTries <= 0) || (nDuration > nOpenPipeTimeout)) { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X, Timeout", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); } return NULL; } else { nTries--; } // Может быть пайп еще не создан (в процессе срабатывания семафора) if (dwErr == ERROR_FILE_NOT_FOUND) { Sleep(nSleepError); continue; } // Exit if an error other than ERROR_PIPE_BUSY occurs. // -- if (dwErr != ERROR_PIPE_BUSY) // уже проверено выше { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); } return NULL; } // Уже сделано выше //// All pipe instances are busy, so wait for 500 ms. //WaitNamedPipe(szPipeName, 500); //if (!WaitNamedPipe(szPipeName, 1000) ) //{ // dwErr = GetLastError(); // if (pszErr) // { // StringCchPrintf(pszErr, countof(pszErr), L"%s: WaitNamedPipe(%s) failed, code=0x%08X, WaitNamedPipe", // szModule ? szModule : L"Unknown", szPipeName, dwErr); // // Видимо это возникает в момент запуска (обычно для ShiftEnter - новая консоль) // // не сразу срабатывает GUI и RCon еще не создал Pipe для HWND консоли // _ASSERTE(dwErr == 0); // } // return NULL; //} } #ifdef _DEBUG DWORD nCurState = 0, nCurInstances = 0; BOOL bCurState = GetNamedPipeHandleState(hPipe, &nCurState, &nCurInstances, NULL, NULL, NULL, 0); #endif // The pipe connected; change to message-read mode. dwMode = PIPE_READMODE_MESSAGE; fSuccess = SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL); // don't set maximum time #if 0 if (!fSuccess) { dwErr = GetLastError(); _ASSERTE(fSuccess); //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: SetNamedPipeHandleState(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); #ifdef _DEBUG int nCurLen = lstrlen(szErr); msprintf(szErr+nCurLen, countof(szErr)-nCurLen, L"\nCurState: %u,x%08X,%u", bCurState, nCurState, nCurInstances); #endif } CloseHandle(hPipe); #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); ::MessageBox(NULL, szErr, szTitle, MB_SYSTEMMODAL); } #endif return NULL; } #endif return hPipe; }
// nTimeout - таймаут подключения HANDLE ExecuteOpenPipe(const wchar_t* szPipeName, wchar_t (&szErr)[MAX_PATH*2], const wchar_t* szModule, DWORD nServerPID, DWORD nTimeout, BOOL Overlapped /*= FALSE*/, HANDLE hStop /*= NULL*/) { HANDLE hPipe = NULL; DWORD dwErr = 0, dwMode = 0; BOOL fSuccess = FALSE; DWORD dwStartTick = GetTickCount(); DWORD nSleepError = 10; // допустимое количество обломов, отличных от ERROR_PIPE_BUSY. после каждого - Sleep(nSleepError); int nTries = 10; // nTimeout должен ограничивать ВЕРХНЮЮ границу времени ожидания _ASSERTE(EXECUTE_CMD_OPENPIPE_TIMEOUT >= nTimeout); DWORD nOpenPipeTimeout = nTimeout ? min(nTimeout,EXECUTE_CMD_OPENPIPE_TIMEOUT) : EXECUTE_CMD_OPENPIPE_TIMEOUT; _ASSERTE(nOpenPipeTimeout > 0); DWORD nWaitPipeTimeout = min(250,nOpenPipeTimeout); BOOL bWaitPipeRc = FALSE, bWaitCalled = FALSE; DWORD nWaitPipeErr = 0; DWORD nDuration = 0; DWORD nStopWaitRc = (DWORD)-1; #ifdef _DEBUG wchar_t szDbgMsg[512], szTitle[128]; #endif // WinXP SP1 и выше DEBUGTEST(BOOL lbServerIsDebugged = nServerPID ? IsProcessDebugged(nServerPID) : FALSE); _ASSERTE(LocalSecurity()!=NULL); // Try to open a named pipe; wait for it, if necessary. while (1) { hPipe = CreateFile( szPipeName, // pipe name GENERIC_READ|GENERIC_WRITE, 0, // no sharing LocalSecurity(), // default security attributes OPEN_EXISTING, // opens existing pipe (Overlapped ? FILE_FLAG_OVERLAPPED : 0), // default attributes NULL); // no template file dwErr = GetLastError(); // Break if the pipe handle is valid. if (hPipe != INVALID_HANDLE_VALUE) { _ASSERTE(hPipe); break; // OK, открыли } #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); msprintf(szDbgMsg, countof(szDbgMsg), L"Can't open pipe, ErrCode=%u\n%s\nWait: %u,%u,%u", dwErr, szPipeName, bWaitCalled, bWaitPipeRc, nWaitPipeErr); int nBtn = ::MessageBox(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL|MB_RETRYCANCEL); if (nBtn == IDCANCEL) return NULL; } #endif nDuration = GetTickCount() - dwStartTick; if (hStop) { // Затребовано завершение приложения или еще что-то nStopWaitRc = WaitForSingleObject(hStop, 0); if (nStopWaitRc == WAIT_OBJECT_0) { return NULL; } } if (dwErr == ERROR_PIPE_BUSY) { if ((nTries > 0) && (nDuration < nOpenPipeTimeout)) { bWaitCalled = TRUE; // All pipe instances are busy, so wait for a while (not more 500 ms). bWaitPipeRc = WaitNamedPipe(szPipeName, nWaitPipeTimeout); nWaitPipeErr = GetLastError(); UNREFERENCED_PARAMETER(bWaitPipeRc); UNREFERENCED_PARAMETER(nWaitPipeErr); // -- 120602 раз они заняты (но живы), то будем ждать, пока не освободятся //nTries--; continue; } else { _ASSERTEX(dwErr != ERROR_PIPE_BUSY); } } // Сделаем так, чтобы хотя бы пару раз он попробовал повторить if ((nTries <= 0) || (nDuration > nOpenPipeTimeout)) { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X, Timeout", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); _ASSERTEX(FALSE && "Pipe open failed with timeout!"); } return NULL; } else { nTries--; } // Может быть пайп еще не создан (в процессе срабатывания семафора) if (dwErr == ERROR_FILE_NOT_FOUND) { // Wait for a while (10 ms) Sleep(nSleepError); continue; } // Exit if an error other than ERROR_PIPE_BUSY occurs. // -- if (dwErr != ERROR_PIPE_BUSY) // уже проверено выше { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); } return NULL; } // Уже сделано выше //// All pipe instances are busy, so wait for 500 ms. //WaitNamedPipe(szPipeName, 500); //if (!WaitNamedPipe(szPipeName, 1000) ) //{ // dwErr = GetLastError(); // if (pszErr) // { // StringCchPrintf(pszErr, countof(pszErr), L"%s: WaitNamedPipe(%s) failed, code=0x%08X, WaitNamedPipe", // szModule ? szModule : L"Unknown", szPipeName, dwErr); // // Видимо это возникает в момент запуска (обычно для ShiftEnter - новая консоль) // // не сразу срабатывает GUI и RCon еще не создал Pipe для HWND консоли // _ASSERTE(dwErr == 0); // } // return NULL; //} } #ifdef _DEBUG DWORD nCurState = 0, nCurInstances = 0; BOOL bCurState = GetNamedPipeHandleState(hPipe, &nCurState, &nCurInstances, NULL, NULL, NULL, 0); #endif // The pipe connected; change to message-read mode. dwMode = CE_PIPE_READMODE; fSuccess = SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL); // don't set maximum time #if 0 if (!fSuccess) { dwErr = GetLastError(); _ASSERTE(fSuccess); //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: SetNamedPipeHandleState(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); #ifdef _DEBUG int nCurLen = lstrlen(szErr); msprintf(szErr+nCurLen, countof(szErr)-nCurLen, L"\nCurState: %u,x%08X,%u", bCurState, nCurState, nCurInstances); #endif } CloseHandle(hPipe); #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); ::MessageBox(NULL, szErr, szTitle, MB_SYSTEMMODAL); } #endif return NULL; } #endif UNREFERENCED_PARAMETER(bWaitCalled); UNREFERENCED_PARAMETER(fSuccess); return hPipe; }
bool CAttachDlg::StartAttach(HWND ahAttachWnd, DWORD anPID, DWORD anBits, AttachProcessType anType, BOOL abAltMode) { bool lbRc = false; // Тут нужно получить инфу из списка и дернуть собственно аттач wchar_t szPipe[MAX_PATH]; PROCESS_INFORMATION pi = {}; STARTUPINFO si = {sizeof(si)}; SHELLEXECUTEINFO sei = {sizeof(sei)}; CESERVER_REQ *pIn = NULL, *pOut = NULL; HANDLE hPipeTest = NULL, hProcTest = NULL; DWORD nErrCode = 0; bool lbCreate; CESERVER_CONSOLE_MAPPING_HDR srv; DWORD nWrapperWait = -1; DWORD nWrapperResult = -1; if (!ahAttachWnd || !anPID || !anBits || !anType) { MBoxAssert(ahAttachWnd && anPID && anBits && anType); goto wrap; } if (gpSetCls->isAdvLogging) { wchar_t szInfo[128]; _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"CAttachDlg::StartAttach HWND=x%08X, PID=%u, Bits%u, Type=%u, AltMode=%u", (DWORD)(DWORD_PTR)ahAttachWnd, anPID, anBits, (UINT)anType, abAltMode); gpConEmu->LogString(szInfo); } if (LoadSrvMapping(ahAttachWnd, srv)) { pIn = ExecuteNewCmd(CECMD_ATTACH2GUI, sizeof(CESERVER_REQ_HDR)); pOut = ExecuteSrvCmd(srv.nServerPID, pIn, ghWnd); if (pOut && (pOut->hdr.cbSize >= (sizeof(CESERVER_REQ_HDR)+sizeof(DWORD))) && (pOut->dwData[0] != 0)) { lbRc = true; // Успешно подцепились goto wrap; } ExecuteFreeResult(pIn); ExecuteFreeResult(pOut); } // Может быть в процессе уже есть ConEmuHk.dll? Или этот процесс вообще уже во вкладке другого ConEmu? _wsprintf(szPipe, SKIPLEN(countof(szPipe)) CEHOOKSPIPENAME, L".", anPID); hPipeTest = CreateFile(szPipe, GENERIC_READ|GENERIC_WRITE, 0, LocalSecurity(), OPEN_EXISTING, 0, NULL); if (hPipeTest && hPipeTest != INVALID_HANDLE_VALUE) { CloseHandle(hPipeTest); goto DoExecute; } wchar_t szSrv[MAX_PATH+64], szArgs[128]; wcscpy_c(szSrv, gpConEmu->ms_ConEmuBaseDir); wcscat_c(szSrv, (anBits==64) ? L"\\ConEmuC64.exe" : L"\\ConEmuC.exe"); if (abAltMode && (anType == apt_Console)) { _wsprintf(szArgs, SKIPLEN(countof(szArgs)) L" /ATTACH /CONPID=%u /GID=%u /GHWND=%08X", anPID, GetCurrentProcessId(), (DWORD)ghWnd); } else { _wsprintf(szArgs, SKIPLEN(countof(szArgs)) L" /INJECT=%u", anPID); abAltMode = FALSE; } TODO("Определить, может он уже под админом? Тогда и ConEmuC.exe под админом запускать нужно"); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; if (anType == apt_Gui) { gpConEmu->CreateGuiAttachMapping(anPID); } hProcTest = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, anPID); if (hProcTest == NULL) { nErrCode = GetLastError(); MBoxAssert(hProcTest!=NULL || nErrCode==ERROR_ACCESS_DENIED); sei.hwnd = ghWnd; sei.fMask = (abAltMode ? 0 : SEE_MASK_NO_CONSOLE)|SEE_MASK_NOCLOSEPROCESS|SEE_MASK_NOASYNC; sei.lpVerb = L"runas"; sei.lpFile = szSrv; sei.lpParameters = szArgs; sei.lpDirectory = gpConEmu->ms_ConEmuBaseDir; sei.nShow = SW_SHOWMINIMIZED; lbCreate = ShellExecuteEx(&sei); if (lbCreate) { MBoxAssert(sei.hProcess!=NULL); pi.hProcess = sei.hProcess; } } else { lbCreate = CreateProcess(szSrv, szArgs, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS|(abAltMode ? CREATE_NO_WINDOW : CREATE_NEW_CONSOLE), NULL, NULL, &si, &pi); } if (!lbCreate) { wchar_t szErrMsg[MAX_PATH+255], szTitle[128]; DWORD dwErr = GetLastError(); _wsprintf(szErrMsg, SKIPLEN(countof(szErrMsg)) L"Can't start %s server\n%s %s", abAltMode ? L"injection" : L"console", szSrv, szArgs); _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(szErrMsg, dwErr, 0, szTitle); goto wrap; } if (abAltMode) { TODO("Подождать бы завершения процесса, или пока он подцепится к GUI"); lbRc = true; goto wrap; } nWrapperWait = WaitForSingleObject(pi.hProcess, INFINITE); nWrapperResult = -1; GetExitCodeProcess(pi.hProcess, &nWrapperResult); CloseHandle(pi.hProcess); if (pi.hThread) CloseHandle(pi.hThread); if (((int)nWrapperResult != CERR_HOOKS_WAS_SET) && ((int)nWrapperResult != CERR_HOOKS_WAS_ALREADY_SET)) { goto wrap; } DoExecute: // Теперь можно дернуть созданный в удаленном процессе пайп для запуска в той консоли сервера. pIn = ExecuteNewCmd(CECMD_STARTSERVER, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_START)); pIn->NewServer.nGuiPID = GetCurrentProcessId(); pIn->NewServer.hGuiWnd = ghWnd; if (anType == apt_Gui) { _ASSERTE(ahAttachWnd && IsWindow(ahAttachWnd)); pIn->NewServer.hAppWnd = ahAttachWnd; } pOut = ExecuteCmd(szPipe, pIn, 500, ghWnd); if (!pOut || (pOut->hdr.cbSize < pIn->hdr.cbSize) || (pOut->dwData[0] == 0)) { _ASSERTE(pOut && pOut->hdr.cbSize == (sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_START))); wchar_t szMsg[255], szTitle[128]; wcscpy_c(szMsg, L"Failed to start console server in the remote process"); if (hPipeTest && hPipeTest != INVALID_HANDLE_VALUE) wcscat_c(szMsg, L"\nHooks already was set"); _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(szMsg, (pOut && (pOut->hdr.cbSize >= pIn->hdr.cbSize)) ? pOut->dwData[1] : -1, 0, szTitle); goto wrap; } lbRc = true; wrap: UNREFERENCED_PARAMETER(nErrCode); UNREFERENCED_PARAMETER(nWrapperWait); ExecuteFreeResult(pIn); ExecuteFreeResult(pOut); return lbRc; }
DWORD WINAPI DllStart(LPVOID /*apParm*/) { wchar_t *szModule = (wchar_t*)calloc((MAX_PATH+1),sizeof(wchar_t)); if (!GetModuleFileName(NULL, szModule, MAX_PATH+1)) _wcscpy_c(szModule, MAX_PATH+1, L"GetModuleFileName failed"); const wchar_t* pszName = PointToName(szModule); #if defined(SHOW_EXE_TIMINGS) || defined(SHOW_EXE_MSGBOX) wchar_t szTimingMsg[512]; UNREFERENCED_PARAMETER(szTimingMsg); HANDLE hTimingHandle = GetStdHandle(STD_OUTPUT_HANDLE); if (!lstrcmpi(pszName, SHOW_EXE_MSGBOX_NAME)) { gbShowExeMsgBox = true; } #endif // ******************* begin ********************* print_timings(L"DllStart: InitializeHookedModules"); InitializeHookedModules(); //HANDLE hStartedEvent = (HANDLE)apParm; #if defined(SHOW_EXE_MSGBOX) if (gbShowExeMsgBox) { STARTUPINFO si = {sizeof(si)}; GetStartupInfo(&si); LPCWSTR pszCmd = GetCommandLineW(); // GuiMessageBox еще не прокатит, ничего не инициализировано HMODULE hUser = LoadLibrary(user32); typedef int (WINAPI* MessageBoxW_t)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); if (hUser) { MessageBoxW_t MsgBox = (MessageBoxW_t)GetProcAddress(hUser, "MessageBoxW"); if (MsgBox) { wchar_t szMsg[128]; lstrcpyn(szMsg, pszName, 96); lstrcat(szMsg, L" loaded!"); wchar_t szTitle[64]; msprintf(szTitle, countof(szTitle), L"ConEmuHk, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); MsgBox(NULL, szMsg, szTitle, MB_SYSTEMMODAL); } FreeLibrary(hUser); } } #endif #ifdef _DEBUG { wchar_t szCpInfo[128]; DWORD nCP = GetConsoleOutputCP(); _wsprintf(szCpInfo, SKIPLEN(countof(szCpInfo)) L"Current Output CP = %u", nCP); print_timings(szCpInfo); } #endif if ((lstrcmpi(pszName, L"powershell.exe") == 0) || (lstrcmpi(pszName, L"powershell") == 0)) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if (IsOutputHandle(hStdOut)) { gbPowerShellMonitorProgress = true; MY_CONSOLE_SCREEN_BUFFER_INFOEX csbi = {sizeof(csbi)}; if (apiGetConsoleScreenBufferInfoEx(hStdOut, &csbi)) { gnConsolePopupColors = csbi.wPopupAttributes; } else { WARNING("Получить Popup атрибуты из мэппинга"); //gnConsolePopupColors = ...; gnConsolePopupColors = 0; } } } // Поскольку процедура в принципе может быть кем-то перехвачена, сразу найдем адрес // iFindAddress = FindKernelAddress(pi.hProcess, pi.dwProcessId, &fLoadLibrary); //HMODULE hKernel = ::GetModuleHandle(L"kernel32.dll"); //if (hKernel) //{ // gfnLoadLibrary = (UINT_PTR)::GetProcAddress(hKernel, "LoadLibraryW"); // _ASSERTE(gfnLoadLibrary!=NULL); //} //else //{ // _ASSERTE(hKernel!=NULL); // gfnLoadLibrary = NULL; //} if (!GetLoadLibraryAddress()) { _ASSERTE(gfnLoadLibrary!=0); } ghUser32 = GetModuleHandle(user32); if (ghUser32) ghUser32 = LoadLibrary(user32); // если подлинкован - увеличить счетчик WARNING("Попробовать не создавать LocalSecurity при старте"); //#ifndef TESTLINK gpLocalSecurity = LocalSecurity(); //gnMsgActivateCon = RegisterWindowMessage(CONEMUMSG_ACTIVATECON); //#endif //wchar_t szSkipEventName[128]; //msprintf(szSkipEventName, SKIPLEN(countof(szSkipEventName)) CEHOOKDISABLEEVENT, GetCurrentProcessId()); //HANDLE hSkipEvent = OpenEvent(EVENT_ALL_ACCESS , FALSE, szSkipEventName); ////BOOL lbSkipInjects = FALSE; //if (hSkipEvent) //{ // gbSkipInjects = (WaitForSingleObject(hSkipEvent, 0) == WAIT_OBJECT_0); // CloseHandle(hSkipEvent); //} //else //{ // gbSkipInjects = FALSE; //} WARNING("Попробовать не ломиться в мэппинг, а взять все из переменной ConEmuData"); // Открыть мэппинг консоли и попытаться получить HWND GUI, PID сервера, и пр... if (ghConWnd) { print_timings(L"OnConWndChanged"); OnConWndChanged(ghConWnd); //GetConMap(); } if (ghConEmuWnd) { #ifdef SHOW_INJECT_MSGBOX wchar_t* szDbgMsg = (wchar_t*)calloc(1024, sizeof(wchar_t)); wchar_t* szTitle = (wchar_t*)calloc(128, sizeof(wchar_t)); msprintf(szTitle, 1024, L"ConEmuHk, PID=%u", GetCurrentProcessId()); msprintf(szDbgMsg, 128, L"SetAllHooks, ConEmuHk, PID=%u\n%s", GetCurrentProcessId(), szModule); GuiMessageBox(ghConEmuWnd, szDbgMsg, szTitle, MB_SYSTEMMODAL); free(szDbgMsg); free(szTitle); #endif } //if (!gbSkipInjects && ghConWnd) //{ // InitializeConsoleInputSemaphore(); //} print_timings(L"GetImageSubsystem"); // Необходимо определить битность и тип (CUI/GUI) процесса, в который нас загрузили gnImageBits = WIN3264TEST(32,64); gnImageSubsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; // Определим тип (CUI/GUI) GetImageSubsystem(gnImageSubsystem, gnImageBits); // Проверка чего получилось _ASSERTE(gnImageBits==WIN3264TEST(32,64)); _ASSERTE(gnImageSubsystem==IMAGE_SUBSYSTEM_WINDOWS_GUI || gnImageSubsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI); //BOOL lbGuiWindowAttach = FALSE; // Прицепить к ConEmu гуевую программу (notepad, putty, ...) #ifdef USE_PIPE_SERVER _ASSERTEX(gpHookServer==NULL); print_timings(L"gpHookServer"); gpHookServer = (PipeServer<CESERVER_REQ>*)calloc(1,sizeof(*gpHookServer)); if (gpHookServer) { wchar_t szPipeName[128]; msprintf(szPipeName, countof(szPipeName), CEHOOKSPIPENAME, L".", GetCurrentProcessId()); gpHookServer->SetMaxCount(3); gpHookServer->SetOverlapped(true); gpHookServer->SetLoopCommands(false); gpHookServer->SetDummyAnswerSize(sizeof(CESERVER_REQ_HDR)); if (!gpHookServer->StartPipeServer(szPipeName, (LPARAM)gpHookServer, LocalSecurity(), HookServerCommand, HookServerFree, NULL, NULL, HookServerReady)) { _ASSERTEX(FALSE); // Ошибка запуска Pipes? gpHookServer->StopPipeServer(); free(gpHookServer); gpHookServer = NULL; } } else { _ASSERTEX(gpHookServer!=NULL); } #endif WARNING("Попробовать не ломиться в мэппинг, а взять все из переменной ConEmuData"); if (ghConWnd) { print_timings(L"CShellProc"); CShellProc* sp = new CShellProc; if (sp) { if (sp->LoadGuiMapping()) { wchar_t *szExeName = (wchar_t*)calloc((MAX_PATH+1),sizeof(wchar_t)); //BOOL lbDosBoxAllowed = FALSE; if (!GetModuleFileName(NULL, szExeName, MAX_PATH+1)) szExeName[0] = 0; if (sp->GetUseInjects() == 2) { // Можно ли использовать облегченную версию хуков (только для exe-шника)? if (!gbSelfIsRootConsoleProcess && !IsFarExe(szExeName)) { gbHookExecutableOnly = true; } } CESERVER_REQ* pIn = sp->NewCmdOnCreate(eInjectingHooks, L"", szExeName, GetCommandLineW(), NULL, NULL, NULL, NULL, // flags gnImageBits, gnImageSubsystem, GetStdHandle(STD_INPUT_HANDLE), GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_ERROR_HANDLE)); if (pIn) { //HWND hConWnd = GetConsoleWindow(); CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); ExecuteFreeResult(pIn); if (pOut) ExecuteFreeResult(pOut); } free(szExeName); } delete sp; } } else if (gnImageSubsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { print_timings(L"IMAGE_SUBSYSTEM_WINDOWS_GUI"); DWORD dwConEmuHwnd = 0; BOOL bAttachExistingWindow = FALSE; wchar_t szVar[64], *psz; ConEmuGuiMapping* GuiMapping = (ConEmuGuiMapping*)calloc(1,sizeof(*GuiMapping)); if (GuiMapping && LoadGuiMapping(gnSelfPID, *GuiMapping)) { gnGuiPID = GuiMapping->nGuiPID; ghConEmuWnd = GuiMapping->hGuiWnd; bAttachExistingWindow = gbAttachGuiClient = TRUE; //ghAttachGuiClient = } SafeFree(GuiMapping); // Если аттачим существующее окно - таб в ConEmu еще не готов if (!bAttachExistingWindow) { if (!dwConEmuHwnd && GetEnvironmentVariable(ENV_CONEMUHWND_VAR_W, szVar, countof(szVar))) { if (szVar[0] == L'0' && szVar[1] == L'x') { dwConEmuHwnd = wcstoul(szVar+2, &psz, 16); if (!user->isWindow((HWND)dwConEmuHwnd)) dwConEmuHwnd = 0; else if (!user->getClassNameW((HWND)dwConEmuHwnd, szVar, countof(szVar))) dwConEmuHwnd = 0; else if (lstrcmp(szVar, VirtualConsoleClassMain) != 0) dwConEmuHwnd = 0; } } if (dwConEmuHwnd) { // Предварительное уведомление ConEmu GUI, что запущено GUI приложение // и оно может "захотеть во вкладку ConEmu". DWORD nSize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_ATTACHGUIAPP); CESERVER_REQ *pIn = (CESERVER_REQ*)malloc(nSize); ExecutePrepareCmd(pIn, CECMD_ATTACHGUIAPP, nSize); pIn->AttachGuiApp.nPID = GetCurrentProcessId(); GetModuleFileName(NULL, pIn->AttachGuiApp.sAppFileName, countof(pIn->AttachGuiApp.sAppFileName)); pIn->AttachGuiApp.hkl = (DWORD)(LONG)(LONG_PTR)GetKeyboardLayout(0); wchar_t szGuiPipeName[128]; msprintf(szGuiPipeName, countof(szGuiPipeName), CEGUIPIPENAME, L".", dwConEmuHwnd); CESERVER_REQ* pOut = ExecuteCmd(szGuiPipeName, pIn, 10000, NULL); free(pIn); if (pOut) { if (pOut->hdr.cbSize > sizeof(CESERVER_REQ_HDR)) { if (pOut->AttachGuiApp.nFlags & agaf_Success) { user->allowSetForegroundWindow(pOut->hdr.nSrcPID); // PID ConEmu. _ASSERTEX(gnGuiPID==0 || gnGuiPID==pOut->hdr.nSrcPID); gnGuiPID = pOut->hdr.nSrcPID; //ghConEmuWnd = (HWND)dwConEmuHwnd; _ASSERTE(ghConEmuWnd==NULL || gnGuiPID!=0); _ASSERTE(pOut->AttachGuiApp.hConEmuWnd==(HWND)dwConEmuHwnd); ghConEmuWnd = pOut->AttachGuiApp.hConEmuWnd; ghConEmuWndDC = pOut->AttachGuiApp.hConEmuWndDC; ghConWnd = pOut->AttachGuiApp.hSrvConWnd; _ASSERTE(ghConEmuWndDC && user->isWindow(ghConEmuWndDC)); grcConEmuClient = pOut->AttachGuiApp.rcWindow; gnServerPID = pOut->AttachGuiApp.nPID; if (pOut->AttachGuiApp.hkl) { LONG_PTR hkl = (LONG_PTR)(LONG)pOut->AttachGuiApp.hkl; BOOL lbRc = ActivateKeyboardLayout((HKL)hkl, KLF_SETFORPROCESS) != NULL; UNREFERENCED_PARAMETER(lbRc); } OnConWndChanged(ghConWnd); gbAttachGuiClient = TRUE; } } ExecuteFreeResult(pOut); } } } } //if (!gbSkipInjects) { //gnRunMode = RM_APPLICATION; #ifdef _DEBUG //wchar_t szModule[MAX_PATH+1]; szModule[0] = 0; //GetModuleFileName(NULL, szModule, countof(szModule)); _ASSERTE((gnImageSubsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI) || (lstrcmpi(pszName, L"DosBox.exe")==0) || gbAttachGuiClient); //if (!lstrcmpi(pszName, L"far.exe") || !lstrcmpi(pszName, L"mingw32-make.exe")) //if (!lstrcmpi(pszName, L"as.exe")) // MessageBoxW(NULL, L"as.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //else if (!lstrcmpi(pszName, L"cc1plus.exe")) // MessageBoxW(NULL, L"cc1plus.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //else if (!lstrcmpi(pszName, L"mingw32-make.exe")) // MessageBoxW(NULL, L"mingw32-make.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //if (!lstrcmpi(pszName, L"g++.exe")) // MessageBoxW(NULL, L"g++.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //{ #endif print_timings(L"StartupHooks"); gbHooksWasSet = StartupHooks(ghOurModule); print_timings(L"StartupHooks - done"); #ifdef _DEBUG //} #endif // Если NULL - значит это "Detached" консольный процесс, посылать "Started" в сервер смысла нет if (ghConWnd != NULL) { print_timings(L"SendStarted"); SendStarted(); //#ifdef _DEBUG //// Здесь это приводит к обвалу _chkstk, //// похоже из-за того, что dll-ка загружена НЕ из известных модулей, //// а из специально сформированного блока памяти // -- в одной из функций, под локальные переменные выделялось слишком много памяти // -- переделал в malloc/free, все заработало //TestShellProcessor(); //#endif } } //else //{ // gbHooksWasSet = FALSE; //} //delete sp; /* #ifdef _DEBUG if (!lstrcmpi(pszName, L"mingw32-make.exe")) GuiMessageBox(ghConEmuWnd, L"mingw32-make.exe DllMain finished", L"ConEmuHk", MB_SYSTEMMODAL); #endif */ SafeFree(szModule); //if (hStartedEvent) // SetEvent(hStartedEvent); print_timings(L"DllStart - done"); return 0; }
// Проверка окна переднего плана. Если оно принадлежит к хукаемым процесса - вставить хук. // ДИАЛОГИ НЕ ПРОВЕРЯЮТСЯ bool CDefaultTerminal::CheckForeground(HWND hFore, DWORD nForePID, bool bRunInThread /*= true*/) { if (!isDefaultTerminalAllowed()) return false; bool lbRc = false; bool lbLocked = false; DWORD nResult = 0; wchar_t szClass[MAX_PATH]; szClass[0] = 0; PROCESSENTRY32 prc; bool bMonitored = false; const wchar_t* pszMonitored = NULL; HANDLE hProcess = NULL; int nBits = 0; wchar_t szCmdLine[MAX_PATH*3]; wchar_t szName[64]; PROCESS_INFORMATION pi = {}; STARTUPINFO si = {sizeof(si)}; BOOL bStarted = FALSE; // Если главное окно еще не создано if (!mb_ReadyToHook) { // Сразу выходим goto wrap; } //_ASSERTE(gpConEmu->isMainThread()); if (!hFore || !nForePID) { _ASSERTE(hFore && nForePID); goto wrap; } if (hFore == mh_LastWnd || hFore == mh_LastIgnoredWnd) { // Это окно уже проверялось lbRc = (hFore == mh_LastWnd); goto wrap; } if (bRunInThread && (hFore == mh_LastCall)) { // Просто выйти. Это проверка на частые фоновые вызовы. goto wrap; } mh_LastCall = hFore; if (bRunInThread) { if (gpConEmu->isMainThread()) { // Clear finished threads ClearThreads(false); } HANDLE hPostThread = NULL; DWORD nThreadId = 0; ThreadArg* pArg = (ThreadArg*)malloc(sizeof(ThreadArg)); if (!pArg) { _ASSERTE(pArg); goto wrap; } pArg->pTerm = this; pArg->hFore = hFore; pArg->nForePID = nForePID; hPostThread = CreateThread(NULL, 0, PostCheckThread, pArg, 0, &nThreadId); _ASSERTE(hPostThread!=NULL); if (hPostThread) { m_Threads.push_back(hPostThread); } lbRc = (hPostThread != NULL); // вернуть OK? goto wrap; } EnterCriticalSection(&mcs); lbLocked = true; // Clear dead processes and windows ClearProcessed(false); // Check window class if (GetClassName(hFore, szClass, countof(szClass))) { if ((lstrcmp(szClass, VirtualConsoleClass) == 0) //|| (lstrcmp(szClass, L"#32770") == 0) // Ignore dialogs // -- Process dialogs too (Application may be dialog-based) || isConsoleClass(szClass)) { mh_LastIgnoredWnd = hFore; goto wrap; } } // Go and check if (!GetProcessInfo(nForePID, &prc)) { mh_LastIgnoredWnd = hFore; goto wrap; } CharLowerBuff(prc.szExeFile, lstrlen(prc.szExeFile)); if (lstrcmp(prc.szExeFile, L"csrss.exe") == 0) { // This is "System" process and may not be hooked mh_LastIgnoredWnd = hFore; goto wrap; } // Is it in monitored applications? pszMonitored = gpSet->GetDefaultTerminalAppsMSZ(); if (pszMonitored) { // All strings are lower case const wchar_t* psz = pszMonitored; while (*psz) { if (_tcscmp(psz, prc.szExeFile) == 0) { bMonitored = true; break; } psz += _tcslen(psz)+1; } } // And how it is? if (!bMonitored) { mh_LastIgnoredWnd = hFore; goto wrap; } // Need to process for (INT_PTR i = m_Processed.size(); i--;) { if (m_Processed[i].nPID == nForePID) { bMonitored = false; break; // already hooked } } // May be hooked already? if (!bMonitored) { mh_LastWnd = hFore; lbRc = true; goto wrap; } _ASSERTE(isDefaultTerminalAllowed()); hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|SYNCHRONIZE, FALSE, nForePID); if (!hProcess) { // Failed to hook mh_LastIgnoredWnd = hFore; goto wrap; } // Need to be hooked nBits = GetProcessBits(nForePID, hProcess); switch (nBits) { case 32: _wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\\%s\" /DEFTRM=%u", gpConEmu->ms_ConEmuBaseDir, L"ConEmuC.exe", nForePID); break; case 64: _wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\\%s\" /DEFTRM=%u", gpConEmu->ms_ConEmuBaseDir, L"ConEmuC64.exe", nForePID); break; } if (!*szCmdLine) { // Unsupported bitness? CloseHandle(hProcess); mh_LastIgnoredWnd = hFore; goto wrap; } // Prepare event _wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOK, nForePID); SafeCloseHandle(mh_SignEvent); mh_SignEvent = CreateEvent(LocalSecurity(), FALSE, FALSE, szName); if (mh_SignEvent) SetEvent(mh_SignEvent); // May be excess, but if event already exists... // Run hooker si.dwFlags = STARTF_USESHOWWINDOW; bStarted = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (!bStarted) { DisplayLastError(L"Failed to start hooking application!\nDefault terminal feature will not be available!"); CloseHandle(hProcess); mh_LastIgnoredWnd = hFore; goto wrap; } CloseHandle(pi.hThread); // Waiting for result TODO("Show status in status line?"); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &nResult); CloseHandle(pi.hProcess); // And what? if (nResult == (UINT)CERR_HOOKS_WAS_SET) { mh_LastWnd = hFore; ProcessInfo inf = {}; inf.hProcess = hProcess; hProcess = NULL; // его закрывать НЕ нужно, сохранен в массиве inf.nPID = nForePID; inf.nHookTick = GetTickCount(); m_Processed.push_back(inf); lbRc = true; goto wrap; } // Failed, remember this CloseHandle(hProcess); mh_LastIgnoredWnd = hFore; _ASSERTE(lbRc == false); wrap: if (lbLocked) { LeaveCriticalSection(&mcs); } return lbRc; }