Generate the same computer hardware id. (CHID) like computerhardwareids.exe from Windows SDK

1.4k views Asked by At

INTRODUCTION

This thread should be the ending chapter for this first thread from 2014 and this second one from 2017.

To cut the story short, you simply need to know that the Microsoft Windows SDK includes a program called computerhardwareids.exe, which, as its name suggests, it generates (several) hardware identifiers for the computer, and I would like to replicate the CHID algorithm using .NET to generate the same identifiers as this program generates.

The list of CHIDS that this program can generate on Windows 10, which is the O.S that I'm using, is listed here:

  1. HardwareID-0 Manufacturer + Family + Product Name + SKU Number + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
  2. HardwareID-1 Manufacturer + Family + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
  3. HardwareID-2 Manufacturer + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
  4. HardwareID-3 Manufacturer + Family + Product Name + SKU Number + Baseboard Manufacturer + Baseboard Product
  5. HardwareID-4 Manufacturer + Family + Product Name + SKU Number
  6. HardwareID-5 Manufacturer + Family + Product Name
  7. HardwareID-6 Manufacturer + SKU Number + Baseboard Manufacturer + Baseboard Product
  8. HardwareID-7 Manufacturer + SKU Number
  9. HardwareID-8 Manufacturer + Product Name + Baseboard Manufacturer + Baseboard Product
  10. HardwareID-9 Manufacturer + Product Name
  11. HardwareID-10 Manufacturer + Family + Baseboard Manufacturer + Baseboard Product
  12. HardwareID-11 Manufacturer + Family
  13. HardwareID-12 Manufacturer + Enclosure Type
  14. HardwareID-13 Manufacturer + Baseboard Manufacturer + Baseboard Product
  15. HardwareID-14 Manufacturer

PROBLEM

I managed to replicate all hardware ids except: 0, 1, 2 and 12

I found that these four problematic identifiers have in common that they are the only which contains numeric values to append to the string with which to generate the UUID. See the table in this link or read this list:

  • Name | Length | Type

  • System BIOS Major Release | BYTE |Varies

  • System BIOS Minor Release | BYTE | Varies

  • Enclosure type | BYTE | Varies

I think this is a clear sign that I don't know how to treat those numerical values when building the string with which to generate the UUID.

QUESTION

I don't know in which WMI class to find the Enclosure Type value, but it doesn't matter because I really don't care about replicating the HardwareID-12 / Enclosure Type value, but I would like to be able replicate the HardwareID-0, HardwareID-1 and HardwareID-2

I already know from which WMI class to get the BIOS major and minor release version for HardwareID-0, HardwareID-1 and HardwareID-2, but the problem is that when I append those BIOS values to the string with which to generate the UUID, I end getting a totally different UUID from what computerhardwareids.exe generates.

My questions are:

  • What I need to do to replicate the same exact generated UUID for HardwareID-0, HardwareID-1 and HardwareID-2?.

  • Maybe I need to treat those numerical values in a special way, applying some format that I don't know when appending them to the string with which to generate the UUID?.

Please note that I DON'T have experience in reverse-engineering.

CODE

This is the code I'm using, written in VB.NET. At its current state I consider it a working solution that replicates (or it should replicate) the same computer hardware ids as computerhardwareids.exe program generate, except hardware ids 0, 1, 2 and 12 for the reasons that I have explained.

  1. Computer hardware id type enumeration

     ' https://learn.microsoft.com/en-us/windows-hardware/drivers/install/specifying-hardware-ids-for-a-computer
     Public Enum ComputerHardwareIdMicrosoftType
    
         ''' <summary>
         ''' HardwareID-0
         ''' <para></para>
         ''' Manufacturer + Family + Product Name + SKU Number + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
         ''' </summary>
         HardwareID_0 = 0
    
         ''' <summary>
         ''' HardwareID-1
         ''' <para></para>
         ''' Manufacturer + Family + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
         ''' </summary>
         HardwareID_1 = 1
    
         ''' <summary>
         ''' HardwareID-2
         ''' <para></para>
         ''' Manufacturer + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
         ''' </summary>
         HardwareID_2 = 2
    
         ''' <summary>
         ''' HardwareID-3
         ''' <para></para>
         ''' Manufacturer + Family + Product Name + SKU Number + Baseboard Manufacturer + Baseboard Product
         ''' </summary>
         HardwareID_3 = 3
    
         ''' <summary>
         ''' HardwareID-4
         ''' <para></para>
         ''' Manufacturer + Family + Product Name + SKU Number
         ''' </summary>
         HardwareID_4 = 4
    
         ''' <summary>
         ''' HardwareID-5
         ''' <para></para>
         ''' Manufacturer + Family + Product Name
         ''' </summary>
         HardwareID_5 = 5
    
         ''' <summary>
         ''' HardwareID-6
         ''' <para></para>
         ''' Manufacturer + SKU Number + Baseboard Manufacturer + Baseboard Product
         ''' </summary>
         HardwareID_6 = 6
    
         ''' <summary>
         ''' HardwareID-7
         ''' <para></para>
         ''' Manufacturer + SKU Number
         ''' </summary>
         HardwareID_7 = 7
    
         ''' <summary>
         ''' HardwareID-8
         ''' <para></para>
         ''' Manufacturer + Product Name + Baseboard Manufacturer + Baseboard Product
         ''' </summary>
         HardwareID_8 = 8
    
         ''' <summary>
         ''' HardwareID-9
         ''' <para></para>
         ''' Manufacturer + Product Name
         ''' </summary>
         HardwareID_9 = 9
    
         ''' <summary>
         ''' HardwareID-10
         ''' <para></para>
         ''' Manufacturer + Family + Baseboard Manufacturer + Baseboard Product
         ''' </summary>
         HardwareID_10 = 10
    
         ''' <summary>
         ''' HardwareID-11
         ''' <para></para>
         ''' Manufacturer + Family
         ''' </summary>
         HardwareID_11 = 11
    
         ''' <summary>
         ''' HardwareID-12
         ''' <para></para>
         ''' Manufacturer + Enclosure Type
         ''' </summary>
         HardwareID_12 = 12
    
         ''' <summary>
         ''' HardwareID-13
         ''' <para></para>
         ''' Manufacturer + Baseboard Manufacturer + Baseboard Product
         ''' </summary>
         HardwareID_13 = 13
    
         ''' <summary>
         ''' HardwareID-14
         ''' <para></para>
         ''' Manufacturer
         ''' </summary>
         HardwareID_14 = 14
    
     End Enum
    
  2. Computer hardware id generation method:

     Public Shared Function GetComputerHardwareIdFromMicrosoftHwIdType(hwidType As ComputerHardwareIdMicrosoftType) As Guid
    
         Select Case hwidType
             Case Is < 0, Is > 14
                 Throw New InvalidEnumArgumentException(argumentName:=NameOf(hwidType), invalidValue:=hwidType, enumClass:=GetType(ComputerHardwareIdMicrosoftType))
    
         '' *************************************************************
         '' HARDWARE TYPE ID. 0, 1 AND 2 ARE NOT GIVING THE CORRECT GUID.
         '' *************************************************************
             Case 0, 1, 2, 12
                 Throw New NotImplementedException("This hardware id type is not implemented.")
         End Select
    
         ' Namespace used by 'computerhardwareids.exe' program included in the Windows SDK.
         ' https://stackoverflow.com/questions/25190906/get-hardware-ids-like-microsoft-does/43619888#43619888
         ' https://blogs.gnome.org/hughsie/2017/04/25/reverse-engineering-computerhardwareids-exe-with-winedbg/
         Dim namespaceUUID As Guid = Guid.Parse("70ffd812-4c7f-4c7d-0000-000000000000")
    
         ' Win32_ComputerSystem fields
         Dim manufacturer, family, productName, skuNumber As String
    
         ' Win32_BaseBoard fields
         Dim baseBoardManufacturer, baseBoardProduct As String
    
         ' Win32_BIOS fields
         Dim biosVendor, biosVersion, biosMajorRelease, biosMinorRelease As String
    
         ' Retrieve computer info.
         Using mos As New Management.ManagementObjectSearcher()
    
             ' Win32_ComputerSystem
             mos.Query.QueryString = "select Manufacturer,Model,SystemFamily,SystemSKUNumber from Win32_ComputerSystem"
             Using systemInfo As Management.ManagementObject = mos.Get(0)
                 manufacturer = CStr(systemInfo.Properties("Manufacturer").Value).Trim()
                 productName = CStr(systemInfo.Properties("Model").Value).Trim()
                 family = CStr(systemInfo.Properties("SystemFamily").Value).Trim()
                 skuNumber = CStr(systemInfo.Properties("SystemSKUNumber").Value).Trim()
             End Using
    
             ' Win32_BaseBoard
             mos.Query.QueryString = "select Manufacturer,Product from Win32_BaseBoard"
             Using baseBoardInfo As Management.ManagementObject = mos.Get(0)
                 baseBoardManufacturer = CStr(baseBoardInfo.Properties("Manufacturer").Value).Trim()
                 baseBoardProduct = CStr(baseBoardInfo.Properties("Product").Value).Trim()
             End Using
    
             ' Win32_BIOS
             mos.Query.QueryString = "select Manufacturer,SMBIOSBIOSVersion,SystemBiosMajorVersion,SystemBiosMinorVersion from Win32_BIOS"
             Using biosInfo As Management.ManagementObject = mos.Get(0)
                 biosVendor = CStr(biosInfo.Properties("Manufacturer").Value).Trim()
                 biosVersion = CStr(biosInfo.Properties("SMBIOSBIOSVersion").Value).Trim()
                 biosMajorRelease = CStr(biosInfo.Properties("SystemBiosMajorVersion").Value).Trim()
                 biosMinorRelease = CStr(biosInfo.Properties("SystemBiosMinorVersion").Value).Trim()
             End Using
    
         End Using
    
     #If DEBUG Then
         ' Console.WriteLine($"{NameOf(manufacturer)}          = {manufacturer}")
         ' Console.WriteLine($"{NameOf(productName)}           = {productName}")
         ' Console.WriteLine($"{NameOf(family)}                = {family}")
         ' Console.WriteLine($"{NameOf(skuNumber)}             = {skuNumber}")
         ' Console.WriteLine($"{NameOf(baseBoardManufacturer)} = {baseBoardManufacturer}")
         ' Console.WriteLine($"{NameOf(baseBoardProduct)}      = {baseBoardProduct}")
         ' Console.WriteLine($"{NameOf(biosVendor)}            = {biosVendor}")
         ' Console.WriteLine($"{NameOf(biosVersion)}           = {biosVersion}")
         ' Console.WriteLine($"{NameOf(biosMajorRelease)}      = {biosMajorRelease}")
         ' Console.WriteLine($"{NameOf(biosMinorRelease)}      = {biosMinorRelease}")
     #End If
    
         Dim stringToHash As String = String.Empty
    
         Select Case hwidType
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_0
                 stringToHash = $"{manufacturer}&{family}&{productName}&{skuNumber}&{biosVendor}&{biosVersion}&{biosMajorRelease}&{biosMinorRelease}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_1
                 stringToHash = $"{manufacturer}&{family}&{productName}&{biosVendor}&{biosVersion}&{biosMajorRelease}&{biosMinorRelease}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_2
                 stringToHash = $"{manufacturer}&{productName}&{biosVendor}&{biosVersion}&{biosMajorRelease}&{biosMinorRelease}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_3
                 stringToHash = $"{manufacturer}&{family}&{productName}&{skuNumber}&{baseBoardManufacturer}&{baseBoardProduct}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_4
                 stringToHash = $"{manufacturer}&{family}&{productName}&{skuNumber}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_5
                 stringToHash = $"{manufacturer}&{family}&{productName}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_6
                 stringToHash = $"{manufacturer}&{skuNumber}&{baseBoardManufacturer}&{baseBoardProduct}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_7
                 stringToHash = $"{manufacturer}&{skuNumber}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_8
                 stringToHash = $"{manufacturer}&{productName}&{baseBoardManufacturer}&{baseBoardProduct}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_9
                 stringToHash = $"{manufacturer}&{productName}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_10
                 stringToHash = $"{manufacturer}&{family}&{baseBoardManufacturer}&{baseBoardProduct}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_11
                 stringToHash = $"{manufacturer}&{family}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_13
                 stringToHash = $"{manufacturer}&{baseBoardManufacturer}&{baseBoardProduct}"
    
             Case ComputerHardwareIdMicrosoftType.HardwareID_14
                 stringToHash = manufacturer
    
         End Select
    
         ' Creates a name-based UUID using the algorithm from RFC 4122 ยง4.3.
         ' https://stackoverflow.com/questions/61267254/generating-uuid-based-on-strings
         Dim generateGuidDelegate As Func(Of Guid, String, Guid) =
             Function(namespaceId As Guid, name As String) As Guid
    
                 ' Converts a GUID (expressed as a byte array) to/from network order (MSB-first).
                 Dim swapByteOrderDelegate As New Action(Of Byte())(
                     Sub(ByVal guid() As Byte)
                         Dim temp As Byte = guid(0)
                         guid(0) = guid(3)
                         guid(3) = temp
    
                         temp = guid(1)
                         guid(1) = guid(2)
                         guid(2) = temp
    
                         temp = guid(4)
                         guid(4) = guid(5)
                         guid(5) = temp
    
                         temp = guid(6)
                         guid(6) = guid(7)
                         guid(7) = temp
                     End Sub)
    
                 ' Convert the name to a sequence of octets (as defined by the standard or conventions of its namespace) (step 3).
                 Dim nameBytes() As Byte = Encoding.Unicode.GetBytes(name)
    
                 ' Convert the namespace UUID to network order (step 3).
                 Dim namespaceBytes() As Byte = namespaceId.ToByteArray()
                 swapByteOrderDelegate.Invoke(namespaceBytes)
    
                 ' Compute the hash of the name space ID concatenated with the name (step 4).
                 Dim hash As Byte()
                 Using algorithm As HashAlgorithm = SHA1.Create()
                     algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, Nothing, 0)
                     algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length)
                     hash = algorithm.Hash
                 End Using
    
                 ' Most bytes from the hash are copied straight to the bytes of the new GUID (steps 5-7, 9, 11-12).
                 Dim newGuid(15) As Byte
                 Array.Copy(hash, 0, newGuid, 0, 16)
    
                 ' Set the four most significant bits (bits 12 through 15) of the time_hi_and_version field
                 ' to the appropriate 4-bit version number from Section 4.1.3 (step 8).
                 newGuid(6) = CByte((newGuid(6) And &HF) Or (5 << 4))
    
                 ' Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved
                 ' to zero and one, respectively (step 10).
                 newGuid(8) = CByte((newGuid(8) And &H3F) Or &H80)
    
                 ' Convert the resulting UUID to local byte order (step 13).
                 swapByteOrderDelegate.Invoke(newGuid)
                 Return New Guid(newGuid)
             End Function
    
         Return generateGuidDelegate.Invoke(namespaceUUID, stringToHash)
    
     End Function
    
  3. Usage example:

     'Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(0)}}}    <- Manufacturer + Family + ProductName + SKUNumber + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release")
     'Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(1)}}}    <- Manufacturer + Family + ProductName + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release")
     'Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(2)}}}    <- Manufacturer + ProductName + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(3)}}}    <- Manufacturer + Family + ProductName + SKUNumber + Baseboard Manufacturer + Baseboard Product")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(4)}}}    <- Manufacturer + Family + ProductName + SKUNumber")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(5)}}}    <- Manufacturer + Family + ProductName")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(6)}}}    <- Manufacturer + SKUNumber + Baseboard Manufacturer + Baseboard Product")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(7)}}}    <- Manufacturer + SKUNumber")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(8)}}}    <- Manufacturer + ProductName + Baseboard Manufacturer + Baseboard Product")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(9)}}}    <- Manufacturer + ProductName")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(10)}}}    <- Manufacturer + Family + Baseboard Manufacturer + Baseboard Product")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(11)}}}    <- Manufacturer + Family")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(13)}}}    <- Manufacturer + Baseboard Manufacturer + Baseboard Product")
     Console.WriteLine($"{{{GetComputerHardwareIdFromMicrosoftHwIdType(14)}}}    <- Manufacturer")
    
1

There are 1 answers

0
ElektroStudios On BEST ANSWER

By trial and error trying possible formattings, I found that the numeric values (of type byte) must be converted to hexadecimal, and they must be in lower-casing.

So the only changes I need to do in the source-code that I published in the main post, and in order to replicate Hardware-Id 0, 1, 2, is this:

biosMajorRelease = CByte(biosInfo.Properties("SystemBiosMajorVersion").Value).ToString("X2").ToLower()
biosMinorRelease = CByte(biosInfo.Properties("SystemBiosMinorVersion").Value).ToString("X2").ToLower()

That and of course remove the NotImplementedException line.

Now the code works to get all hardware ids except the HardwareId-12 because I'm not aware in which WMI class to find the Enclosure Type value, which by the way is a byte type too.

But it doesn't really matter. I have 13 working CHIDS out of 14 and I consider it is a very good rate to finally say this is a complete managed solution to replicate what computerhardwareids.exe does, although I didn't tested it out of my PC.

enter image description here

enter image description here