master ohmu/fastfetch-openbsd / src / detection / initsystem / initsystem_windows.c
ohmu  ·  2026-10-15
 1#include "initsystem.h"
 2#include "common/debug.h"
 3#include "common/windows/unicode.h"
 4#include "common/windows/nt.h"
 5#include "common/windows/version.h"
 6
 7#include <ntstatus.h>
 8#include <winternl.h>
 9#include <wchar.h>
10
11static bool fillResult(FFInitSystemResult* result, uint32_t ppid, uint32_t pid, uint16_t len, PCWSTR name) {
12    if (ppid != 4 /* System */ || len <= 4 || _wcsnicmp(name + len - 4, L".exe", 4) != 0) { // smss.exe
13        return false;
14    }
15    result->pid = pid;
16    // We have no permission to open the process for querying the full information
17    wchar_t exePath[MAX_PATH];
18    _snwprintf(exePath, ARRAY_SIZE(exePath), L"%ls\\system32\\%.*ls", (const wchar_t*) SharedUserData->NtSystemRoot, len, name);
19    ffGetFileVersion(exePath, NULL, &result->version);
20    ffStrbufSetWS(&result->exe, exePath);
21    ffStrbufSetNWS(&result->name, len - 4, name);
22    return true;
23}
24
25const char* ffDetectInitSystem(FFInitSystemResult* result) {
26    if (ffIsSystemBasicProcessInfoAvailable()) {
27        // SYSTEM_BASICPROCESS_INFORMATION entries are much smaller than SYSTEM_PROCESS_INFORMATION ones,
28        // so a modest buffer should be enough to contain all processes
29        SYSTEM_BASICPROCESS_INFORMATION buffer[1024] = {};
30        NTSTATUS status = NtQuerySystemInformation(SystemBasicProcessInformation, buffer, sizeof(buffer), NULL);
31        if (status != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(status)) {
32            goto fallback;
33        }
34        for (auto ptr = buffer; ;ptr = (PSYSTEM_BASICPROCESS_INFORMATION) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
35            assert(ptr >= buffer && (uint8_t*) ptr < (uint8_t*) buffer + sizeof(buffer));
36            if (fillResult(result, (uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId,
37                                        (uint32_t)(uintptr_t) ptr->UniqueProcessId,
38                                        ptr->ImageName.Length / sizeof(*ptr->ImageName.Buffer),
39                                        ptr->ImageName.Buffer)) {
40                return nullptr;
41            }
42            // The last process in the list always has a NextEntryOffset of 0, even if the buffer was truncated.
43            if (!ptr->NextEntryOffset) {
44                return "Could not find init system process";
45            }
46        }
47    }
48
49fallback:
50    {
51        // We only need to find the first user process, so 1024 entries should be enough
52        SYSTEM_PROCESS_INFORMATION buffer[1024] = {};
53        ULONG size = sizeof(buffer);
54        NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, buffer, size, &size);
55        if (status != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(status)) {
56            FF_DEBUG("NtQuerySystemInformation(SystemProcessInformation) failed: %s", ffDebugNtStatus(status));
57            return "NtQuerySystemInformation(SystemProcessInformation) failed";
58        }
59
60        for (auto ptr = buffer; ; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
61            assert(ptr >= buffer && (uint8_t*) ptr < (uint8_t*) buffer + sizeof(buffer));
62            uint16_t len = ptr->ImageName.Length / sizeof(*ptr->ImageName.Buffer);
63            if (fillResult(result, (uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId,
64                                    (uint32_t)(uintptr_t) ptr->UniqueProcessId, len, ptr->ImageName.Buffer)) {
65                return nullptr;
66            }
67            // The last process in the list always has a NextEntryOffset of 0, even if the buffer was truncated.
68            if (!ptr->NextEntryOffset) {
69                return "Could not find init system process";
70            }
71        }
72    }
73}