diff --git a/CMakeLists.txt b/CMakeLists.txt index 725b2b668..06c70fa19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1068,7 +1068,7 @@ elseif(WIN32) src/detection/users/users_windows.c src/detection/wallpaper/wallpaper_windows.c src/detection/wifi/wifi_windows.c - src/detection/wm/wm_windows.cpp + src/detection/wm/wm_windows.c src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_windows.c src/detection/camera/camera_windows.cpp @@ -1729,6 +1729,7 @@ elseif(WIN32) PRIVATE "cfgmgr32" PRIVATE "propsys" PRIVATE "secur32" + PRIVATE "wintrust" ) if(NOT ENABLE_WIN7_COMPAT) target_link_libraries(libfastfetch diff --git a/src/detection/wm/wm_windows.c b/src/detection/wm/wm_windows.c new file mode 100644 index 000000000..9b5f850a0 --- /dev/null +++ b/src/detection/wm/wm_windows.c @@ -0,0 +1,143 @@ +#include "wm.h" +#include "common/mallocHelper.h" +#include "common/windows/version.h" +#include "common/io.h" + +#include +#include +#include +#include +#include +#include + +bool isProcessTrusted(DWORD processId, UNICODE_STRING* buffer, size_t bufSize) +{ + FF_AUTO_CLOSE_FD HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); + if (!hProcess) + return false; + + ULONG size; + if(!NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, buffer, (ULONG) bufSize, &size)) || + buffer->Length == 0) return false; + assert(buffer->MaximumLength >= buffer->Length + 2); // NULL terminated + + static wchar_t windowsAppsPath[MAX_PATH]; + static uint32_t windowsAppsPathLen; + if (windowsAppsPathLen == 0) + { + PWSTR pPath = NULL; + if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &pPath))) + { + windowsAppsPathLen = (uint32_t) wcslen(pPath); + memcpy(windowsAppsPath, pPath, windowsAppsPathLen * sizeof(wchar_t)); + memcpy(windowsAppsPath + windowsAppsPathLen, L"\\WindowsApps\\", sizeof(L"\\WindowsApps\\")); + windowsAppsPathLen += strlen("\\WindowsApps\\"); + } + else + { + windowsAppsPathLen = -1u; + } + CoTaskMemFree(pPath); + } + if (windowsAppsPathLen != -1u && + buffer->Length > windowsAppsPathLen * sizeof(wchar_t) && + _wcsnicmp(buffer->Buffer, windowsAppsPath, windowsAppsPathLen) == 0 + ) return true; // Always trust Windows Store apps, in case the exe is not signed (FancyWM-GUI) + + WINTRUST_FILE_INFO fileInfo = { + .cbStruct = sizeof(fileInfo), + .pcwszFilePath = buffer->Buffer, + }; + + GUID actionID = WINTRUST_ACTION_GENERIC_VERIFY_V2; + + WINTRUST_DATA trustData = { + .cbStruct = sizeof(trustData), + .dwUIChoice = WTD_UI_NONE, + .fdwRevocationChecks = WTD_REVOKE_NONE, + .dwUnionChoice = WTD_CHOICE_FILE, + .pFile = &fileInfo, + .dwStateAction = WTD_STATEACTION_VERIFY, + .dwProvFlags = WTD_SAFER_FLAG, + }; + + LONG status = WinVerifyTrustEx(NULL, &actionID, &trustData); + trustData.dwStateAction = WTD_STATEACTION_CLOSE; + WinVerifyTrust(NULL, &actionID, &trustData); + + return status == ERROR_SUCCESS; +} + +const char* ffDetectWMPlugin(FFstrbuf* pluginName) +{ + alignas(UNICODE_STRING) uint8_t buffer[4096]; + UNICODE_STRING* filePath = (UNICODE_STRING*) buffer; + SYSTEM_PROCESS_INFORMATION* FF_AUTO_FREE pstart = NULL; + + // Multiple attempts in case processes change while + // we are in the middle of querying them. + ULONG size = 0; + for (int attempts = 0;; ++attempts) + { + if (size) + { + pstart = (SYSTEM_PROCESS_INFORMATION*)realloc(pstart, size); + assert(pstart); + } + NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, pstart, size, &size); + if(NT_SUCCESS(status)) + break; + else if(status == STATUS_INFO_LENGTH_MISMATCH && attempts < 4) + size += sizeof(SYSTEM_PROCESS_INFORMATION) * 5; + else + return "NtQuerySystemInformation(SystemProcessInformation) failed"; + } + + for (SYSTEM_PROCESS_INFORMATION* ptr = pstart; ptr->NextEntryOffset; ptr = (SYSTEM_PROCESS_INFORMATION*)((uint8_t*)ptr + ptr->NextEntryOffset)) + { + assert(ptr->ImageName.Length == 0 || ptr->ImageName.MaximumLength >= ptr->ImageName.Length + 2); // NULL terminated + if (ptr->ImageName.Length == strlen("FancyWM-GUI.exe") * sizeof(wchar_t) && + memcmp(ptr->ImageName.Buffer, L"FancyWM-GUI.exe", ptr->ImageName.Length) == 0 && + isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, filePath, sizeof(buffer)) + ) { + if (ffGetFileVersion(filePath->Buffer, NULL, pluginName)) + ffStrbufPrependS(pluginName, "FancyWM "); + else + ffStrbufSetStatic(pluginName, "FancyWM"); + break; + } + else if (ptr->ImageName.Length == strlen("glazewm-watcher.exe") * sizeof(wchar_t) && + memcmp(ptr->ImageName.Buffer, L"glazewm-watcher.exe", ptr->ImageName.Length) == 0 && + isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, filePath, sizeof(buffer)) + ) { + if (ffGetFileVersion(filePath->Buffer, NULL, pluginName)) + ffStrbufPrependS(pluginName, "GlazeWM "); + else + ffStrbufSetStatic(pluginName, "GlazeWM"); + break; + } + } + + return NULL; +} + +const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options) +{ + if (!wmName) + return "No WM detected"; + + if (ffStrbufEqualS(wmName, "dwm.exe")) + { + PWSTR pPath = NULL; + if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_System, KF_FLAG_DEFAULT, NULL, &pPath))) + { + wchar_t fullPath[MAX_PATH]; + wcscpy(fullPath, pPath); + wcscat(fullPath, L"\\dwm.exe"); + ffGetFileVersion(fullPath, NULL, result); + } + CoTaskMemFree(pPath); + return NULL; + } + return "Not supported on this platform"; +} diff --git a/src/detection/wm/wm_windows.cpp b/src/detection/wm/wm_windows.cpp deleted file mode 100644 index 84ee1bde2..000000000 --- a/src/detection/wm/wm_windows.cpp +++ /dev/null @@ -1,79 +0,0 @@ -extern "C" -{ -#include "wm.h" -#include "common/io.h" -#include "common/windows/version.h" -#include "detection/terminalshell/terminalshell.h" -} - -#include "common/windows/com.hpp" -#include "common/windows/util.hpp" - -#include -#include -#include -#include - -extern "C" -const char* ffDetectWMPlugin(FFstrbuf* pluginName) -{ - DWORD pid = ffDetectTerminal()->pid; // Whatever GUI program - if (pid == 0) return "Unable to find a GUI program"; - - FF_AUTO_CLOSE_FD HANDLE snapshot = NULL; - while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid)) && GetLastError() == ERROR_BAD_LENGTH) {} - - if(!snapshot) - return "CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid) failed"; - - if (ffInitCom()) - return "ffInitCom() failed"; - - MODULEENTRY32W module; - module.dwSize = sizeof(module); - for(BOOL success = Module32FirstW(snapshot, &module); success; success = Module32NextW(snapshot, &module)) - { - if(wcscmp(module.szModule, L"wbhelp64.dll") == 0 || wcscmp(module.szModule, L"wbhelp.dll") == 0) - { - IShellItem2* shellItem = NULL; - if (FAILED(SHCreateItemFromParsingName(module.szExePath, NULL, IID_IShellItem2, (void**) &shellItem))) - continue; - - on_scope_exit destroyShellItem([=] { shellItem->Release(); }); - - wchar_t* desc = NULL; - if (FAILED(shellItem->GetString(PKEY_FileDescription, &desc))) - continue; - - on_scope_exit destroyDesc([=] { CoTaskMemFree(desc); }); - - if (wcscmp(desc, L"WindowBlinds Helper DLL") == 0) - { - ffStrbufSetStatic(pluginName, "WindowBlinds"); - break; - } - } - } - return NULL; -} - -const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options) -{ - if (!wmName) - return "No WM detected"; - - if (ffStrbufEqualS(wmName, "dwm.exe")) - { - PWSTR pPath = NULL; - if(SUCCEEDED(SHGetKnownFolderPath(FOLDERID_System, KF_FLAG_DEFAULT, NULL, &pPath))) - { - wchar_t fullPath[MAX_PATH]; - wcscpy(fullPath, pPath); - wcscat(fullPath, L"\\dwm.exe"); - ffGetFileVersion(fullPath, NULL, result); - } - CoTaskMemFree(pPath); - return NULL; - } - return "Not supported on this platform"; -}