diff --git a/CHANGELOG.md b/CHANGELOG.md index 4992e1913..5d79318a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Features: * Bluetooth module * Sound module +Bugfixes: + +* Fix a rare case that fails to detect terminal + # 1.9.1 Bugfixes: diff --git a/src/detection/terminalshell/terminalshell.h b/src/detection/terminalshell/terminalshell.h index a2a1f4200..f506381bb 100644 --- a/src/detection/terminalshell/terminalshell.h +++ b/src/detection/terminalshell/terminalshell.h @@ -12,12 +12,14 @@ typedef struct FFTerminalShellResult const char* shellExeName; //pointer to a char in shellExe FFstrbuf shellPrettyName; FFstrbuf shellVersion; + uint32_t shellPid; FFstrbuf terminalProcessName; FFstrbuf terminalExe; FFstrbuf terminalPrettyName; const char* terminalExeName; //pointer to a char in terminalExe FFstrbuf terminalVersion; + uint32_t terminalPid; FFstrbuf userShellExe; const char* userShellExeName; //pointer to a char in userShellExe diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index e6b765ba9..1a2875508 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -162,6 +162,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) ) { if (result->shellProcessName.length == 0) { + result->shellPid = (uint32_t) pid; ffStrbufSetS(&result->shellProcessName, name); getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); } @@ -170,6 +171,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) return; } + result->terminalPid = (uint32_t) pid; ffStrbufSetS(&result->terminalProcessName, name); getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName); } @@ -336,10 +338,12 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) ffStrbufInitA(&result.shellExe, exePathLen); result.shellExeName = result.shellExe.chars; ffStrbufInit(&result.shellVersion); + result.shellPid = 0; ffStrbufInit(&result.terminalProcessName); ffStrbufInitA(&result.terminalExe, exePathLen); result.terminalExeName = result.terminalExe.chars; + result.terminalPid = 0; ffStrbufInit(&result.userShellExe); result.userShellExeName = result.userShellExe.chars; diff --git a/src/detection/terminalshell/terminalshell_windows.cpp b/src/detection/terminalshell/terminalshell_windows.cpp index b800228fa..58dc2c588 100644 --- a/src/detection/terminalshell/terminalshell_windows.cpp +++ b/src/detection/terminalshell/terminalshell_windows.cpp @@ -2,6 +2,7 @@ extern "C" { #include "terminalshell.h" #include "common/processing.h" #include "common/thread.h" +#include "util/mallocHelper.h" } #include @@ -10,6 +11,7 @@ extern "C" { #ifdef FF_USE_WIN_NTAPI +#include #include static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName) @@ -54,6 +56,45 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb return true; } +static bool getTerminalInfoByEnumeratingChildProcesses(FFTerminalShellResult* result, uint32_t ppid) +{ + ULONG size = 0; + if(NtQuerySystemInformation(SystemProcessInformation, nullptr, 0, &size) != STATUS_INFO_LENGTH_MISMATCH) + return false; + + size += sizeof(SystemProcessInformation) * 5; //What if new processes are created during two syscalls? + + SYSTEM_PROCESS_INFORMATION* FF_AUTO_FREE pstart = (SYSTEM_PROCESS_INFORMATION*)malloc(size); + if(!pstart) + return false; + + if(!NT_SUCCESS(NtQuerySystemInformation(SystemProcessInformation, pstart, size, nullptr))) + return false; + + uint32_t currentProcessId = (uint32_t) GetCurrentProcessId(); + + for (auto ptr = pstart; ptr->NextEntryOffset; ptr = (SYSTEM_PROCESS_INFORMATION*)((uint8_t*)ptr + ptr->NextEntryOffset)) + { + if ((uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId != ppid) + continue; + + uint32_t pid = (uint32_t)(uintptr_t) ptr->UniqueProcessId; + if (pid == currentProcessId) + continue; + + if(!getProcessInfo(pid, nullptr, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName)) + return false; + + result->terminalPid = pid; + ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); + if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) + ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4); + + return true; + } + return false; +} + #else #include "util/windows/wmi.hpp" @@ -95,6 +136,33 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb return true; } +static bool getTerminalInfoByEnumeratingChildProcesses(FFTerminalShellResult* result, uint32_t ppid) +{ + wchar_t sql[256] = {}; + swprintf(sql, 256, L"SELECT Name, ExecutablePath, ProcessId FROM Win32_Process WHERE ProcessId <> %" PRIu32 " AND ParentProcessId = %" PRIu32, + (uint32_t) GetCurrentProcessId(), + ppid); + + FFWmiQuery query(sql); + if(!query) + return false; + + if(FFWmiRecord record = query.next()) + { + record.getString(L"Name", &result->terminalProcessName); + record.getString(L"ExecutablePath", &result->terminalExe); + result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1; + uint64_t pid; + record.getUnsigned(L"ProcessId", &pid); + result->terminalPid = (uint32_t) pid; + ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); + if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) + ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4); + return true; + } + return false; +} + #endif extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); @@ -135,6 +203,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* if(instance->config.shellVersion) fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion); + result->shellPid = pid; if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh")) ffStrbufSetS(&result->shellPrettyName, "PowerShell"); else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell")) @@ -154,7 +223,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* module.dwSize = sizeof(module); for(BOOL success = Module32FirstW(snapshot, &module); success; success = Module32NextW(snapshot, &module)) { - if(wcsncmp(module.szModule, L"clink_dll_", wcslen(L"clink_dll_")) == 0) + if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0) { ffStrbufAppendS(&result->shellPrettyName, "CMD (with Clink)"); break; @@ -170,6 +239,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) { ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell + // In this case, terminal process will be created by fastfetch itself. return 0; } @@ -205,6 +275,21 @@ static uint32_t getTerminalInfo(const FFinstance* instance, FFTerminalShellResul return getTerminalInfo(instance, result, ppid); } + if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "sihost") || + ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer") + ) { + ffStrbufClear(&result->terminalProcessName); + ffStrbufClear(&result->terminalPrettyName); + ffStrbufClear(&result->terminalExe); + result->terminalExeName = ""; + + // Maybe terminal process is created by shell + if(!getTerminalInfoByEnumeratingChildProcesses(result, result->shellPid)) + return 0; + } + else + result->terminalPid = pid; + if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal")) ffStrbufSetS(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_") ? "Windows Terminal Preview" @@ -288,11 +373,13 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) result.shellExeName = ""; ffStrbufInit(&result.shellPrettyName); ffStrbufInit(&result.shellVersion); + result.shellPid = 0; ffStrbufInit(&result.terminalProcessName); ffStrbufInitA(&result.terminalExe, 128); result.terminalExeName = ""; ffStrbufInit(&result.terminalPrettyName); + result.terminalPid = 0; ffStrbufInit(&result.userShellExe); result.userShellExeName = ""; @@ -303,7 +390,9 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) goto exit; ppid = getShellInfo(instance, &result, ppid); - getTerminalInfo(instance, &result, ppid); + if(ppid) + getTerminalInfo(instance, &result, ppid); + if(result.terminalProcessName.length == 0) getTerminalFromEnv(&result);