DWORD WINAPI MyAssertThread(LPVOID p) { if (gbInMyAssertTrap) { // Если уже в трапе - то повторно не вызывать, иначе может вывалиться серия окон, что затруднит отладку return IDCANCEL; } MyAssertInfo* pa = (MyAssertInfo*)p; if (ghInMyAssertTrap == NULL) { ghInMyAssertTrap = CreateEvent(NULL, TRUE, FALSE, NULL); } gnInMyAssertThread = GetCurrentThreadId(); if (ghInMyAssertTrap) ResetEvent(ghInMyAssertTrap); gbInMyAssertTrap = true; DWORD nRc = #ifdef CONEMU_MINIMAL GuiMessageBox(ghConEmuWnd, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); #else MessageBoxW(NULL, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); #endif gbInMyAssertTrap = false; if (ghInMyAssertTrap) SetEvent(ghInMyAssertTrap); gnInMyAssertThread = 0; return nRc; }
HANDLE WINAPI OnCreateConsoleScreenBuffer(DWORD dwDesiredAccess, DWORD dwShareMode, const SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwFlags, LPVOID lpScreenBufferData) { //typedef HANDLE(WINAPI* OnCreateConsoleScreenBuffer_t)(DWORD dwDesiredAccess, DWORD dwShareMode, const SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwFlags, LPVOID lpScreenBufferData); ORIGINALFAST(CreateConsoleScreenBuffer); #ifdef SHOWCREATEBUFFERINFO wchar_t szDebugInfo[255]; msprintf(szDebugInfo, countof(szDebugInfo), L"CreateConsoleScreenBuffer(0x%X,0x%X,0x%X,0x%X,0x%X)", dwDesiredAccess, dwShareMode, (DWORD)(DWORD_PTR)lpSecurityAttributes, dwFlags, (DWORD)(DWORD_PTR)lpScreenBufferData); #endif if ((dwShareMode & (FILE_SHARE_READ|FILE_SHARE_WRITE)) != (FILE_SHARE_READ|FILE_SHARE_WRITE)) dwShareMode |= (FILE_SHARE_READ|FILE_SHARE_WRITE); if ((dwDesiredAccess & (GENERIC_READ|GENERIC_WRITE)) != (GENERIC_READ|GENERIC_WRITE)) dwDesiredAccess |= (GENERIC_READ|GENERIC_WRITE); if (!ghStdOutHandle) ghStdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE h = INVALID_HANDLE_VALUE; if (F(CreateConsoleScreenBuffer)) h = F(CreateConsoleScreenBuffer)(dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlags, lpScreenBufferData); #ifdef SHOWCREATEBUFFERINFO msprintf(szDebugInfo+lstrlen(szDebugInfo), 32, L"=0x%X", (DWORD)(DWORD_PTR)h); GuiMessageBox(ghConEmuWnd, szDebugInfo, L"ConEmuHk", MB_SETFOREGROUND|MB_SYSTEMMODAL); #endif return h; }
DWORD WINAPI MyAssertThread(LPVOID p) { if (gnInMyAssertTrap > 0) { // Если уже в трапе - то повторно не вызывать, иначе может вывалиться серия окон, что затруднит отладку return IDCANCEL; } MyAssertInfo* pa = (MyAssertInfo*)p; if (ghInMyAssertTrap == NULL) { ghInMyAssertTrap = CreateEvent(NULL, TRUE, FALSE, NULL); } gnInMyAssertThread = GetCurrentThreadId(); if (ghInMyAssertTrap) ResetEvent(ghInMyAssertTrap); InterlockedIncrement(&gnInMyAssertTrap); DWORD nRc = #if defined(CONEMU_MINIMAL) && defined(ASSERT_PIPE_ALLOWED) GuiMessageBox(ghConEmuWnd, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); #else AssertMsgBox ? AssertMsgBox(pa->szDebugInfo, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL, pa->szTitle, NULL, false) : MessageBox(NULL, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); #endif InterlockedDecrement(&gnInMyAssertTrap); if (ghInMyAssertTrap) SetEvent(ghInMyAssertTrap); gnInMyAssertThread = 0; return nRc; }
LONG WINAPI HkExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) { wchar_t szTitle[128], szText[MAX_PATH*2]; szText[0] = 0; msprintf(szTitle, countof(szTitle), L"Exception, PID=%u", GetCurrentProcessId(), GetCurrentThreadId()); GetModuleFileName(NULL, szText, countof(szText)); int nBtn = GuiMessageBox(ghConEmuWnd, szText, szTitle, MB_RETRYCANCEL|MB_SYSTEMMODAL); return (nBtn == IDRETRY) ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER; }
int MyAssertProc(const wchar_t* pszFile, int nLine, const wchar_t* pszTest, bool abNoPipe) { #ifdef _DEBUG bool lbSkip = false; if (lbSkip) return 1; #endif HANDLE hHeap = GetProcessHeap(); MyAssertInfo* pa = (MyAssertInfo*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(MyAssertInfo)); wchar_t *szExeName = (wchar_t*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, (MAX_PATH+1)*sizeof(wchar_t)); if (!GetModuleFileNameW(NULL, szExeName, MAX_PATH+1)) szExeName[0] = 0; pa->bNoPipe = abNoPipe; msprintf(pa->szTitle, countof(pa->szTitle), L"CEAssert PID=%u TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); msprintf(pa->szDebugInfo, countof(pa->szDebugInfo), L"Assertion in %s\n%s\n\n%s: %i\n\nPress 'Retry' to trap.", szExeName, pszTest ? pszTest : L"", pszFile, nLine); DWORD dwCode = 0; if (gAllowAssertThread == am_Thread) { DWORD dwTID; HANDLE hThread = CreateThread(NULL, 0, MyAssertThread, pa, 0, &dwTID); if (hThread == NULL) { dwCode = IDRETRY; goto wrap; } WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &dwCode); CloseHandle(hThread); goto wrap; } #ifdef ASSERT_PIPE_ALLOWED #ifdef _DEBUG if (!abNoPipe && (gAllowAssertThread == am_Pipe)) { HWND hConWnd = GetConEmuHWND(2); HWND hGuiWnd = ghConEmuWnd; // -- искать - нельзя. Если мы НЕ в ConEmu - нельзя стучаться в другие копии!!! //#ifndef CONEMU_MINIMAL //if (hGuiWnd == NULL) //{ // hGuiWnd = FindWindowEx(NULL, NULL, VirtualConsoleClassMain, NULL); //} //#endif if (hGuiWnd && !gbInMyAssertTrap) { gbInMyAssertTrap = true; gbInMyAssertPipe = true; gnInMyAssertThread = GetCurrentThreadId(); ResetEvent(ghInMyAssertTrap); dwCode = GuiMessageBox(abNoPipe ? NULL : hGuiWnd, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); gbInMyAssertTrap = false; gbInMyAssertPipe = false; SetEvent(ghInMyAssertTrap); gnInMyAssertThread = 0; goto wrap; } } while (gbInMyAssertPipe && (gnInMyAssertThread != GetCurrentThreadId())) { Sleep(250); } #endif #endif // В консольных приложениях попытка запустить CreateThread(MyAssertThread) может зависать dwCode = MyAssertThread(pa); wrap: if (pa) HeapFree(hHeap, 0, pa); if (szExeName) HeapFree(hHeap, 0, szExeName); return (dwCode == IDRETRY) ? -1 : 1; }
LPVOID WINAPI OnVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { //typedef LPVOID(WINAPI* OnVirtualAlloc_t)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); ORIGINAL_KRNL(VirtualAlloc); LPVOID lpResult = F(VirtualAlloc)(lpAddress, dwSize, flAllocationType, flProtect); DWORD dwErr = GetLastError(); wchar_t szText[MAX_PATH*4]; if (lpResult == NULL) { wchar_t szTitle[64]; msprintf(szTitle, countof(szTitle), L"ConEmuHk, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); MEMORY_BASIC_INFORMATION mbi = {}; SIZE_T mbiSize = VirtualQuery(lpAddress, &mbi, sizeof(mbi)); wchar_t szOwnedModule[MAX_PATH] = L""; FindModuleByAddress((const BYTE*)lpAddress, szOwnedModule, countof(szOwnedModule)); msprintf(szText, countof(szText)-MAX_PATH, L"VirtualAlloc " WIN3264TEST(L"%u",L"x%X%08X") L" bytes failed (%08X..%08X)\n" L"ErrorCode=%u %s\n\n" L"Allocated information (" WIN3264TEST(L"x%08X",L"x%X%08X") L".." WIN3264TEST(L"x%08X",L"x%X%08X") L")\n" L"Size " WIN3264TEST(L"%u",L"x%X%08X") L" bytes State x%X Type x%X Protect x%X\n" L"Module: %s\n\n" L"Warning! This may cause an errors in Release!\n" L"Press <OK> to VirtualAlloc at the default address\n\n", WIN3264WSPRINT(dwSize), LODWORD(lpAddress), LODWORD((LPBYTE)lpAddress+dwSize), dwErr, (dwErr == 487) ? L"(ERROR_INVALID_ADDRESS)" : L"", WIN3264WSPRINT(mbi.BaseAddress), WIN3264WSPRINT(((LPBYTE)mbi.BaseAddress+mbi.RegionSize)), WIN3264WSPRINT(mbi.RegionSize), mbi.State, mbi.Type, mbi.Protect, szOwnedModule[0] ? szOwnedModule : L"<Unknown>", 0); GetModuleFileName(NULL, szText+lstrlen(szText), MAX_PATH); DebugString(szText); #if defined(REPORT_VIRTUAL_ALLOC) // clink use bunch of VirtualAlloc to try to find suitable memory location // Some processes raises that error too often (in debug) bool bReport = (!gbIsCmdProcess || (dwSize != 0x1000)) && !gbSkipVirtualAllocErr && !gbIsNodeJSProcess; if (bReport) { // Do not report for .Net application static int iNetChecked = 0; if (!iNetChecked) { HMODULE hClr = GetModuleHandle(L"mscoree.dll"); iNetChecked = hClr ? 2 : 1; } bReport = (iNetChecked == 1); } int iBtn = bReport ? GuiMessageBox(NULL, szText, szTitle, MB_SYSTEMMODAL|MB_OKCANCEL|MB_ICONSTOP) : IDCANCEL; if (iBtn == IDOK) { lpResult = F(VirtualAlloc)(NULL, dwSize, flAllocationType, flProtect); dwErr = GetLastError(); } #endif } msprintf(szText, countof(szText), L"VirtualAlloc(" WIN3264TEST(L"0x%08X",L"0x%08X%08X") L"," WIN3264TEST(L"0x%08X",L"0x%08X%08X") L",%u,%u)=" WIN3264TEST(L"0x%08X",L"0x%08X%08X") L"\n", WIN3264WSPRINT(lpAddress), WIN3264WSPRINT(dwSize), flAllocationType, flProtect, WIN3264WSPRINT(lpResult)); DebugString(szText); SetLastError(dwErr); return lpResult; }
bool InitRegistryRoot(CESERVER_CONSOLE_MAPPING_HDR* pInfo) { wchar_t szTitle[64]; msprintf(szTitle, countof(szTitle), L"ConEmuHk, PID=%u", GetCurrentProcessId()); if (!ghAdvapi32) { GuiMessageBox(ghConEmuWnd, L"ConEmuHk: InitRegistryRoot was called, but ghAdvapi32 is null!\n", szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); return false; } if (!RegOpenKeyEx_f) { _ASSERTE(RegOpenKeyEx_f!=NULL); RegOpenKeyEx_f = (RegOpenKeyEx_t)GetProcAddress(ghAdvapi32, "RegOpenKeyExW"); if (!RegOpenKeyEx_f) { GuiMessageBox(ghConEmuWnd, L"ConEmuHk: InitRegistryRoot was called, but GetProcAddress(RegOpenKeyExW) is null!\n", szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); return false; } } if (!RegCreateKeyEx_f) { _ASSERTE(RegCreateKeyEx_f!=NULL); RegCreateKeyEx_f = (RegCreateKeyEx_t)GetProcAddress(ghAdvapi32, "RegCreateKeyExW"); if (!RegCreateKeyEx_f) { GuiMessageBox(ghConEmuWnd, L"ConEmuHk: InitRegistryRoot was called, but GetProcAddress(RegCreateKeyExW) is null!\n", szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); return false; } } if (!RegCloseKey_f) { _ASSERTE(RegCloseKey_f!=NULL); RegCloseKey_f = (RegCloseKey_t)GetProcAddress(ghAdvapi32, "RegCloseKey"); if (!RegCloseKey_f) { GuiMessageBox(ghConEmuWnd, L"ConEmuHk: InitRegistryRoot was called, but GetProcAddress(RegCloseKey) is null!\n", szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); return false; } } if (ghNewKeyRoot == NULL) { //OSVERSIONINFO osv = {sizeof(OSVERSIONINFO)}; //GetVersionEx(&osv); //if (osv.dwMajorVersion >= 6) if (!*pInfo->sMountKey) { // Vista+ typedef LONG (WINAPI* RegLoadAppKey_t)(LPCWSTR lpFile, PHKEY phkResult, REGSAM samDesired, DWORD dwOptions, DWORD Reserved); RegLoadAppKey_t RegLoadAppKey_f = (RegLoadAppKey_t)GetProcAddress(ghAdvapi32, "RegLoadAppKeyW"); if (RegLoadAppKey_f) { LONG lRc = 0; if ((lRc = RegLoadAppKey_f(pInfo->sHiveFileName, &ghNewKeyRoot, KEY_ALL_ACCESS, 0, 0)) != 0) { if ((lRc = RegLoadAppKey_f(pInfo->sHiveFileName, &ghNewKeyRoot, KEY_READ, 0, 0)) != 0) { wchar_t szDbgMsg[128]; msprintf(szDbgMsg, countof(szDbgMsg), L"ConEmuHk: RegLoadAppKey failed, code=0x%08X!\n", (DWORD)lRc); GuiMessageBox(ghConEmuWnd, szDbgMsg, szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); ghNewKeyRoot = NULL; } } } else { GuiMessageBox(ghConEmuWnd, L"ConEmuHk: InitRegistryRoot was called, but GetProcAddress(RegLoadAppKeyW) is null!\n", szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); ghNewKeyRoot = NULL; } } else { // XP Only. т.к. для монтирования хайва требуются права админа HKEY hkRoot = pInfo->hMountRoot; if (hkRoot == HKEY_CURRENT_USER) { // Значит это "HKCU\Software\ConEmu Virtual Registry" if (RegOpenKeyEx_f(HKEY_CURRENT_USER, VIRTUAL_REGISTRY_ROOT, 0, KEY_ALL_ACCESS, &hkRoot)) { GuiMessageBox(ghConEmuWnd, L"ConEmuHk: RegOpenKeyEx(" VIRTUAL_REGISTRY_ROOT L") failed!\n", szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); ghNewKeyRoot = NULL; hkRoot = NULL; } } if (hkRoot && RegOpenKeyEx_f(hkRoot, pInfo->sMountKey, 0, KEY_ALL_ACCESS, &ghNewKeyRoot)) { if (RegOpenKeyEx_f(hkRoot, pInfo->sMountKey, 0, KEY_READ, &ghNewKeyRoot)) { wchar_t szErrMsg[512]; msprintf(szErrMsg, countof(szErrMsg), L"ConEmuHk: RegOpenKeyEx(0x%X,'%s') failed!\n", (DWORD)(LONG)(LONG_PTR)hkRoot, pInfo->sMountKey); GuiMessageBox(ghConEmuWnd, szErrMsg, szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); ghNewKeyRoot = NULL; } } } if (!ghNewKeyRoot) { ghNewKeyRoot = (HKEY)-1; } else { LONG lRc = 0; LPCWSTR pszKeyName = NULL; if (!lRc) lRc = RegCreateKeyEx_f(ghNewKeyRoot, pszKeyName=L"HKCU", 0,0,0, KEY_ALL_ACCESS, 0, &ghNewHKCU, 0); if (!lRc) lRc = RegCreateKeyEx_f(ghNewKeyRoot, pszKeyName=L"HKCU\\Software", 0,0,0, KEY_ALL_ACCESS, 0, &ghNewHKCUSoftware, 0); if (!lRc) lRc = RegCreateKeyEx_f(ghNewKeyRoot, pszKeyName=L"HKLM", 0,0,0, KEY_ALL_ACCESS, 0, &ghNewHKLM32, 0); if (!lRc) lRc = RegCreateKeyEx_f(ghNewKeyRoot, pszKeyName=L"HKLM\\Software", 0,0,0, KEY_ALL_ACCESS, 0, &ghNewHKLM32Software, 0); if (!lRc && IsWindows64()) { // эта ветка не должна выполняться в 32битных ОС if (!lRc) lRc = RegCreateKeyEx_f(ghNewKeyRoot, pszKeyName=L"HKLM64", 0,0,0, KEY_ALL_ACCESS, 0, &ghNewHKLM64, 0); if (!lRc) lRc = RegCreateKeyEx_f(ghNewKeyRoot, pszKeyName=L"HKLM64\\Software", 0,0,0, KEY_ALL_ACCESS, 0, &ghNewHKLM64Software, 0); } if (lRc != 0) { CloseRootKeys(); ghNewKeyRoot = (HKEY)-1; // чтобы не пытаться открыть повторно wchar_t szErrInfo[MAX_PATH]; msprintf(szErrInfo, countof(szErrInfo), L"ConEmuHk: Virtual subkey (%s) creation failed! ErrCode=0x%08X\n", pszKeyName ? pszKeyName : L"<NULL>", (DWORD)lRc); GuiMessageBox(ghConEmuWnd, szErrInfo, szTitle, MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); } // Для консистентности if (!ghNewHKLM64) ghNewHKLM64 = ghNewHKLM32; if (!ghNewHKLM64Software) ghNewHKLM64Software = ghNewHKLM32Software; } } if ((ghNewKeyRoot == NULL) || (ghNewKeyRoot == (HKEY)-1)) { DEBUGSTR(L"ConEmuHk: Registry virtualization failed!\n"); return false; } else { DEBUGSTR(L"ConEmuHk: Registry virtualization succeeded\n"); } return true; }
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { BOOL lbAllow = TRUE; switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: { gnDllState = ds_DllProcessAttach; #ifdef _DEBUG HANDLE hProcHeap = GetProcessHeap(); #endif HeapInitialize(); ghOurModule = (HMODULE)hModule; ghConWnd = GetConsoleWindow(); if (ghConWnd) GetConsoleTitle(gsInitConTitle, countof(gsInitConTitle)); gnSelfPID = GetCurrentProcessId(); ghWorkingModule = (u64)hModule; gfGetRealConsoleWindow = GetConsoleWindow; user = (UserImp*)calloc(1, sizeof(*user)); GetMainThreadId(); // Инициализировать gnHookMainThreadId gcchLastWriteConsoleMax = 4096; gpszLastWriteConsole = (wchar_t*)calloc(gcchLastWriteConsoleMax,sizeof(*gpszLastWriteConsole)); gInQueue.Initialize(512, NULL); #ifdef _DEBUG gAllowAssertThread = am_Pipe; #endif #ifdef _DEBUG #ifdef UseDebugExceptionFilter gfnPrevFilter = SetUnhandledExceptionFilter(HkExceptionFilter); #endif #endif #ifdef SHOW_STARTED_MSGBOX if (!IsDebuggerPresent()) { ::MessageBox(ghConEmuWnd, L"ConEmuHk*.dll loaded", L"ConEmu hooks", MB_SYSTEMMODAL); } #endif #ifdef _DEBUG DWORD dwConMode = -1; GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConMode); #endif //_ASSERTE(ghHeap == NULL); //ghHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 200000, 0); wchar_t szEvtName[64]; msprintf(szEvtName, countof(szEvtName), CECONEMUROOTPROCESS, gnSelfPID); HANDLE hRootProcessFlag = OpenEvent(SYNCHRONIZE|EVENT_MODIFY_STATE, FALSE, szEvtName); DWORD nWaitRoot = -1; if (hRootProcessFlag) { nWaitRoot = WaitForSingleObject(hRootProcessFlag, 0); gbSelfIsRootConsoleProcess = (nWaitRoot == WAIT_OBJECT_0); } SafeCloseHandle(hRootProcessFlag); #ifdef HOOK_USE_DLLTHREAD _ASSERTEX(FALSE && "Hooks starting in background thread?"); //HANDLE hEvents[2]; //hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL); //hEvents[1] = ghStartThread = CreateThread(NULL, 0, DllStart, NULL/*(LPVOID)(hEvents[0])*/, 0, &gnStartThreadID); if (ghStartThread == NULL) { //_ASSERTE(ghStartThread!=NULL); wchar_t szMsg[128]; DWORD nErrCode = GetLastError(); msprintf(szMsg, countof(szMsg), L"Failed to start DllStart thread!\nErrCode=0x%08X\nPID=%u", nErrCode, GetCurrentProcessId()); GuiMessageBox(ghConEmuWnd, szMsg, L"ConEmu hooks", 0); } else { DWORD nThreadWait = WaitForSingleObject(ghStartThread, 5000); DllThreadClose(); } //DWORD nThreadWait = WaitForMultipleObjects(hEvents, countof(hEvents), FALSE, INFINITE); //CloseHandle(hEvents[0]); #else DllStart(NULL); #endif user->setAllowLoadLibrary(); } break; case DLL_THREAD_ATTACH: { gnDllThreadCount++; if (gbHooksWasSet) InitHooksRegThread(); } break; case DLL_THREAD_DETACH: { #ifdef SHOW_SHUTDOWN_STEPS gnDbgPresent = 0; ShutdownStep(L"DLL_THREAD_DETACH"); #endif if (gbHooksWasSet) DoneHooksRegThread(); // DLL_PROCESS_DETACH зовется как выяснилось не всегда if (gnHookMainThreadId && (GetCurrentThreadId() == gnHookMainThreadId) && !gbDllDeinitialized) { gbDllDeinitialized = true; //WARNING!!! OutputDebugString must NOT be used from ConEmuHk::DllMain(DLL_PROCESS_DETACH). See Issue 465 DllStop(); } gnDllThreadCount--; ShutdownStep(L"DLL_THREAD_DETACH done, left=%i", gnDllThreadCount); } break; case DLL_PROCESS_DETACH: { ShutdownStep(L"DLL_PROCESS_DETACH"); gnDllState = ds_DllProcessDetach; if (gbHooksWasSet) lbAllow = FALSE; // Иначе свалимся, т.к. FreeLibrary перехвачена // Уже могли дернуть в DLL_THREAD_DETACH if (!gbDllDeinitialized) { gbDllDeinitialized = true; //WARNING!!! OutputDebugString must NOT be used from ConEmuHk::DllMain(DLL_PROCESS_DETACH). See Issue 465 DllStop(); } // -- free не нужен, т.к. уже вызван HeapDeinitialize() //free(user); ShutdownStep(L"DLL_PROCESS_DETACH done"); } break; } return lbAllow; }
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; }