int ComspecInit() { TODO("Определить код родительского процесса, и если это FAR - запомнить его (для подключения к пайпу плагина)"); TODO("Размер получить из GUI, если оно есть, иначе - по умолчанию"); TODO("GUI может скорректировать размер с учетом полосы прокрутки"); WARNING("CreateFile(CONOUT$) по идее возвращает текущий ScreenBuffer. Можно его самим возвращать в ComspecDone"); // Правда нужно проверить, что там происходит с ghConOut.Close(),... // Размер должен менять сам GUI, через серверный ConEmuC! #ifdef SHOW_STARTED_MSGBOX MessageBox(GetConEmuHWND(2), L"ConEmuC (comspec mode) is about to START", L"ConEmuC.ComSpec", 0); #endif //int nNewBufferHeight = 0; //COORD crNewSize = {0,0}; //SMALL_RECT rNewWindow = gpSrv->sbi.srWindow; BOOL lbSbiRc = FALSE; gbRootWasFoundInCon = 2; // не добавлять к "Press Enter to close console" - "or wait" gbComspecInitCalled = TRUE; // Нельзя вызывать ComspecDone, если не было вызова ComspecInit // в режиме ComSpec - запрещено! gbAlwaysConfirmExit = FALSE; gbAutoDisableConfirmExit = FALSE; #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif // Это наверное и не нужно, просто для информации... lbSbiRc = GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &gpSrv->sbi); #ifdef _DEBUG DWORD nErrCode = lbSbiRc ? 0 : GetLastError(); // Процесс запущен с редиректом вывода? _ASSERTE(lbSbiRc || (nErrCode == ERROR_INVALID_HANDLE)); #endif #if 0 // 111211 - "-new_console" теперь передается в GUI и исполняется в нем // Сюда мы попадаем если был ключик -new_console // А этом случае нужно завершить ЭТОТ экземпляр и запустить в ConEmu новую вкладку if (gpSrv->bNewConsole) { #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USECOUNTCHARS; si.dwXCountChars = gpSrv->sbi.dwSize.X; si.dwYCountChars = gpSrv->sbi.dwSize.Y; si.wShowWindow = SW_HIDE; PRINT_COMSPEC(L"Creating new console for:\n%s\n", gpszRunCmd); #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif // CREATE_NEW_PROCESS_GROUP - низя, перестает работать Ctrl-C // Запускается новый сервер (новая консоль), сюда хуки ставить не надо. BOOL lbRc = createProcess(TRUE, NULL, gpszRunCmd, NULL,NULL, TRUE, NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); DWORD dwErr = GetLastError(); if (!lbRc) { PrintExecuteError(gpszRunCmd, dwErr); return CERR_CREATEPROCESS; } #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif //delete psNewCmd; psNewCmd = NULL; AllowSetForegroundWindow(pi.dwProcessId); PRINT_COMSPEC(L"New console created. PID=%i. Exiting...\n", pi.dwProcessId); SafeCloseHandle(pi.hProcess); SafeCloseHandle(pi.hThread); DisableAutoConfirmExit(); //gpSrv->nProcessStartTick = GetTickCount() - 2*CHECK_ROOTSTART_TIMEOUT; // менять nProcessStartTick не нужно. проверка только по флажкам #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif return CERR_RUNNEWCONSOLE; } #endif // Если определена ComSpecC - значит ConEmuC переопределил стандартный ComSpec // Вернем его wchar_t szComSpec[MAX_PATH+1]; const wchar_t* pszComSpecName; //110202 - comspec более не переопределяется //if (GetEnvironmentVariable(L"ComSpecC", szComSpec, MAX_PATH) && szComSpec[0] != 0) WARNING("TCC/ComSpec"); if (GetEnvironmentVariable(L"ComSpec", szComSpec, MAX_PATH) && szComSpec[0] != 0) { //// Только если это (случайно) не conemuc.exe //wchar_t* pwszCopy = (wchar_t*)PointToName(szComSpec); //wcsrchr(szComSpec, L'\\'); ////if (!pwszCopy) pwszCopy = szComSpec; //#pragma warning( push ) //#pragma warning(disable : 6400) //if (lstrcmpiW(pwszCopy, L"ConEmuC")==0 || lstrcmpiW(pwszCopy, L"ConEmuC.exe")==0 // /*|| lstrcmpiW(pwszCopy, L"ConEmuC64")==0 || lstrcmpiW(pwszCopy, L"ConEmuC64.exe")==0*/) // szComSpec[0] = 0; //#pragma warning( pop ) //if (szComSpec[0]) //{ // SetEnvironmentVariable(L"ComSpec", szComSpec); // SetEnvironmentVariable(L"ComSpecC", NULL); //} pszComSpecName = (wchar_t*)PointToName(szComSpec); } else { WARNING("TCC/ComSpec"); pszComSpecName = L"cmd.exe"; } lstrcpyn(gpSrv->szComSpecName, pszComSpecName, countof(gpSrv->szComSpecName)); if (pszComSpecName) { wchar_t szSelf[MAX_PATH+1]; if (GetModuleFileName(NULL, szSelf, MAX_PATH)) { lstrcpyn(gpSrv->szSelfName, (wchar_t*)PointToName(szSelf), countof(gpSrv->szSelfName)); if (!GetAliases(gpSrv->szSelfName, &gpSrv->pszPreAliases, &gpSrv->nPreAliasSize)) { if (gpSrv->pszPreAliases) { _wprintf(gpSrv->pszPreAliases); free(gpSrv->pszPreAliases); gpSrv->pszPreAliases = NULL; } } } } SendStarted(); //ConOutCloseHandle() return 0; }
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; }