WM (Windows): supports komorebi detection

This commit is contained in:
李通洲
2026-02-28 10:03:27 +08:00
parent a69cf456ea
commit 3e25b213b1
2 changed files with 138 additions and 40 deletions
+51
View File
@@ -278,3 +278,54 @@ typedef struct _CURDIR
} CURDIR, *PCURDIR;
PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID BaseOfImage);
/**
* The SECTION_IMAGE_INFORMATION structure contains detailed information about an image section.
*/
typedef struct _SECTION_IMAGE_INFORMATION
{
PVOID TransferAddress; // The address of the image entry point function.
ULONG ZeroBits; // The number of high-order address bits that must be zero in the image base address.
SIZE_T MaximumStackSize; // The maximum stack size of threads from the PE file header.
SIZE_T CommittedStackSize; // The initial stack size of threads from the PE file header.
ULONG SubSystemType; // The image subsystem from the PE file header (e.g., Windows GUI, Windows CUI, POSIX).
union
{
struct
{
USHORT SubSystemMinorVersion;
USHORT SubSystemMajorVersion;
};
ULONG SubSystemVersion;
};
union
{
struct
{
USHORT MajorOperatingSystemVersion;
USHORT MinorOperatingSystemVersion;
};
ULONG OperatingSystemVersion;
};
USHORT ImageCharacteristics; // The image characteristics from the PE file header.
USHORT DllCharacteristics; // The DLL characteristics flags (e.g., ASLR, NX compatibility).
USHORT Machine; // The image architecture (e.g., x86, x64, ARM).
BOOLEAN ImageContainsCode; // The image contains native executable code.
union
{
UCHAR ImageFlags;
struct
{
UCHAR ComPlusNativeReady : 1; // The image contains precompiled .NET assembly generated by NGEN (Native Image Generator).
UCHAR ComPlusILOnly : 1; // the image contains only Microsoft Intermediate Language (IL) assembly.
UCHAR ImageDynamicallyRelocated : 1; // The image was mapped using a random base address rather than the preferred base address.
UCHAR ImageMappedFlat : 1; // The image was mapped using a single contiguous region, rather than separate regions for each section.
UCHAR BaseBelow4gb : 1; // The image was mapped using a base address below the 4 GB boundary.
UCHAR ComPlusPrefer32bit : 1; // The image prefers to run as a 32-bit process, even on a 64-bit system.
UCHAR Reserved : 2;
};
};
ULONG LoaderFlags; // Reserved by ntdll.dll for the Windows loader.
ULONG ImageFileSize; // The size of the image, in bytes, including all headers.
ULONG CheckSum; // The image file checksum, from the PE optional header.
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;
+87 -40
View File
@@ -1,7 +1,10 @@
#include "wm.h"
#include "common/mallocHelper.h"
#include "common/windows/version.h"
#include "common/io.h"
#include "common/processing.h"
#include "common/windows/nt.h"
#include "common/windows/unicode.h"
#include "common/windows/version.h"
#include <stdalign.h>
#include <windows.h>
@@ -10,7 +13,15 @@
#include <shlobj.h>
#include <softpub.h>
bool isProcessTrusted(DWORD processId, UNICODE_STRING* buffer, size_t bufSize)
typedef enum {
FF_PROCESS_TYPE_NONE,
FF_PROCESS_TYPE_SIGNED = 1 << 0,
FF_PROCESS_TYPE_WINDOWS_STORE = 1 << 1,
FF_PROCESS_TYPE_GUI = 1 << 2,
FF_PROCESS_TYPE_CUI = 1 << 3,
} FFProcessType;
bool isProcessTrusted(DWORD processId, FFProcessType processType, UNICODE_STRING* buffer, size_t bufSize)
{
FF_AUTO_CLOSE_FD HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId);
if (!hProcess)
@@ -21,51 +32,72 @@ bool isProcessTrusted(DWORD processId, UNICODE_STRING* buffer, size_t bufSize)
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)
if (processType & FF_PROCESS_TYPE_WINDOWS_STORE)
{
PWSTR pPath = NULL;
if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &pPath)))
static wchar_t windowsAppsPath[MAX_PATH];
static uint32_t windowsAppsPathLen;
if (windowsAppsPathLen == 0)
{
windowsAppsPathLen = (uint32_t) wcslen(pPath);
memcpy(windowsAppsPath, pPath, windowsAppsPathLen * sizeof(wchar_t));
memcpy(windowsAppsPath + windowsAppsPathLen, L"\\WindowsApps\\", sizeof(L"\\WindowsApps\\"));
windowsAppsPathLen += strlen("\\WindowsApps\\");
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);
}
else
{
windowsAppsPathLen = -1u;
}
CoTaskMemFree(pPath);
if (windowsAppsPathLen != -1u &&
buffer->Length > windowsAppsPathLen * sizeof(wchar_t) &&
_wcsnicmp(buffer->Buffer, windowsAppsPath, windowsAppsPathLen) != 0
) return false;
}
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,
};
if (processType & FF_PROCESS_TYPE_SIGNED)
{
WINTRUST_FILE_INFO fileInfo = {
.cbStruct = sizeof(fileInfo),
.pcwszFilePath = buffer->Buffer,
};
GUID actionID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
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,
};
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);
LONG status = WinVerifyTrustEx(NULL, &actionID, &trustData);
trustData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(NULL, &actionID, &trustData);
return status == ERROR_SUCCESS;
if (status != ERROR_SUCCESS)
return false;
}
if (processType & (FF_PROCESS_TYPE_GUI | FF_PROCESS_TYPE_CUI))
{
SECTION_IMAGE_INFORMATION info = {};
if(!NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size)) ||
size != sizeof(info)) return false;
if ((processType & FF_PROCESS_TYPE_GUI) && info.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI)
return false;
if ((processType & FF_PROCESS_TYPE_CUI) && info.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI)
return false;
}
return true;
}
const char* ffDetectWMPlugin(FFstrbuf* pluginName)
@@ -98,7 +130,7 @@ const char* ffDetectWMPlugin(FFstrbuf* pluginName)
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))
isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_WINDOWS_STORE | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer))
) {
if (ffGetFileVersion(filePath->Buffer, NULL, pluginName))
ffStrbufPrependS(pluginName, "FancyWM ");
@@ -108,7 +140,7 @@ const char* ffDetectWMPlugin(FFstrbuf* pluginName)
}
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))
isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_SIGNED | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer))
) {
if (ffGetFileVersion(filePath->Buffer, NULL, pluginName))
ffStrbufPrependS(pluginName, "GlazeWM ");
@@ -116,6 +148,21 @@ const char* ffDetectWMPlugin(FFstrbuf* pluginName)
ffStrbufSetStatic(pluginName, "GlazeWM");
break;
}
else if (ptr->ImageName.Length == strlen("komorebi.exe") * sizeof(wchar_t) &&
memcmp(ptr->ImageName.Buffer, L"komorebi.exe", ptr->ImageName.Length) == 0 &&
isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_CUI, filePath, sizeof(buffer))
) {
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateNWS(filePath->Length / sizeof(wchar_t), filePath->Buffer);
if (ffProcessAppendStdOut(pluginName, (char *const[]) {
path.chars,
"--version",
NULL,
}) == NULL)
ffStrbufSubstrBeforeFirstC(pluginName, '\n');
else
ffStrbufSetStatic(pluginName, "Komorebi");
break;
}
}
return NULL;