bool isConsoleWindow(HWND hWnd) { wchar_t szClass[64] = L""; if (!hWnd) return false; if (!GetClassName(hWnd, szClass, countof(szClass))) return false; if (!isConsoleClass(szClass)) return false; // But when process is hooked, GetConsoleClass will return "proper" name // even if hWnd points to our VirtualConsole // RealConsole handle is stored in the Window DATA wchar_t szClassPtr[64] = L""; HWND h = (HWND)GetWindowLongPtr(hWnd, 0); if (h && (h != hWnd) && IsWindow(h)) { if (GetClassName(h, szClassPtr, countof(szClassPtr))) { if (isConsoleClass(szClassPtr)) { _ASSERTE(FALSE && "RealConsole handle was not retrieved properly!"); return false; } } } // Well, it's a RealConsole return true; }
void OnConWndChanged(HWND ahNewConWnd) { //BOOL lbForceReopen = FALSE; if (ahNewConWnd) { #ifdef _DEBUG if (user) { wchar_t sClass[64]; user->getClassNameW(ahNewConWnd, sClass, countof(sClass)); _ASSERTEX(isConsoleClass(sClass)); } #endif if (ghConWnd != ahNewConWnd) { ghConWnd = ahNewConWnd; //lbForceReopen = TRUE; } } else { //lbForceReopen = TRUE; } GetConMap(TRUE); }
// GetConsoleWindow хукается, поэтому, для получения реального консольного окна // можно дергать эту экспортируемую функцию HWND WINAPI GetRealConsoleWindow() { _ASSERTE(gfGetRealConsoleWindow); HWND hConWnd = gfGetRealConsoleWindow ? gfGetRealConsoleWindow() : NULL; //GetConsoleWindow(); #ifdef _DEBUG wchar_t sClass[64]; user->getClassNameW(hConWnd, sClass, countof(sClass)); _ASSERTEX(hConWnd==NULL || isConsoleClass(sClass)); #endif return hConWnd; }
bool CAttachDlg::CanAttachWindow(HWND hFind, DWORD nSkipPID, CProcessData* apProcessData, CAttachDlg::AttachWndInfo& Info) { static bool bIsWin64 = IsWindows64(); ZeroStruct(Info); DWORD_PTR nStyle = GetWindowLongPtr(hFind, GWL_STYLE); DWORD_PTR nStyleEx = GetWindowLongPtr(hFind, GWL_EXSTYLE); if (!GetWindowThreadProcessId(hFind, &Info.nPID)) Info.nPID = 0; if (!Info.nPID) return false; bool lbCan = ((nStyle & (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/)) == (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/)); if (lbCan) { // Более тщательно стили проверить lbCan = ((nStyle & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) || ((nStyle & WS_THICKFRAME) == WS_THICKFRAME); } if (lbCan && Info.nPID == GetCurrentProcessId()) lbCan = false; if (lbCan && Info.nPID == nSkipPID) lbCan = false; if (lbCan && (nStyle & WS_CHILD)) lbCan = false; if (lbCan && (nStyleEx & WS_EX_TOOLWINDOW)) lbCan = false; if (lbCan && gpConEmu->isOurConsoleWindow(hFind)) lbCan = false; if (lbCan && gpConEmu->mp_Inside && (hFind == gpConEmu->mp_Inside->mh_InsideParentRoot)) lbCan = false; GetClassName(hFind, Info.szClass, countof(Info.szClass)); GetWindowText(hFind, Info.szTitle, countof(Info.szTitle)); if (gpSetCls->isAdvLogging) { wchar_t szLogInfo[MAX_PATH*3]; _wsprintf(szLogInfo, SKIPLEN(countof(szLogInfo)) L"Attach:%s x%08X/x%08X/x%08X {%s} \"%s\"", Info.szExeName, LODWORD(hFind), nStyle, nStyleEx, Info.szClass, Info.szTitle); CVConGroup::LogString(szLogInfo); } if (!lbCan) return false; _wsprintf(Info.szPid, SKIPLEN(countof(Info.szPid)) L"%u", Info.nPID); const wchar_t sz32bit[] = L" [32]"; const wchar_t sz64bit[] = L" [64]"; HANDLE h; DEBUGTEST(DWORD nErr); bool lbExeFound = false; if (apProcessData) { lbExeFound = apProcessData->GetProcessName(Info.nPID, Info.szExeName, countof(Info.szExeName), Info.szExePathName, countof(Info.szExePathName), &Info.nImageBits); if (lbExeFound) { //ListView_SetItemText(hList, nItem, alc_File, szExeName); //ListView_SetItemText(hList, nItem, alc_Path, szExePathName); if (bIsWin64 && Info.nImageBits) { wcscat_c(Info.szPid, (Info.nImageBits == 64) ? sz64bit : sz32bit); } } } if (!lbExeFound) { Info.nImageBits = GetProcessBits(Info.nPID); if (bIsWin64 && Info.nImageBits) { wcscat_c(Info.szPid, (Info.nImageBits == 64) ? sz64bit : sz32bit); } h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, Info.nPID); if (h && h != INVALID_HANDLE_VALUE) { MODULEENTRY32 mi = {sizeof(mi)}; if (Module32First(h, &mi)) { lstrcpyn(Info.szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(Info.szExeName)); lstrcpyn(Info.szExePathName, mi.szExePath, countof(Info.szExePathName)); lbExeFound = true; } else { if (bIsWin64) { wcscat_c(Info.szPid, sz64bit); } } CloseHandle(h); } else { #ifdef _DEBUG nErr = GetLastError(); _ASSERTE(nErr == 5 || (nErr == 299 && Info.nImageBits == 64)); #endif wcscpy_c(Info.szExeName, L"???"); } #if 0 //#ifdef _WIN64 -- no need to call TH32CS_SNAPMODULE32, simple TH32CS_SNAPMODULE will handle both if it can if (!lbExeFound) { h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, Info.nPID); if (h && h != INVALID_HANDLE_VALUE) { MODULEENTRY32 mi = {sizeof(mi)}; if (Module32First(h, &mi)) { //ListView_SetItemText(hList, nItem, alc_File, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath)); lstrcpyn(Info.szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(Info.szExeName)); //ListView_SetItemText(hList, nItem, alc_Path, mi.szExePath); lstrcpyn(Info.szExePathName, mi.szExePath, countof(Info.szExePathName)); } CloseHandle(h); } } #endif } if (!lbExeFound) { // Так можно получить только имя файла процесса PROCESSENTRY32 pi = {sizeof(pi)}; h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (h && h != INVALID_HANDLE_VALUE) { if (Process32First(h, &pi)) { do { if (pi.th32ProcessID == Info.nPID) { lstrcpyn(Info.szExeName, pi.szExeFile, countof(Info.szExeName)); break; } } while (Process32Next(h, &pi)); } } } wcscpy_c(Info.szType, isConsoleClass(Info.szClass) ? szTypeCon : szTypeGui); return true; }
// Проверка окна переднего плана. Если оно принадлежит к хукаемым процесса - вставить хук. bool CDefaultTerminal::CheckForeground(HWND hFore, DWORD nForePID, bool bRunInThread /*= true*/) { if (!isDefaultTerminalAllowed()) return false; bool lbRc = false; bool lbLocked = false; bool lbConHostLocked; 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; DWORD nErrCode = 0; int iHookerRc = -1; // Если главное окно еще не создано 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()); TODO("Show status in status line?"); lbConHostLocked = gpConEmu->LockConhostStart(); iHookerRc = StartDefTermHooker(nForePID, hProcess, nResult, gpConEmu->ms_ConEmuBaseDir, nErrCode); if (lbConHostLocked) gpConEmu->UnlockConhostStart(); if (iHookerRc != 0) { mh_LastIgnoredWnd = hFore; if (iHookerRc == -3) DisplayLastError(L"Failed to start hooking application!\nDefault terminal feature will not be available!", nErrCode); goto wrap; } //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 //WaitForSingleObject(pi.hProcess, INFINITE); //GetExitCodeProcess(pi.hProcess, &nResult); //CloseHandle(pi.hProcess); // And what? if ((nResult == (UINT)CERR_HOOKS_WAS_SET) || (nResult == (UINT)CERR_HOOKS_WAS_ALREADY_SET)) { mh_LastWnd = hFore; ProcessInfo inf = {}; inf.hProcess = hProcess; hProcess = NULL; // его закрывать НЕ нужно, сохранен в массиве inf.nPID = nForePID; //inf.bHooksSucceeded = (nResult == (UINT)CERR_HOOKS_WAS_ALREADY_SET); 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; }
HWND myGetConsoleWindow() { HWND hConWnd = NULL; static HMODULE hHookLib = NULL; if (!hHookLib) hHookLib = GetModuleHandle(WIN3264TEST(L"ConEmuHk.dll",L"ConEmuHk64.dll")); if (hHookLib) { typedef HWND (WINAPI* GetRealConsoleWindow_t)(); static GetRealConsoleWindow_t GetRealConsoleWindow_f = NULL; if (!GetRealConsoleWindow_f) GetRealConsoleWindow_f = (GetRealConsoleWindow_t)GetProcAddress(hHookLib, "GetRealConsoleWindow"); if (GetRealConsoleWindow_f) { hConWnd = GetRealConsoleWindow_f(); } else { _ASSERTE(GetRealConsoleWindow_f!=NULL); } } if (!hConWnd) { hConWnd = GetConsoleWindow(); // Это может быть GUI приложение if (!hConWnd) return NULL; } #ifdef _DEBUG // Избежать статической линковки для user32.dll HMODULE hUser32 = GetModuleHandle(L"user32.dll"); if (!hUser32) { // Скорее всего, user32 уже должен быть загружен, но если вдруг - сильно // плохо, если он будет вызываться из DllMain _ASSERTE(hUser32!=NULL); hUser32 = LoadLibrary(L"user32.dll"); } typedef LONG_PTR (WINAPI* GetWindowLongPtr_t)(HWND,int); GetWindowLongPtr_t GetWindowLongPtr_f = (GetWindowLongPtr_t)GetProcAddress(hUser32,WIN3264TEST("GetWindowLongW","GetWindowLongPtrW")); typedef int (WINAPI* GetClassName_t)(HWND hWnd,LPWSTR lpClassName,int nMaxCount); GetClassName_t GetClassName_f = (GetClassName_t)GetProcAddress(hUser32,"GetClassNameW"); typedef LONG_PTR (WINAPI* IsWindow_t)(HWND); IsWindow_t IsWindow_f = (IsWindow_t)GetProcAddress(hUser32,"IsWindow"); if (!(GetClassName_f && GetWindowLongPtr_f && IsWindow_f)) { _ASSERTE(GetClassName_f && GetWindowLongPtr_f); } else { wchar_t sClass[64]; if (hConWnd) GetClassName_f(hConWnd, sClass, countof(sClass)); _ASSERTE(hConWnd==NULL || isConsoleClass(sClass)); #if 0 if (lstrcmp(sClass, VirtualConsoleClass) == 0) { // в данных окна DC - хранится хэндл окна консоли HWND h = (HWND)GetWindowLongPtr_f(hConWnd, 0); if (h && IsWindow_f(h)) { hConWnd = h; } else { _ASSERTE(h && IsWindow_f(h)); } } #endif } #endif return hConWnd; #if 0 // Смысла звать GetProcAddress для "GetConsoleWindow" мало, все равно хукается typedef HWND (APIENTRY *FGetConsoleWindow)(); static FGetConsoleWindow fGetConsoleWindow = NULL; if (!fGetConsoleWindow) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); if (hKernel32) { fGetConsoleWindow = (FGetConsoleWindow)GetProcAddress(hKernel32, "GetConsoleWindow"); } } if (fGetConsoleWindow) hConWnd = fGetConsoleWindow(); return hConWnd; #endif }
BOOL CAttachDlg::AttachDlgEnumWin(HWND hFind, LPARAM lParam) { if (IsWindowVisible(hFind)) { CAttachDlg* pDlg = (CAttachDlg*)lParam; // Условия? DWORD_PTR nStyle = GetWindowLongPtr(hFind, GWL_STYLE); DWORD_PTR nStyleEx = GetWindowLongPtr(hFind, GWL_EXSTYLE); DWORD nPID; if (!GetWindowThreadProcessId(hFind, &nPID)) nPID = 0; bool lbCan = ((nStyle & (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/)) == (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/)); if (lbCan) { // Более тщательно стили проверить lbCan = ((nStyle & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) || ((nStyle & WS_THICKFRAME) == WS_THICKFRAME); } if (lbCan && nPID == GetCurrentProcessId()) lbCan = false; if (lbCan && nPID == pDlg->mn_ExplorerPID) lbCan = false; if (lbCan && (nStyle & WS_CHILD)) lbCan = false; if (lbCan && (nStyleEx & WS_EX_TOOLWINDOW)) lbCan = false; if (lbCan && gpConEmu->isOurConsoleWindow(hFind)) lbCan = false; if (lbCan && gpConEmu->mp_Inside && (hFind == gpConEmu->mp_Inside->mh_InsideParentRoot)) lbCan = false; wchar_t szClass[MAX_PATH], szTitle[MAX_PATH]; GetClassName(hFind, szClass, countof(szClass)); GetWindowText(hFind, szTitle, countof(szTitle)); if (gpSetCls->isAdvLogging) { wchar_t szLogInfo[MAX_PATH*3]; _wsprintf(szLogInfo, SKIPLEN(countof(szLogInfo)) L"Attach:%s x%08X/x%08X/x%08X {%s} \"%s\"", (DWORD)hFind, nStyle, nStyleEx, szClass, szTitle); CVConGroup::LogString(szLogInfo); } if (lbCan) { wchar_t szPid[32], szHwnd[32], szType[16]; szPid[0] = szHwnd[0] = szType[0] = 0; wchar_t szExeName[MAX_PATH], szExePathName[MAX_PATH*4]; szExeName[0] = szExePathName[0] = 0; #ifndef ALLOW_GUI_ATTACH if (!isConsoleClass(szClass)) return TRUE; #endif HWND hList = pDlg->mh_List; if (nPID) { _wsprintf(szPid, SKIPLEN(countof(szPid)) L"%u", nPID); } else { #ifdef _DEBUG wcscpy_c(szPid, L"????"); #else return TRUE; #endif } HANDLE h; bool lbExeFound = false; int nImageBits = 32; #if 0 // Так можно получить только имя файла процесса, а интересен еще и путь PROCESSENTRY32 pi = {sizeof(pi)}; h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (h && h != INVALID_HANDLE_VALUE) { if (Process32First(h, &pi)) { while (pi.th32ProcessID != nPID) { if (!Process32Next(h, &pi)) pi.th32ProcessID = 0; } } } #endif if (pDlg->mp_ProcessData) { lbExeFound = pDlg->mp_ProcessData->GetProcessName(nPID, szExeName, countof(szExeName), szExePathName, countof(szExePathName), &nImageBits); if (lbExeFound) { //ListView_SetItemText(hList, nItem, alc_File, szExeName); //ListView_SetItemText(hList, nItem, alc_Path, szExePathName); if (pDlg->mb_IsWin64) { wcscat_c(szPid, (nImageBits == 64) ? L" *64" : L" *32"); } } } if (!lbExeFound) { h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, nPID); if (h && h != INVALID_HANDLE_VALUE) { MODULEENTRY32 mi = {sizeof(mi)}; if (Module32First(h, &mi)) { //ListView_SetItemText(hList, nItem, alc_File, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath)); lstrcpyn(szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(szExeName)); //ListView_SetItemText(hList, nItem, alc_Path, mi.szExePath); lstrcpyn(szExePathName, mi.szExePath, countof(szExePathName)); if (pDlg->mb_IsWin64) { wcscat_c(szPid, WIN3264TEST(L" *32",L" *64")); } lbExeFound = true; } else { if (pDlg->mb_IsWin64) { wcscat_c(szPid, L" *64"); } } CloseHandle(h); } #ifdef _WIN64 if (!lbExeFound) { h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, nPID); if (h && h != INVALID_HANDLE_VALUE) { MODULEENTRY32 mi = {sizeof(mi)}; if (Module32First(h, &mi)) { //ListView_SetItemText(hList, nItem, alc_File, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath)); lstrcpyn(szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(szExeName)); //ListView_SetItemText(hList, nItem, alc_Path, mi.szExePath); lstrcpyn(szExePathName, mi.szExePath, countof(szExePathName)); wcscat_c(szPid, L" *32"); } CloseHandle(h); } } #endif } LVITEM lvi = {LVIF_TEXT|LVIF_STATE}; lvi.state = 0; lvi.stateMask = LVIS_SELECTED|LVIS_FOCUSED; lvi.pszText = szPid; lvi.iItem = ListView_GetItemCount(hList); // в конец int nItem = ListView_InsertItem(hList, &lvi); ListView_SetItemState(hList, nItem, 0, LVIS_SELECTED|LVIS_FOCUSED); ListView_SetItemText(hList, nItem, alc_Title, szTitle); ListView_SetItemText(hList, nItem, alc_Class, szClass); _wsprintf(szHwnd, SKIPLEN(countof(szHwnd)) L"0x%08X", (DWORD)(((DWORD_PTR)hFind) & (DWORD)-1)); ListView_SetItemText(hList, nItem, alc_HWND, szHwnd); wcscpy_c(szType, isConsoleClass(szClass) ? szTypeCon : szTypeGui); ListView_SetItemText(hList, nItem, alc_File, szExeName); ListView_SetItemText(hList, nItem, alc_Path, szExePathName); ListView_SetItemText(hList, nItem, alc_Type, szType); } } return TRUE; // Продолжить }