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:
- HardwareID-0 Manufacturer + Family + Product Name + SKU Number + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
- HardwareID-1 Manufacturer + Family + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
- HardwareID-2 Manufacturer + Product Name + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
- HardwareID-3 Manufacturer + Family + Product Name + SKU Number + Baseboard Manufacturer + Baseboard Product
- HardwareID-4 Manufacturer + Family + Product Name + SKU Number
- HardwareID-5 Manufacturer + Family + Product Name
- HardwareID-6 Manufacturer + SKU Number + Baseboard Manufacturer + Baseboard Product
- HardwareID-7 Manufacturer + SKU Number
- HardwareID-8 Manufacturer + Product Name + Baseboard Manufacturer + Baseboard Product
- HardwareID-9 Manufacturer + Product Name
- HardwareID-10 Manufacturer + Family + Baseboard Manufacturer + Baseboard Product
- HardwareID-11 Manufacturer + Family
- HardwareID-12 Manufacturer + Enclosure Type
- HardwareID-13 Manufacturer + Baseboard Manufacturer + Baseboard Product
- 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.
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
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
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")
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:
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.