From 33f319938387aba9a9414ea8740479032ea79452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 00:41:02 +0800 Subject: [PATCH] Host / Chassis (Windows): parse SMBIOS data directly --- CMakeLists.txt | 4 +- src/detection/chassis/chassis.c | 4 +- src/detection/chassis/chassis_windows.c | 47 +++++++++++++++ src/detection/chassis/chassis_windows.cpp | 73 ----------------------- src/detection/host/host_windows.c | 68 +++++++++++++++++++++ src/detection/host/host_windows.cpp | 49 --------------- src/util/smbiosHelper.c | 18 ++++++ src/util/smbiosHelper.h | 60 +++++++++++++++++++ 8 files changed, 197 insertions(+), 126 deletions(-) create mode 100644 src/detection/chassis/chassis_windows.c delete mode 100644 src/detection/chassis/chassis_windows.cpp create mode 100644 src/detection/host/host_windows.c delete mode 100644 src/detection/host/host_windows.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a0babff5..357faaaf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,7 +621,7 @@ elseif(WIN32) src/detection/bluetooth/bluetooth_windows.c src/detection/board/board_windows.c src/detection/brightness/brightness_windows.cpp - src/detection/chassis/chassis_windows.cpp + src/detection/chassis/chassis_windows.c src/detection/cpu/cpu_windows.c src/detection/cpuusage/cpuusage_windows.c src/detection/cursor/cursor_windows.c @@ -631,7 +631,7 @@ elseif(WIN32) src/detection/displayserver/displayserver_windows.c src/detection/font/font_windows.c src/detection/gpu/gpu_windows.c - src/detection/host/host_windows.cpp + src/detection/host/host_windows.c src/detection/icons/icons_windows.c src/detection/libc/libc_windows.cpp src/detection/lm/lm_nosupport.c diff --git a/src/detection/chassis/chassis.c b/src/detection/chassis/chassis.c index f2ebc2da1..9e76bcfc8 100644 --- a/src/detection/chassis/chassis.c +++ b/src/detection/chassis/chassis.c @@ -2,9 +2,9 @@ const char* ffChassisTypeToString(uint32_t type) { - // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf + // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf // 7.4.1 System Enclosure or Chassis Types - switch (type) + switch (type & 0b01111111) { case 0x01: return "Other"; case 0x02: return "Unknown"; diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c new file mode 100644 index 000000000..54dbad81f --- /dev/null +++ b/src/detection/chassis/chassis_windows.c @@ -0,0 +1,47 @@ +#include "chassis.h" +#include "util/smbiosHelper.h" + +// 7.4 +typedef struct FFSmbiosSystemEnclosure +{ + uint8_t Manufacturer; + uint8_t Type; + uint8_t Version; + uint8_t SerialNumber; + uint8_t AssetTagNumber; + uint8_t BootupState; + uint8_t PowerSupplyState; + uint8_t ThermalState; + uint8_t SecurityStatus; + uint32_t OEMDefined; + uint8_t Height; + uint8_t NumberOfPowerCords; +} FFSmbiosSystemEnclosure; + +const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options) +{ + const FFRawSmbiosData* data = ffGetSmbiosData(); + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) data->SMBIOSTableData; + (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type < FF_SMBIOS_TYPE_LAST; + header = ffSmbiosSkipLastStr(header) + ) + { + if (header->Type != FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE) + continue; + + const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) header->Data; + const char* strings = (const char*) header + header->Length; + + ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&result->vendor); + ffStrbufSetStatic(&result->version, ffSmbiosLocateString(strings, data->Version)); + ffCleanUpSmbiosValue(&result->version); + ffStrbufSetStatic(&result->type, ffChassisTypeToString(data->Type)); + + return NULL; + } + + return "System enclosure is not found in SMBIOS data"; +} diff --git a/src/detection/chassis/chassis_windows.cpp b/src/detection/chassis/chassis_windows.cpp deleted file mode 100644 index 9a3d37fcc..000000000 --- a/src/detection/chassis/chassis_windows.cpp +++ /dev/null @@ -1,73 +0,0 @@ -extern "C" { -#include "chassis.h" -#include "util/windows/registry.h" -#include "util/smbiosHelper.h" -} -#include "util/windows/unicode.hpp" -#include "util/windows/wmi.hpp" - -static const char* detectWithRegistry(FFChassisResult* result) -{ - FF_HKEY_AUTO_DESTROY hKey = NULL; - if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) // SMBIOS - return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed"; - - uint32_t type = 0; - if(!ffRegReadUint(hKey, L"EnclosureType", &type, NULL)) - return "\"HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\EnclosureType\" doesn't exist"; - - const char* typeStr = ffChassisTypeToString(type); - if(!typeStr) - return "Unknown chassis type"; - - ffStrbufAppendS(&result->type, typeStr); - return NULL; -} - -FF_MAYBE_UNUSED static const char* detectWithWmi(FFChassisResult* result) -{ - FFWmiQuery query(L"SELECT Version, ChassisTypes, Manufacturer FROM Win32_SystemEnclosure"); - if (!query) - return "Query WMI service failed"; - - if (FFWmiRecord record = query.next()) - { - if (auto vtProp = record.get(L"ChassisTypes")) - { - auto [arr, len] = vtProp.get>(); - if(len == 0) - return "ChassisTypes contain no data"; - for (uint32_t i = 0; i < len; ++i) - { - if (i > 0) - ffStrbufAppendS(&result->type, ", "); - ffStrbufAppendS(&result->type, ffChassisTypeToString((uint32_t) arr[i])); - } - } - else - return "Get ChassisTypes failed"; - - if (auto vtProp = record.get(L"Version")) - { - ffStrbufSetWSV(&result->version, vtProp.get()); - ffCleanUpSmbiosValue(&result->version); - } - - if (auto vtProp = record.get(L"Manufacturer")) - { - ffStrbufSetWSV(&result->vendor, vtProp.get()); - ffCleanUpSmbiosValue(&result->vendor); - } - - return NULL; - } - return "No WMI result returned"; -} - -extern "C" -const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options) -{ - if (options->useWmi) - return detectWithWmi(result); - return detectWithRegistry(result); -} diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c new file mode 100644 index 000000000..6b217fa99 --- /dev/null +++ b/src/detection/host/host_windows.c @@ -0,0 +1,68 @@ +#include "host.h" +#include "util/smbiosHelper.h" + +typedef struct FFSmbiosSystemInfo +{ + uint8_t Manufacturer; + uint8_t ProductName; + uint8_t Version; + uint8_t SerialNumber; + struct { + uint32_t TimeLow; + uint16_t TimeMid; + uint16_t TimeHighAndVersion; + uint8_t ClockSeqHiAndReserved; + uint8_t ClockSeqLow; + uint8_t Node[6]; + } UUID; + uint8_t WakeUpType; + uint8_t SKUNumber; + uint8_t Family; +} FFSmbiosSystemInfo; + +const char* ffDetectHost(FFHostResult* host, FFHostOptions* options) +{ + const FFRawSmbiosData* fullData = ffGetSmbiosData(); + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) fullData->SMBIOSTableData; + (const uint8_t*) header < fullData->SMBIOSTableData + fullData->Length && header->Type < FF_SMBIOS_TYPE_LAST; + header = ffSmbiosSkipLastStr(header) + ) + { + if (header->Type != FF_SMBIOS_TYPE_SYSTEM_INFO) + continue; + + const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) header->Data; + const char* strings = (const char*) header + header->Length; + + ffStrbufSetStatic(&host->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&host->vendor); + ffStrbufSetStatic(&host->name, ffSmbiosLocateString(strings, data->ProductName)); + ffCleanUpSmbiosValue(&host->name); + ffStrbufSetStatic(&host->version, ffSmbiosLocateString(strings, data->Version)); + ffCleanUpSmbiosValue(&host->version); + ffStrbufSetStatic(&host->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&host->serial); + + if (header->Length > 0x08) + { + // Order? + ffStrbufSetF(&host->uuid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + data->UUID.TimeLow, data->UUID.TimeMid, data->UUID.TimeHighAndVersion, + data->UUID.ClockSeqHiAndReserved, data->UUID.ClockSeqLow, + data->UUID.Node[0], data->UUID.Node[1], data->UUID.Node[2], data->UUID.Node[3], data->UUID.Node[4], data->UUID.Node[5]); + } + if (header->Length > 0x19) + { + ffStrbufSetStatic(&host->family, ffSmbiosLocateString(strings, data->Family)); + ffCleanUpSmbiosValue(&host->family); + ffStrbufSetStatic(&host->sku, ffSmbiosLocateString(strings, data->SKUNumber)); + ffCleanUpSmbiosValue(&host->sku); + } + + return NULL; + } + + return "System information is not found in SMBIOS data"; +} diff --git a/src/detection/host/host_windows.cpp b/src/detection/host/host_windows.cpp deleted file mode 100644 index 2d3ab2040..000000000 --- a/src/detection/host/host_windows.cpp +++ /dev/null @@ -1,49 +0,0 @@ -extern "C" -{ -#include "host.h" -#include "util/windows/registry.h" -#include "util/smbiosHelper.h" -} -#include "util/windows/wmi.hpp" -#include "util/windows/unicode.hpp" - -const char* detectWithWmi(FFHostResult* host) -{ - FFWmiQuery query(L"SELECT IdentifyingNumber, UUID FROM Win32_ComputerSystemProduct", nullptr, FFWmiNamespace::CIMV2); - if(!query) - return "Query WMI service failed"; - - if (FFWmiRecord record = query.next()) - { - if (auto identifyingNumber = record.get(L"IdentifyingNumber")) - ffStrbufSetWSV(&host->serial, identifyingNumber.get()); - if (auto uuid = record.get(L"UUID")) - ffStrbufSetWSV(&host->uuid, uuid.get()); - return NULL; - } - return "No WMI result returned"; -} - -const char* ffDetectHost(FFHostResult* host, FFHostOptions* options) -{ - FF_HKEY_AUTO_DESTROY hKey = NULL; - - if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) - return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed"; - - ffRegReadStrbuf(hKey, L"SystemProductName", &host->name, NULL); - ffCleanUpSmbiosValue(&host->name); - ffRegReadStrbuf(hKey, L"SystemFamily", &host->family, NULL); - ffCleanUpSmbiosValue(&host->family); - ffRegReadStrbuf(hKey, L"SystemVersion", &host->version, NULL); - ffCleanUpSmbiosValue(&host->version); - ffRegReadStrbuf(hKey, L"SystemSKU", &host->sku, NULL); - ffCleanUpSmbiosValue(&host->sku); - ffRegReadStrbuf(hKey, L"SystemManufacturer", &host->vendor, NULL); - ffCleanUpSmbiosValue(&host->vendor); - - if (options->useWmi) - detectWithWmi(host); - - return NULL; -} diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 5f958fc27..718d56cfc 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -47,4 +47,22 @@ void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* ffStrbufClear(buffer); } +#elif defined(_WIN32) +#include + +#pragma GCC diagnostic ignored "-Wmultichar" + +const FFRawSmbiosData* ffGetSmbiosData() +{ + static FFRawSmbiosData* buffer; + if (!buffer) + { + const DWORD signature = 'RSMB'; + uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0); + assert(bufSize > sizeof(FFRawSmbiosData)); + buffer = (FFRawSmbiosData*) malloc(bufSize); + GetSystemFirmwareTable(signature, 0, buffer, bufSize); + } + return buffer; +} #endif diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index f129af5ac..bfb7c97af 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -14,6 +14,66 @@ static inline void ffCleanUpSmbiosValue(FFstrbuf* value) #ifdef __linux__ void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer); +#elif defined(_WIN32) +// https://github.com/KunYi/DumpSMBIOS +// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf + +typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t +{ + FF_SMBIOS_TYPE_BIOS = 0, + FF_SMBIOS_TYPE_SYSTEM_INFO = 1, + FF_SMBIOS_TYPE_BASEBOARD_INFO = 2, + FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE = 3, + FF_SMBIOS_TYPE_PROCESSOR_INFO = 4, + FF_SMBIOS_TYPE_MEMORY_MODULE_INFO = 6, + FF_SMBIOS_TYPE_CACHE_INFO = 7, + FF_SMBIOS_TYPE_OEM_STRING = 11, + FF_SMBIOS_TYPE_MEMORY_DEVICE = 17, + FF_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS = 19, + FF_SMBIOS_TYPE_BUILTIN_POINT_DEVICE = 21, + FF_SMBIOS_TYPE_PORTABLE_BATTERY = 22, + FF_SMBIOS_TYPE_LAST = 127, +} FFSmbiosType; +static_assert(sizeof(FFSmbiosType) == 1, "FFSmbiosType should be 1 byte"); + +typedef struct FFSmbiosHeader +{ + FFSmbiosType Type; + uint8_t Length; + uint16_t Handle; + uint8_t Data[]; +} FFSmbiosHeader; +static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes"); + +typedef struct FFRawSmbiosData +{ + uint8_t Used20CallingMethod; + uint8_t SMBIOSMajorVersion; + uint8_t SMBIOSMinorVersion; + uint8_t DmiRevision; + uint32_t Length; + uint8_t SMBIOSTableData[]; +} FFRawSmbiosData; + +static inline const char* ffSmbiosLocateString(const char* start, uint8_t index /* start from 1 */) +{ + if (index == 0 || *start == '\0') + return NULL; + while (--index) + start += strlen(start) + 1; + return start; +} + +static inline const FFSmbiosHeader* ffSmbiosSkipLastStr(const FFSmbiosHeader* header) +{ + const char* p = ((const char*) header) + header->Length; + while (*p) + p += strlen(p) + 1; + + return (const FFSmbiosHeader*) (p + 1); +} + +const FFRawSmbiosData* ffGetSmbiosData(); #endif #endif