mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 09:58:03 +02:00
InitSystem: uses SystemBasicProcessInformation if available
This commit is contained in:
+23
-3
@@ -13,6 +13,8 @@ enum {
|
||||
SystemLogicalProcessorAndGroupInformation = 107,
|
||||
SystemBasicPerformanceInformation = 123,
|
||||
SystemSecureBootInformation = 146,
|
||||
SystemBasicProcessInformation = 252,
|
||||
SystemHandleCountInformation = 253,
|
||||
};
|
||||
|
||||
typedef struct _PROCESSOR_POWER_INFORMATION {
|
||||
@@ -206,6 +208,20 @@ typedef struct _SYSTEM_BASIC_PERFORMANCE_INFORMATION {
|
||||
SIZE_T PeakCommitment;
|
||||
} SYSTEM_BASIC_PERFORMANCE_INFORMATION, *PSYSTEM_BASIC_PERFORMANCE_INFORMATION;
|
||||
|
||||
typedef struct _SYSTEM_BASICPROCESS_INFORMATION {
|
||||
ULONG NextEntryOffset;
|
||||
HANDLE UniqueProcessId;
|
||||
HANDLE InheritedFromUniqueProcessId;
|
||||
ULONG64 SequenceNumber;
|
||||
UNICODE_STRING ImageName;
|
||||
} SYSTEM_BASICPROCESS_INFORMATION, *PSYSTEM_BASICPROCESS_INFORMATION;
|
||||
|
||||
typedef struct _SYSTEM_HANDLECOUNT_INFORMATION {
|
||||
ULONG ProcessCount;
|
||||
ULONG ThreadCount;
|
||||
ULONG HandleCount;
|
||||
} SYSTEM_HANDLECOUNT_INFORMATION, *PSYSTEM_HANDLECOUNT_INFORMATION;
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtDelayExecution(_In_ BOOLEAN Alertable, _In_ PLARGE_INTEGER DelayInterval);
|
||||
|
||||
/**
|
||||
@@ -691,15 +707,19 @@ static inline uint64_t ffKSystemTimeToUInt64(const volatile KSYSTEM_TIME* pTime)
|
||||
|
||||
static inline bool ffIsWindows10OrGreater() {
|
||||
#if FF_WIN81_COMPAT
|
||||
return SharedUserData->NtMajorVersion >= 10;
|
||||
return SharedUserData->NtBuildNumber >= 10240;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool ffIsWindows11OrGreater() {
|
||||
return SharedUserData->NtMajorVersion > 10 ||
|
||||
(SharedUserData->NtMajorVersion == 10 && SharedUserData->NtBuildNumber >= 22000);
|
||||
return SharedUserData->NtBuildNumber >= 22000;
|
||||
}
|
||||
|
||||
static inline bool ffIsSystemBasicProcessInfoAvailable() { // Includes HandleCountInformation, which was added together
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation#systembasicprocessinformation
|
||||
return SharedUserData->NtBuildNumber >= 26200; // MSDN says it was added in 26100.4770; ntdoc says 25H2
|
||||
}
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtOpenProcessToken(
|
||||
|
||||
@@ -7,32 +7,65 @@
|
||||
#include <winternl.h>
|
||||
#include <wchar.h>
|
||||
|
||||
static bool fillResult(FFInitSystemResult* result, uint32_t ppid, uint32_t pid, uint16_t len, PCWSTR name) {
|
||||
if (ppid != 4 /* System */ || len <= 4 || _wcsnicmp(name + len - 4, L".exe", 4) != 0) { // smss.exe
|
||||
return false;
|
||||
}
|
||||
result->pid = pid;
|
||||
// We have no permission to open the process for querying the full information
|
||||
wchar_t exePath[MAX_PATH];
|
||||
_snwprintf(exePath, ARRAY_SIZE(exePath), L"%ls\\system32\\%.*ls", (const wchar_t*) SharedUserData->NtSystemRoot, len, name);
|
||||
ffGetFileVersion(exePath, NULL, &result->version);
|
||||
ffStrbufSetWS(&result->exe, exePath);
|
||||
ffStrbufSetNWS(&result->name, len - 4, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectInitSystem(FFInitSystemResult* result) {
|
||||
// We only need to find the first user process, so 1024 entries should be enough
|
||||
SYSTEM_PROCESS_INFORMATION buffer[1024] = {};
|
||||
ULONG size = sizeof(buffer);
|
||||
NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, buffer, size, &size);
|
||||
if (status != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(status)) {
|
||||
return "NtQuerySystemInformation(SystemProcessInformation) failed";
|
||||
if (ffIsSystemBasicProcessInfoAvailable()) {
|
||||
// SYSTEM_BASICPROCESS_INFORMATION entries are much smaller than SYSTEM_PROCESS_INFORMATION ones,
|
||||
// so a modest buffer should be enough to contain all processes
|
||||
SYSTEM_BASICPROCESS_INFORMATION buffer[1024];
|
||||
NTSTATUS status = NtQuerySystemInformation(SystemBasicProcessInformation, buffer, sizeof(buffer), NULL);
|
||||
if (status != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(status)) {
|
||||
goto fallback;
|
||||
}
|
||||
for (auto ptr = buffer; ;ptr = (PSYSTEM_BASICPROCESS_INFORMATION) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
|
||||
assert(ptr >= buffer && (uint8_t*) ptr < (uint8_t*) buffer + sizeof(buffer));
|
||||
if (fillResult(result, (uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId,
|
||||
(uint32_t)(uintptr_t) ptr->UniqueProcessId,
|
||||
ptr->ImageName.Length / sizeof(*ptr->ImageName.Buffer),
|
||||
ptr->ImageName.Buffer)) {
|
||||
return nullptr;
|
||||
}
|
||||
// The last process in the list always has a NextEntryOffset of 0, even if the buffer was truncated.
|
||||
if (!ptr->NextEntryOffset) {
|
||||
return "Could not find init system process";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (SYSTEM_PROCESS_INFORMATION* ptr = buffer; ; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
|
||||
assert(ptr >= buffer && (uint8_t*) ptr < (uint8_t*) buffer + sizeof(buffer));
|
||||
uint16_t len = ptr->ImageName.Length / sizeof(*ptr->ImageName.Buffer);
|
||||
if (ptr->InheritedFromUniqueProcessId == (HANDLE)(uintptr_t) 4 /* System */ &&
|
||||
len > 4 && _wcsnicmp(ptr->ImageName.Buffer + len - 4, L".exe", 4) == 0) { // smss.exe
|
||||
result->pid = (uint32_t)(uintptr_t) ptr->UniqueProcessId;
|
||||
// We have no permission to open the process for querying the full information
|
||||
wchar_t exePath[MAX_PATH];
|
||||
_snwprintf(exePath, ARRAY_SIZE(exePath), L"%ls\\system32\\%.*ls", (const wchar_t*) SharedUserData->NtSystemRoot, len, ptr->ImageName.Buffer);
|
||||
ffGetFileVersion(exePath, NULL, &result->version);
|
||||
ffStrbufSetWS(&result->exe, exePath);
|
||||
ffStrbufSetNWS(&result->name, len - 4, ptr->ImageName.Buffer);
|
||||
return nullptr;
|
||||
fallback:
|
||||
{
|
||||
// We only need to find the first user process, so 1024 entries should be enough
|
||||
SYSTEM_PROCESS_INFORMATION buffer[1024] = {};
|
||||
ULONG size = sizeof(buffer);
|
||||
NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, buffer, size, &size);
|
||||
if (status != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(status)) {
|
||||
return "NtQuerySystemInformation(SystemProcessInformation) failed";
|
||||
}
|
||||
// The last process in the list always has a NextEntryOffset of 0, even if the buffer was truncated.
|
||||
if (!ptr->NextEntryOffset) {
|
||||
return "Could not find init system process";
|
||||
|
||||
for (auto ptr = buffer; ; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
|
||||
assert(ptr >= buffer && (uint8_t*) ptr < (uint8_t*) buffer + sizeof(buffer));
|
||||
uint16_t len = ptr->ImageName.Length / sizeof(*ptr->ImageName.Buffer);
|
||||
if (fillResult(result, (uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId,
|
||||
(uint32_t)(uintptr_t) ptr->UniqueProcessId, len, ptr->ImageName.Buffer)) {
|
||||
return nullptr;
|
||||
}
|
||||
// The last process in the list always has a NextEntryOffset of 0, even if the buffer was truncated.
|
||||
if (!ptr->NextEntryOffset) {
|
||||
return "Could not find init system process";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user