Last active
October 29, 2023 11:19
-
-
Save vadimpiven/618b720324e9f54c01075fcb8675f2c4 to your computer and use it in GitHub Desktop.
Get SMBIOS UUID (WinAPI, C++ 17, Boost)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
// MIT Software License: https://opensource.org/licenses/MIT | |
// Copyright Vadim Piven <[email protected]> | |
#include <boost/uuid/uuid.hpp> | |
#include <boost/uuid/uuid_io.hpp> | |
#include <algorithm> | |
#include <functional> | |
#include <iterator> | |
#include <string> | |
#include <vector> | |
#include <sysinfoapi.h> | |
#include <Windows.h> | |
[[nodiscard]] std::string GetBiosUuid() | |
{ | |
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable | |
struct RawSMBIOSData | |
{ | |
BYTE Used20CallingMethod; | |
BYTE SMBIOSMajorVersion; | |
BYTE SMBIOSMinorVersion; | |
BYTE DmiRevision; | |
DWORD Length; | |
BYTE SMBIOSTableData[1]; | |
}; | |
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf | |
enum class StructureType : BYTE | |
{ | |
SystemInformation = 0x01, | |
}; | |
// para 6.1.2 | |
struct Header | |
{ | |
StructureType type; | |
BYTE length; | |
WORD handle; | |
}; | |
// para 7.2 | |
struct SystemInformation : Header | |
{ | |
BYTE manufacturer; | |
BYTE productName; | |
BYTE version; | |
BYTE serialNumber; | |
BYTE uuid[16]; | |
}; | |
// para 6.1.1 | |
BYTE constexpr Terminator[] = {0x00, 0x00}; | |
std::vector<BYTE> buffer(::GetSystemFirmwareTable('RSMB', 0, nullptr, 0)); | |
(void)::GetSystemFirmwareTable('RSMB', 0, buffer.data(), static_cast<DWORD>(buffer.size())); | |
const auto rawData = reinterpret_cast<RawSMBIOSData const *>(buffer.data()); | |
for (auto it = rawData->SMBIOSTableData, itEnd = it + rawData->Length; it < itEnd;) | |
{ | |
switch (auto const header = reinterpret_cast<Header const *>(it); header->type) | |
{ | |
default: // skip structure | |
{ | |
it = std::search(it + header->length, itEnd, std::begin(Terminator), std::end(Terminator)) | |
+ sizeof(Terminator); | |
continue; | |
} | |
case StructureType::SystemInformation: | |
{ | |
if (header->length >= sizeof(SystemInformation)) // UUID field supported on this SMBIOS version | |
{ | |
auto const uuid = static_cast<SystemInformation const *>(header)->uuid; | |
auto const correctUuid = boost::uuids::uuid{{ // byte order from para 7.2.1 | |
uuid[0x3], uuid[0x2], uuid[0x1], uuid[0x0], uuid[0x5], uuid[0x4], uuid[0x7], uuid[0x6], | |
uuid[0x8],uuid[0x9], uuid[0xA], uuid[0xB], uuid[0xC], uuid[0xD], uuid[0xE], uuid[0xF] | |
}}; | |
if (auto const begin = std::begin(correctUuid.data), end = std::end(correctUuid.data); | |
!std::all_of(begin, end, std::bind_front(std::equal_to(), 0x00)) && // UUID missing | |
!std::all_of(begin, end, std::bind_front(std::equal_to(), 0xFF))) // UUID missing but can be set | |
{ | |
return boost::uuids::to_string(correctUuid); | |
} | |
} | |
break; | |
} | |
} | |
break; | |
} | |
return {}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Credits to https://gist.github.com/neacsum/5199627fec4143c1e8d553d38dabed68 - that helped a lot!