From 06a8f12d6adfc439f8e9e7f3a4872a7d70fe6887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 15 May 2024 20:39:22 +0800 Subject: [PATCH] Bios (Windows): detect secure boot state & boot manager Boot manager detection requires Administrator privilege to work --- src/detection/bios/bios_linux.c | 46 +----------------- src/detection/bios/bios_windows.c | 79 +++++++++++++++++++++++++++++++ src/detection/bios/efi.h | 47 ++++++++++++++++++ 3 files changed, 127 insertions(+), 45 deletions(-) create mode 100644 src/detection/bios/efi.h diff --git a/src/detection/bios/bios_linux.c b/src/detection/bios/bios_linux.c index ecb009082..08056d9a8 100644 --- a/src/detection/bios/bios_linux.c +++ b/src/detection/bios/bios_linux.c @@ -1,55 +1,11 @@ #include "bios.h" #include "common/io/io.h" #include "util/smbiosHelper.h" +#include "efi.h" #include -// https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#generic-device-path-structures -typedef struct ffEfiDevicePathProtocol -{ - uint8_t Type; - uint8_t SubType; - uint16_t Length; - uint8_t SpecificDevicePathData[]; -} ffEfiDevicePathProtocol; - -// https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html#load-options -typedef struct FFEfiLoadOption -{ - uint32_t Attributes; - uint16_t FilePathListLength; - uint16_t Description[]; - // ffEfiDevicePathProtocol FilePathList[]; - // uint8_t OptionalData[]; -} FFEfiLoadOption; - -uint8_t ffEvBits(uint16_t val, uint8_t mask, uint8_t shift) -{ - return (uint8_t) ((val & (mask << shift)) >> shift); -} - -static void ffUcs2ToUtf8(const uint16_t *const chars, FFstrbuf* result) -{ - for (uint32_t i = 0; chars[i]; i++) - { - if (chars[i] <= 0x007f) - ffStrbufAppendC(result, (char) chars[i]); - else if (chars[i] > 0x007f && chars[i] <= 0x07ff) - { - ffStrbufAppendC(result, (char) (0xc0 | ffEvBits(chars[i], 0x1f, 6))); - ffStrbufAppendC(result, (char) (0x80 | ffEvBits(chars[i], 0x3f, 0))); - } - else - { - ffStrbufAppendC(result, (char) (0xe0 | ffEvBits(chars[i], 0xf, 12))); - ffStrbufAppendC(result, (char) (0x80 | ffEvBits(chars[i], 0x3f, 6))); - ffStrbufAppendC(result, (char) (0x80 | ffEvBits(chars[i], 0x3f, 0))); - } - } -} - #define FF_EFIVARS_PATH_PREFIX "/sys/firmware/efi/efivars/" -#define FF_EFI_GLOBAL_GUID "8be4df61-93ca-11d2-aa0d-00e098032b8c" const char *detectBootmgr(FFstrbuf *result) { diff --git a/src/detection/bios/bios_windows.c b/src/detection/bios/bios_windows.c index d8a305493..d1bbd4e4f 100644 --- a/src/detection/bios/bios_windows.c +++ b/src/detection/bios/bios_windows.c @@ -1,8 +1,11 @@ #include "bios.h" #include "util/smbiosHelper.h" +#include "util/windows/registry.h" +#include "efi.h" #include #include +#include typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION { @@ -51,6 +54,76 @@ typedef struct FFSmbiosBios static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18, "FFSmbiosBios: Wrong struct alignment"); +const char* enablePrivilege(const wchar_t* privilege) +{ + HANDLE token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) + return "OpenProcessToken() failed"; + + TOKEN_PRIVILEGES tp = { + .PrivilegeCount = 1, + .Privileges = { + (LUID_AND_ATTRIBUTES) { .Attributes = SE_PRIVILEGE_ENABLED } + }, + }; + if (!LookupPrivilegeValueW(NULL, privilege, &tp.Privileges[0].Luid)) + return "LookupPrivilegeValue() failed"; + + if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), NULL, NULL)) + return "AdjustTokenPrivileges() failed"; + + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) + return "The token does not have the specified privilege"; + + return NULL; +} + +const char *detectBootmgr(FFstrbuf *result) +{ + if (enablePrivilege(L"SeSystemEnvironmentPrivilege") != NULL) + return "Failed to enable SeSystemEnvironmentPrivilege"; + + uint16_t value; + if (GetFirmwareEnvironmentVariableW(L"BootCurrent", L"{" FF_EFI_GLOBAL_GUID L"}", &value, sizeof(value)) != 2) + return "GetFirmwareEnvironmentVariableW(BootCurrent) failed"; + + uint8_t buffer[2048]; + wchar_t key[16]; + wsprintfW(key, L"Boot%04X", value); + uint32_t size = GetFirmwareEnvironmentVariableW(key, L"{" FF_EFI_GLOBAL_GUID L"}", buffer, sizeof(buffer)); + if (size < sizeof(FFEfiLoadOption) || size == sizeof(buffer)) + return "GetFirmwareEnvironmentVariableW(Boot####) failed"; + + FFEfiLoadOption *efiOption = (FFEfiLoadOption *)buffer; + uint32_t descLen = 0; + while (efiOption->Description[descLen]) ++descLen; + + for ( + ffEfiDevicePathProtocol* filePathList = (void*) &efiOption->Description[descLen + 1]; + filePathList->Type != 0x7F; // End of Hardware Device Path + filePathList = (void*) ((uint8_t*) filePathList + filePathList->Length)) + { + if (filePathList->Type == 4 && filePathList->SubType == 4) + { + // https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#file-path-media-device-path + ffUcs2ToUtf8((uint16_t*) filePathList->SpecificDevicePathData, result); + return NULL; + } + } + + if (!result->length) ffUcs2ToUtf8(efiOption->Description, result); + return NULL; +} + +const char *detectSecureBoot(bool* result) +{ + DWORD uefiSecureBootEnabled = 0, bufSize = 0; + if (RegGetValueW(HKEY_LOCAL_MACHINE, L"SYSTEM\\ControlSet001\\Control\\SecureBoot\\State", L"UEFISecureBootEnabled", RRF_RT_REG_DWORD, NULL, &uefiSecureBootEnabled, &bufSize) != ERROR_SUCCESS) + return "RegGetValueW(HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\SecureBoot\\State) failed"; + *result = !!uefiSecureBootEnabled; + return NULL; +} + const char* ffDetectBios(FFBiosResult* bios) { const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); @@ -84,6 +157,12 @@ const char* ffDetectBios(FFBiosResult* bios) case FirmwareTypeUefi: ffStrbufSetStatic(&bios->type, "UEFI"); break; default: break; } + + if (sbei.FirmwareType == FirmwareTypeUefi) + { + detectSecureBoot(&bios->secureBoot); + detectBootmgr(&bios->bootmgr); + } } return NULL; diff --git a/src/detection/bios/efi.h b/src/detection/bios/efi.h new file mode 100644 index 000000000..3878954bd --- /dev/null +++ b/src/detection/bios/efi.h @@ -0,0 +1,47 @@ +#include "fastfetch.h" + +// https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#generic-device-path-structures +typedef struct ffEfiDevicePathProtocol +{ + uint8_t Type; + uint8_t SubType; + uint16_t Length; + uint8_t SpecificDevicePathData[]; +} ffEfiDevicePathProtocol; + +// https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html#load-options +typedef struct FFEfiLoadOption +{ + uint32_t Attributes; + uint16_t FilePathListLength; + uint16_t Description[]; + // ffEfiDevicePathProtocol FilePathList[]; + // uint8_t OptionalData[]; +} FFEfiLoadOption; + +uint8_t ffEvBits(uint16_t val, uint8_t mask, uint8_t shift) +{ + return (uint8_t) ((val & (mask << shift)) >> shift); +} + +static void ffUcs2ToUtf8(const uint16_t *const chars, FFstrbuf* result) +{ + for (uint32_t i = 0; chars[i]; i++) + { + if (chars[i] <= 0x007f) + ffStrbufAppendC(result, (char) chars[i]); + else if (chars[i] > 0x007f && chars[i] <= 0x07ff) + { + ffStrbufAppendC(result, (char) (0xc0 | ffEvBits(chars[i], 0x1f, 6))); + ffStrbufAppendC(result, (char) (0x80 | ffEvBits(chars[i], 0x3f, 0))); + } + else + { + ffStrbufAppendC(result, (char) (0xe0 | ffEvBits(chars[i], 0xf, 12))); + ffStrbufAppendC(result, (char) (0x80 | ffEvBits(chars[i], 0x3f, 6))); + ffStrbufAppendC(result, (char) (0x80 | ffEvBits(chars[i], 0x3f, 0))); + } + } +} + +#define FF_EFI_GLOBAL_GUID "8be4df61-93ca-11d2-aa0d-00e098032b8c"