Skip to content

Instantly share code, notes, and snippets.

@vadimpiven
Last active October 29, 2023 11:19
Show Gist options
  • Save vadimpiven/618b720324e9f54c01075fcb8675f2c4 to your computer and use it in GitHub Desktop.
Save vadimpiven/618b720324e9f54c01075fcb8675f2c4 to your computer and use it in GitHub Desktop.
Get SMBIOS UUID (WinAPI, C++ 17, Boost)
// SPDX-License-Identifier: MIT
// MIT Software License: https://opensource.org/licenses/MIT
// Copyright Vadim Piven <vadim@piven.tech>
#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 {};
}
@vadimpiven
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment