Example #1
0
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;
}
Example #2
0
DWORD WINAPI DebugThread(LPVOID lpvParam)
{
	DWORD nWait = WAIT_TIMEOUT;
	//DWORD nExternalExitCode = -1;
	wchar_t szInfo[1024];

	if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL)
	{
		STARTUPINFO si = {sizeof(si)};
		PROCESS_INFORMATION pi = {};

		if (gpSrv->DbgInfo.bDebugProcessTree)
		{
			SetEnvironmentVariable(ENV_CONEMU_BLOCKCHILDDEBUGGERS_W, ENV_CONEMU_BLOCKCHILDDEBUGGERS_YES);
		}

		if (!CreateProcess(NULL, gpSrv->DbgInfo.pszDebuggingCmdLine, NULL, NULL, FALSE,
			NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE|
			DEBUG_PROCESS | (gpSrv->DbgInfo.bDebugProcessTree ? 0 : DEBUG_ONLY_THIS_PROCESS),
			NULL, NULL, &si, &pi))
		{
			DWORD dwErr = GetLastError();

			wchar_t szProc[64]; szProc[0] = 0;
			PROCESSENTRY32 pi = {sizeof(pi)};
			if (GetProcessInfo(gpSrv->dwRootProcess, &pi))
				_wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc));

			_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start debugging process. ErrCode=0x%08X\n", dwErr);
			lstrcpyn(szInfo+lstrlen(szInfo), gpSrv->DbgInfo.pszDebuggingCmdLine, 400);
			wcscat_c(szInfo, L"\n");
			_wprintf(szInfo);
			return CERR_CANTSTARTDEBUGGER;
		}

		gpSrv->hRootProcess = pi.hProcess;
		gpSrv->hRootThread = pi.hThread;
		gpSrv->dwRootProcess = pi.dwProcessId;
		gpSrv->dwRootThread = pi.dwThreadId;
		gpSrv->dwRootStartTime = GetTickCount();
	}


	/* ************************* */
	int iDbgIdx = 0, iAttachedCount = 0;
	while (true)
	{
		HANDLE hDbgProcess = NULL;
		DWORD  nDbgProcessID = 0;

		bool bFirstPID = ((iDbgIdx++) == 0);
		if (bFirstPID)
		{
			hDbgProcess = gpSrv->hRootProcess;
			nDbgProcessID = gpSrv->dwRootProcess;
		}
		else
		{
			// Взять из pDebugAttachProcesses
			if (!gpSrv->DbgInfo.pDebugAttachProcesses)
				break;
			if (!gpSrv->DbgInfo.pDebugAttachProcesses->pop_back(nDbgProcessID))
				break;
			hDbgProcess = GetProcessHandleForDebug(nDbgProcessID);
			if (!hDbgProcess)
			{
				_ASSERTE(hDbgProcess!=NULL && "Can't open debugging process handle");
				continue;
			}
		}
	

		_ASSERTE(hDbgProcess!=NULL && "Process handle must be opened");


		// Битность отладчика должна соответствовать битности приложения!
		if (IsWindows64())
		{
			int nBits = GetProcessBits(nDbgProcessID, hDbgProcess);
			if ((nBits == 32 || nBits == 64) && (nBits != WIN3264TEST(32,64)))
			{
				if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL)
				{
					_printf("Bitness of ConEmuC and debugging program does not match\n");
					if (bFirstPID)
						return CERR_CANTSTARTDEBUGGER;
					else
						continue;
				}

				wchar_t szExe[MAX_PATH+16];
				wchar_t szCmdLine[MAX_PATH*2];
				if (GetModuleFileName(NULL, szExe, countof(szExe)-16))
				{
					wchar_t* pszName = (wchar_t*)PointToName(szExe);
					_wcscpy_c(pszName, 16, (nBits == 32) ? L"ConEmuC.exe" : L"ConEmuC64.exe");
					_wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine))
						L"\"%s\" /DEBUGPID=%u %s", szExe, nDbgProcessID,
						(gpSrv->DbgInfo.nDebugDumpProcess == 1) ? L"/DUMP" :
						(gpSrv->DbgInfo.nDebugDumpProcess == 2) ? L"/MINIDUMP" :
						(gpSrv->DbgInfo.nDebugDumpProcess == 3) ? L"/FULLDUMP" : L"");

					STARTUPINFO si = {sizeof(si)};
					PROCESS_INFORMATION pi = {};
					if (CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
					{
						// Ждать НЕ будем, сразу на выход

						//HANDLE hEvents[2] = {pi.hProcess, ghExitQueryEvent};
						//nWait = WaitForMultipleObjects(countof(hEvents), hEvents, FALSE, INFINITE);
						//if (nWait == WAIT_OBJECT_0)
						//{
						//	//GetExitCodeProcess(pi.hProcess, &nExternalExitCode);
						//	nExternalExitCode = 0;
						//}

						//CloseHandle(pi.hProcess);
						//CloseHandle(pi.hThread);

						//if (nExternalExitCode == 0)
						//{
						//	goto done;
						//}

						// Может там еще процессы в списке на дамп?
						continue;
					}
					else
					{
						DWORD dwErr = GetLastError();
						_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start external debugger '%s'. ErrCode=0x%08X\n",
							szCmdLine, dwErr);
						_wprintf(szInfo);
						if (bFirstPID)
							return CERR_CANTSTARTDEBUGGER;
						else
							continue;
					}
				}


				wchar_t szProc[64]; szProc[0] = 0;
				PROCESSENTRY32 pi = {sizeof(pi)};
				if (GetProcessInfo(nDbgProcessID, &pi))
					_wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc));

				_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Bits are incompatible. Can't debug '%s' PID=%i\n",
					szProc[0] ? szProc : L"not found", nDbgProcessID);
				_wprintf(szInfo);
				if (bFirstPID)
					return CERR_CANTSTARTDEBUGGER;
				else
					continue;
			}
		}

		if (gpSrv->DbgInfo.pszDebuggingCmdLine == NULL)
		{
			if (!DebugActiveProcess(nDbgProcessID))
			{
				DWORD dwErr = GetLastError();

				wchar_t szProc[64]; szProc[0] = 0;
				PROCESSENTRY32 pi = {sizeof(pi)};
				if (GetProcessInfo(nDbgProcessID, &pi))
					_wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc));

				_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't attach debugger to '%s' PID=%i. ErrCode=0x%08X\n",
					szProc[0] ? szProc : L"not found", nDbgProcessID, dwErr);
				_wprintf(szInfo);
				return CERR_CANTSTARTDEBUGGER;
			}
		}

		iAttachedCount++;
	}

	if (iAttachedCount == 0)
	{
		return CERR_CANTSTARTDEBUGGER;
	}
	/* **************** */

	// Дополнительная инициализация, чтобы закрытие дебагера (наш процесс) не привело
	// к закрытию "отлаживаемой" программы
	pfnDebugActiveProcessStop = (FDebugActiveProcessStop)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugActiveProcessStop");
	pfnDebugSetProcessKillOnExit = (FDebugSetProcessKillOnExit)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugSetProcessKillOnExit");

	if (pfnDebugSetProcessKillOnExit)
		pfnDebugSetProcessKillOnExit(FALSE/*KillOnExit*/);

	gpSrv->DbgInfo.bDebuggerActive = TRUE;
	PrintDebugInfo();
	SetEvent(gpSrv->DbgInfo.hDebugReady);
	

	while (nWait == WAIT_TIMEOUT)
	{
		ProcessDebugEvent();

		if (ghExitQueryEvent)
			nWait = WaitForSingleObject(ghExitQueryEvent, 0);
	}

