Skip to content

Instantly share code, notes, and snippets.

@neacsum
Created November 27, 2021 15:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save neacsum/5199627fec4143c1e8d553d38dabed68 to your computer and use it in GitHub Desktop.
Save neacsum/5199627fec4143c1e8d553d38dabed68 to your computer and use it in GitHub Desktop.
How to Get the BIOS UUID
#include <windows.h>
#include <sysinfoapi.h>
#include "biosuuid.h"
/*!
SMBIOS Structure header as described at
https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.3.0.pdf
(para 6.1.2)
*/
struct dmi_header
{
BYTE type;
BYTE length;
WORD handle;
BYTE data[1];
};
/*
Structure needed to get the SMBIOS table using GetSystemFirmwareTable API.
see 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];
};
/*
Get BIOS UUID in a 16 byte array.
Return true if successful, 0 otherwise
*/
bool biosuuid (unsigned char *uuid)
{
bool result = false;
RawSMBIOSData *smb=nullptr;
BYTE *data;
DWORD size = 0;
// Get size of BIOS table
size = GetSystemFirmwareTable ('RSMB', 0, smb, size);
smb = (RawSMBIOSData*)malloc (size);
// Get BIOS table
GetSystemFirmwareTable ('RSMB', 0, smb, size);
//Go through BIOS structures
data = smb->SMBIOSTableData;
while (data < smb->SMBIOSTableData + smb->Length)
{
BYTE *next;
dmi_header *h = (dmi_header*)data;
if (h->length < 4)
break;
//Search for System Information structure with type 0x01 (see para 7.2)
if (h->type == 0x01 && h->length >= 0x19)
{
data += 0x08; //UUID is at offset 0x08
// check if there is a valid UUID (not all 0x00 or all 0xff)
bool all_zero = true, all_one = true;
for (int i = 0; i < 16 && (all_zero || all_one); i++)
{
if (data[i] != 0x00) all_zero = false;
if (data[i] != 0xFF) all_one = false;
}
if (!all_zero && !all_one)
{
/* As off version 2.6 of the SMBIOS specification, the first 3 fields
of the UUID are supposed to be encoded on little-endian. (para 7.2.1) */
*uuid++ = data[3];
*uuid++ = data[2];
*uuid++ = data[1];
*uuid++ = data[0];
*uuid++ = data[5];
*uuid++ = data[4];
*uuid++ = data[7];
*uuid++ = data[6];
for (int i = 8; i < 16; i++)
*uuid++ = data[i];
result = true;
}
break;
}
//skip over formatted area
next = data + h->length;
//skip over unformatted area of the structure (marker is 0000h)
while (next < smb->SMBIOSTableData + smb->Length && (next[0] != 0 || next[1] != 0))
next++;
next += 2;
data = next;
}
free (smb);
return result;
}
// Retrieve BIOS UUUID. Return true if successful
bool biosuuid (unsigned char *uuid);
/*
Test program for BIOSUUID function
*/
#include <windows.h>
#include <stdio.h>
#include "biosuuid.h"
char *hexbyte (BYTE b, char *ptr)
{
static const char *digits{ "0123456789ABCDEF" };
*ptr++ = digits[b >> 4];
*ptr++ = digits[b & 0x0f];
return ptr;
}
int main (int argc, char **argv)
{
BYTE uuid[16];
if (biosuuid (uuid))
{
char uuid_str[40];
char *ptr = uuid_str;
int i;
for (i = 0; i < 4; i++)
ptr = hexbyte (uuid[i], ptr);
*ptr++ = '-';
for (; i< 6; i++)
ptr = hexbyte (uuid[i], ptr);
*ptr++ = '-';
for (; i < 8; i++)
ptr = hexbyte (uuid[i], ptr);
*ptr++ = '-';
for (; i < 10; i++)
ptr = hexbyte (uuid[i], ptr);
*ptr++ = '-';
for (; i < 16; i++)
ptr = hexbyte (uuid[i], ptr);
*ptr++ = 0;
printf ("BIOS UUID: %s\n", uuid_str);
return 0;
}
fprintf (stderr, "Failed to get BIOS UUID\n");
return 1;
}
@vadimpiven
Copy link

Thanks for providing such a good reference!
I just reworked this to make more readable for C++ guys, may be that would help someone.
Code: https://gist.github.com/vadimpiven/618b720324e9f54c01075fcb8675f2c4

@neacsum
Copy link
Author

neacsum commented Oct 4, 2023

Good stuff! Thanks for letting me now.

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