//done:
	gbRootAliveLess10sec = FALSE;
	gbInShutdown = TRUE;
	gbAlwaysConfirmExit = FALSE;

	_ASSERTE(gbTerminateOnCtrlBreak==FALSE);

	if (!nExitQueryPlace) nExitQueryPlace = 12+(nExitPlaceStep);

	SetTerminateEvent(ste_DebugThread);
	return 0;
}
Example #3
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;
}
// 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;
}
Example #5
0
DWORD WINAPI DebugThread(LPVOID lpvParam)
{
	DWORD nWait = WAIT_TIMEOUT;
	wchar_t szInfo[1024];
	wchar_t szPID[20];
	int iAttachedCount = 0;
	CEStr szOtherBitPids, szOtherDebugCmd;

	// Дополнительная инициализация, чтобы закрытие дебагера (наш процесс) не привело
	// к закрытию "отлаживаемой" программы
	pfnDebugActiveProcessStop = (FDebugActiveProcessStop)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugActiveProcessStop");
	pfnDebugSetProcessKillOnExit = (FDebugSetProcessKillOnExit)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugSetProcessKillOnExit");

	// Affect GetProcessHandleForDebug
	gpSrv->DbgInfo.bDebuggerActive = TRUE;

	// If dump was requested
	if (gpSrv->DbgInfo.nDebugDumpProcess)
	{
		gpSrv->DbgInfo.bUserRequestDump = TRUE;
	}

	// "/DEBUGEXE" or "/DEBUGTREE"
	if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL)
	{
		STARTUPINFO si = {sizeof(si)};
		PROCESS_INFORMATION pi = {};

		if (gpSrv->DbgInfo.bDebugProcessTree)
		{
			SetEnvironmentVariable(ENV_CONEMU_BLOCKCHILDDEBUGGERS_W, ENV_CONEMU_BLOCKCHILDDEBUGGERS_YES);
		}

		if (!CreateProcess(NULL, gpSrv->DbgInfo.pszDebuggingCmdLine, NULL, NULL, FALSE,
			NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE|
			DEBUG_PROCESS | (gpSrv->DbgInfo.bDebugProcessTree ? 0 : DEBUG_ONLY_THIS_PROCESS),
			NULL, NULL, &si, &pi))
		{
			DWORD dwErr = GetLastError();

			wchar_t szProc[64]; szProc[0] = 0;
			PROCESSENTRY32 pi = {sizeof(pi)};
			if (GetProcessInfo(gpSrv->dwRootProcess, &pi))
				_wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc));

			_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start debugging process. ErrCode=0x%08X\n", dwErr);
			CEStr lsInfo(lstrmerge(szInfo, gpSrv->DbgInfo.pszDebuggingCmdLine, L"\n"));
			_wprintf(lsInfo);
			return CERR_CANTSTARTDEBUGGER;
		}

		gpSrv->hRootProcess = pi.hProcess;
		gpSrv->hRootThread = pi.hThread;
		gpSrv->dwRootProcess = pi.dwProcessId;
		gpSrv->dwRootThread = pi.dwThreadId;
		gpSrv->dwRootStartTime = GetTickCount();

		// Let's know that at least one process is debugging
		iAttachedCount++;
	}


	/* ************************* */
	int iDbgIdx = 0;
	bool bSetKillOnExit = true;

	while (true)
	{
		HANDLE hDbgProcess = NULL;
		DWORD  nDbgProcessID = 0;

		if ((iDbgIdx++) == 0)
		{
			hDbgProcess = gpSrv->hRootProcess;
			nDbgProcessID = gpSrv->dwRootProcess;
		}
		else
		{
			// Взять из pDebugAttachProcesses
			if (!gpSrv->DbgInfo.pDebugAttachProcesses)
				break;
			if (!gpSrv->DbgInfo.pDebugAttachProcesses->pop_back(nDbgProcessID))
				break;
			hDbgProcess = GetProcessHandleForDebug(nDbgProcessID);
			if (!hDbgProcess)
			{
				_ASSERTE(hDbgProcess!=NULL && "Can't open debugging process handle");
				continue;
			}
		}


		_ASSERTE(hDbgProcess!=NULL && "Process handle must be opened");


		// Битность отладчика должна соответствовать битности приложения!
		if (IsWindows64())
		{
			int nBits = GetProcessBits(nDbgProcessID, hDbgProcess);
			if ((nBits == 32 || nBits == 64) && (nBits != WIN3264TEST(32,64)))
			{
				// If /DEBUGEXE or /DEBUGTREE was used
				if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL)
				{
					_printf("Bitness of ConEmuC and debugging program does not match\n");
					continue;
				}

				// Добавить процесс в список для запуска альтернативного дебаггера соотвествующей битности
				// Force trailing "," even if only one PID specified ( --> bDebugMultiProcess = TRUE)
				lstrmerge(&szOtherBitPids.ms_Arg, _itow(nDbgProcessID, szPID, 10), L",");

				// Может там еще процессы в списке на дамп?
				continue;
			}
		}

		if (gpSrv->DbgInfo.pszDebuggingCmdLine == NULL)
		{
			if (DebugActiveProcess(nDbgProcessID))
			{
				iAttachedCount++;
			}
			else
			{
				DWORD dwErr = GetLastError();

				wchar_t szProc[64]; szProc[0] = 0;
				PROCESSENTRY32 pi = {sizeof(pi)};
				if (GetProcessInfo(nDbgProcessID, &pi))
					_wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc));

				_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't attach debugger to '%s' PID=%i. ErrCode=0x%08X\n",
					szProc[0] ? szProc : L"not found", nDbgProcessID, dwErr);
				_wprintf(szInfo);

				// Может другие подцепить получится?
				continue;
			}
		}

		// To avoid debugged processes killing
		if (bSetKillOnExit && pfnDebugSetProcessKillOnExit)
		{
			// affects all current and future debuggees connected to the calling thread
			if (pfnDebugSetProcessKillOnExit(FALSE/*KillOnExit*/))
			{
				bSetKillOnExit = false;
			}
		}
	}

	// Different bitness, need to start appropriate debugger
	if (szOtherBitPids.ms_Arg && *szOtherBitPids.ms_Arg)
	{
		wchar_t szExe[MAX_PATH+5], *pszName;
		if (!GetModuleFileName(NULL, szExe, MAX_PATH))
		{
			_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"GetModuleFileName(NULL) failed. ErrCode=0x%08X\n", GetLastError());
			_wprintf(szInfo);
		}
		else if (!(pszName = (wchar_t*)PointToName(szExe)))
		{
			_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"GetModuleFileName(NULL) returns invalid path\n%s\n", szExe);
			_wprintf(szInfo);
		}
		else
		{
			*pszName = 0;
			// Reverted to current bitness
			wcscat_c(szExe, WIN3264TEST(L"ConEmuC64.exe", L"ConEmuC.exe"));

			szOtherDebugCmd.Attach(lstrmerge(L"\"", szExe, L"\" "
				L"/DEBUGPID=", szOtherBitPids.ms_Arg,
				(gpSrv->DbgInfo.nDebugDumpProcess == 1) ? L" /DUMP" :
				(gpSrv->DbgInfo.nDebugDumpProcess == 2) ? L" /MINIDUMP" :
				(gpSrv->DbgInfo.nDebugDumpProcess == 3) ? L" /FULLDUMP" : L""));

			STARTUPINFO si = {sizeof(si)};
			PROCESS_INFORMATION pi = {};
			if (CreateProcess(NULL, szOtherDebugCmd.ms_Arg, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
			{
				// Ждать не будем
			}
			else
			{
				DWORD dwErr = GetLastError();
				_wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start external debugger, ErrCode=0x%08X\n", dwErr);
				CEStr lsInfo(lstrmerge(szInfo, szOtherDebugCmd, L"\n"));
				_wprintf(lsInfo);
			}
		}
	}

	//_ASSERTE(FALSE && "Continue to dump");

	// If neither /DEBUG[EXE|TREE] nor /DEBUGPID was not succeeded
	if (iAttachedCount == 0)
	{
		gpSrv->DbgInfo.bDebuggerActive = FALSE;
		return CERR_CANTSTARTDEBUGGER;
	}
	else if (iAttachedCount > 1)
	{
		_ASSERTE(gpSrv->DbgInfo.bDebugMultiProcess && "Already must be set from arguments parser");
		gpSrv->DbgInfo.bDebugMultiProcess = TRUE;
	}

	if (gpSrv->DbgInfo.bUserRequestDump)
	{
		gpSrv->DbgInfo.nWaitTreeBreaks = iAttachedCount;
	}

	/* **************** */

	// To avoid debugged processes killing (JIC, must be called already)
	if (bSetKillOnExit && pfnDebugSetProcessKillOnExit)
	{
		// affects all current and future debuggees connected to the calling thread
		if (pfnDebugSetProcessKillOnExit(FALSE/*KillOnExit*/))
		{
			bSetKillOnExit = false;
		}
	}

	PrintDebugInfo();
	SetEvent(gpSrv->DbgInfo.hDebugReady);


	while (nWait == WAIT_TIMEOUT)
	{
		ProcessDebugEvent();

		if (ghExitQueryEvent)
			nWait = WaitForSingleObject(ghExitQueryEvent, 0);
	}

//done:
	gbRootAliveLess10sec = FALSE;
	gbInShutdown = TRUE;
	gbAlwaysConfirmExit = FALSE;

	_ASSERTE(gbTerminateOnCtrlBreak==FALSE);

	if (!nExitQueryPlace) nExitQueryPlace = 12+(nExitPlaceStep);

	SetTerminateEvent(ste_DebugThread);
	return 0;
}