【问题标题】:Get Hardware IDs like Microsoft does像微软一样获取硬件 ID
【发布时间】:2014-10-01 04:33:48
【问题描述】:

在 Windows SDK 中有一个名为 computerhardwareids 的 CLI 工具

该工具会返回各种 GUID,以便为特定情况选择正确的 HardwareId。

这是在我的 PC 中返回此工具的输出:

Using the BIOS to gather information

Computer Information
--------------------

BIOS Vendor: American Megatrends Inc.
BIOS Version string: 1201
System BIOS Major Release: 4
System BIOS Minor Release: 6

System Manufacturer: To be filled by O.E.M.
System Family: To be filled by O.E.M.
System ProductName: To be filled by O.E.M.
SKU Number: SKU

Enclosure Type: 03 "Desktop"


Hardware IDs
------------
{a8670b03-1d98-5e95-ad4e-c64211eac9df}    <- Manufacturer + Family + ProductName + SKUNumber + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
{01c6b2a2-a2b2-58e4-906d-4677639f1a42}    <- Manufacturer + Family + ProductName + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
{dc5af3fe-c2de-539d-aafd-5061a1634723}    <- Manufacturer + ProductName + BIOS Vendor + BIOS Version + BIOS Major Release + BIOS Minor Release
{d78b474d-dee0-5412-bc9d-e9f7d7783df2}    <- Manufacturer + Family + ProductName + SKUNumber
{7ccbb6f1-9641-5f84-b00d-51ff218a4066}    <- Manufacturer + Family + ProductName
{5a127cba-be28-5d3b-84f0-0e450d266d97}    <- Manufacturer + SKUNumber
{6525c6e5-28e9-5f9c-abe4-20fd82504002}    <- Manufacturer + ProductName
{6525c6e5-28e9-5f9c-abe4-20fd82504002}    <- Manufacturer + Family
{482f3f58-6045-593a-9be4-611717ce4770}    <- Manufacturer + Enclosure Type
{11b4a036-3b64-5421-a372-22c07df10a4d}    <- Manufacturer

我想开发一个通用的使用函数,它应该模仿那个微软工具的功能,返回完全相同的 HardwareIds(完全相同)。

我在 MSDN 上找到了信息,所有输出似乎都记录得很清楚,它包含有关返回此工具的值的信息,但它没有具体说明 WMI 类的属性是什么,它只是说“ Bios”和“系统”:

·ComputerHardwareIds Overview

·Specifying Hardware IDs for a Computer

我很迷茫,我找不到任何值,例如“Family”、“BIOS Vendor”、“Bios Major Release”、“Bios Minor Release”,我不确定“SKU Number”在哪里指。

我认为这些是 WMI 类,工具在其中获取所有数据的一部分以制作 guid:

·Win32_BIOS class

·Win32_BaseBoard class

·Win32_ComputerSystem class

·Win32_ComputerSystemProduct class

请注意,文档也这样说:

然后使用 SHA-1 哈希将每个字符串转换为 GUID 算法。


这是我尝试做的,但我不确定我是否对某些概念或某些价值观有误,它是不完整的,而且我对 Guis 也有问题(用注释行解释):

Private Function GetHardwareId() As Guid

    Dim HardwareId As String = String.Empty

    Dim BIOSVersion, BIOSVendor, BIOSMajorRelease, BIOSMinorRelease,
        SystemManufacturer, SystemFamily, SystemProductName, SKUNumber As String

    ' Get System Info.
    Using wmi As New Management.ManagementObjectSearcher("select * from Win32_ComputerSystem")

        Using SystemInfo As Management.ManagementObject = wmi.Get(0)

            SystemManufacturer = Convert.ToString(SystemInfo.Properties("Manufacturer").Value)
            SystemProductName = Convert.ToString(SystemInfo.Properties("Model").Value)
            SystemFamily = I don't know how to get it.
            SKUNumber = I don't know how to get it.

        End Using

    End Using

    ' Get BIOS Info.
    Using wmi As New Management.ManagementObjectSearcher("select * from Win32_BIOS")

        Using BIOSInfo As Management.ManagementObject = wmi.Get(0)

            BIOSVersion = Convert.ToString(BIOSInfo.Properties("SMBIOSBIOSVersion").Value) 
            BIOSVendor = I don't know how to get it.
            BIOSMajorRelease = I don't know how to get it.
            BIOSMinorRelease = I don't know how to get it.

        End Using

    End Using ' wmi

    HardwareId = BIOSVersion & BIOSVendor & BIOSMajorRelease & BIOSMinorRelease &
                 SystemManufacturer & SystemFamily & SystemProductName & SKUNumber

    ' Here I call other method to encode the resulting string to SHA1 Hash
    HardwareId = ConvertToSHA1(HardwareId)
    ' and then continue below...

    ' But this will not work, 
    ' it throws an exception about missing "-" chars in the SHA1 string.
    ' So Microsoft formats "manualy" the SHA1 string to add some "-"?
    Return Guid.Parse(HardwareId)

End Function

【问题讨论】:

标签: .net vb.net wmi guid hardware-id


【解决方案1】:

我不认为您的问题可以按照您想要的方式解决。但目前还没有理由这样做。

MS 正在根据所提供的各种数据的 SHA 哈希创建确定性 GUID。如果根据 rfc422 standards 包括 4 个已定义的 GUID 命名空间之一创建,我们应该能够使用这 4 个命名空间之一从相同的数据重新创建 GUID。

但是,a) 我不能,b) MSDN's 'Specifying Hardware IDs for a Computer' 声明:the hardware ID for the computer must be produced by the ComputerHardwareIds tool (ComputerHardwareIDs.exe)...。这让我相信他们使用专有方法(Salt、私钥等)或定义自己的命名空间来生成这些。

您的次要/子问题的一些答案:

  • BIOS 版本/发行版 - 根据DTMF.org spec, Table 5,“发行版”位于偏移量 &H14 和 &H15 处,与“版本”不同。但是,它们也可能嵌入到 Win32_BIOS 的名称、标题、描述和 SoftwareElementID 属性中(请参阅下面的工具)。它似乎也隐藏在 Win32_BIOS.BiosVersion(1) 中,但与名称/标题等相同。

我觉得有点奇怪,我们的系统相隔几年但具有相同的 Release 值,它可能指的是 SMBios 版本/规范。

  • SKU:根据 MSDN,这是 AKA IdentificationCode

  • Family:显然是 BIOS 编码的一部分,但 WMI 没有公开或返回它(还没有?)。

  • 产品名称也是如此,您从其他地方获取的Model 可能只是巧合地具有相同的值。

因此,散列中使用的值似乎并没有全部暴露。在我的旧系统上,Family 和 SKU 为空。结果好像第一个和第二个ID应该是一样的,其实不然。

如果 GUID/ID 只能从该工具中获得,我不确定它们的用途或它们对普通应用程序有多大价值。您可能会查看 SDK 的其他部分,以查看是否有程序集等在运行时提供信息。

如果您只是想在下次看到某个系统或设备时对其进行识别,您可以简单地基于 rfc422 编写自己的方法,以确保在您定义的命名空间内具有相同的“非常高的概率”唯一值。像 MS 一样这样做的唯一原因是,如果您要看到来自其他地方的价值,事实并非如此。

最后,我没有费心发布 GUID 制造商,因为它不会做你想做的事。


用于获取属性值的 WMI 助手:

Public Sub GetWMIInfo(wmiclass As String)

    Using searcher As New Management.ManagementObjectSearcher("select * from " & wmiclass)

        For Each item As System.Management.ManagementObject In searcher.Get
            DebugProperties(item)
        Next

    End Using
End Sub

' this sub is copied from the watcher answer I gave:
Private Sub DebugProperties(mo As Management.ManagementObject)

    For Each pd As PropertyData In mo.Properties
        If pd.Value IsNot Nothing Then
            ' some props are string arrays, so you can iterate them if you want

            Console.WriteLine("{0} {1}", pd.Name,
                              If(pd.Value IsNot Nothing,
                                 pd.Value.ToString,
                                 "Nothing"))
        End If

    Next
End Sub

输出是这样的:

Caption BIOS Date: XXXXXXXXXXXX Ver: 04.06.04
Description BIOS Date: ##/##/## 11:18:49 Ver: 04.06.04
Manufacturer Dell Inc.
Name BIOS Date: ##/##/## 11:18:49 Ver: 04.06.04
PrimaryBIOS True
ReleaseDate ########000000.000000+000
SerialNumber ######
SMBIOSBIOSVersion A##
SMBIOSMajorVersion #
SMBIOSMinorVersion #

【讨论】:

  • 不能解决问题,这些值中的任何一个都是正确的值,注意 Microsoft 工具检索“BIOS 主要/次要版本”而不是“BIOS 主要/次要版本”,我不知道差异,但我之前尝试过相同的代码,并且“SMBIOSMajorVersion”返回的值与 Microsoft 工具不同。也不知道如何定位系统 Family 和我解释的其他值,以及如何将 SHA1 字符串转换为 GUID。谢谢你的回答
【解决方案2】:

要生成相同的 GUID,您需要从 SMBIOS 获取值(通常使用 GetSystemFirmwareTable),然后使用 '&' 字符连接它们。确保字符串使用 UTF-16 编码。然后,您需要使用类型 5 (SHA-1) UUID 生成方案,并将 70ffd812-4c7f-4c7d-0000-000000000000 作为命名空间。

【讨论】:

  • 欢迎提供解决方案链接,但请确保您的答案在没有它的情况下有用:add context around the link 这样您的其他用户就会知道它是什么以及为什么会出现,然后引用最相关的您链接到的页面的一部分,以防目标页面不可用。 Answers that are little more than a link may be deleted.
  • 非常感谢您的回答。我阅读了这篇文章,这是一篇出色的逆向工程作品,但没有演示性示例代码(用任何语言编写)我仍然非常迷茫,因为似乎不存在 GetSystemFirmwareTable api 用法的示例,我也不知道是什么您正在检索文章输出中的计算机信息组件(您只提到了所需的函数名称和技术人员反转的值,但没有提到如何使用这些函数)。无论如何,感谢您解决了这个谜团!。
【解决方案3】:
public ArrayList<String> getWinVendor()
        throws SecurityException, IOException,
        NullPointerException, IndexOutOfBoundsException,
        UnsupportedEncodingException {
    try {
        Process processProduct = Runtime.getRuntime().exec(new String[]{"wmic", "csproduct", "get", "vendor"});
        processProduct.getOutputStream().close();
        BufferedReader output = getOutput(processProduct);
        BufferedReader error = getError(processProduct);
        StringProductList = new ArrayList<String>();
        String line = "", result = "";
        while ((line = output.readLine()) != null) {
            if (!line.toLowerCase().startsWith("vendor") && line.length() > 0) {
                result = getSubStringSubstractEmptyAndTabSpace(line);
                if (result.length() > 0) {
                    StringProductList.add(result);
                } else {
                    StringProductList.add(UNKNOWN);
                }
            }
        }
        if (!StringProductList.isEmpty()) {
            return StringProductList;
        }
    } catch (Exception e) {
        if (e instanceof SecurityException
                || e instanceof IOException
                || e instanceof NullPointerException
                || e instanceof IndexOutOfBoundsException
                || e instanceof UnsupportedEncodingException) {
            e.printStackTrace();
        }
    }
    return null;
}

public BufferedReader getError(Process process) throws SecurityException, IOException,
        NullPointerException, IndexOutOfBoundsException, UnsupportedEncodingException {
    try {
        if (getCmdEncoding() != null) {
            return new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
        }
    } catch (Exception e) {
        if (e instanceof SecurityException
                || e instanceof IOException
                || e instanceof NullPointerException
                || e instanceof IndexOutOfBoundsException) {
            e.printStackTrace();
        }
    }
    return new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
}

public BufferedReader getOutput(Process process) throws SecurityException, IOException,
        NullPointerException, IndexOutOfBoundsException, UnsupportedEncodingException {
    try {
        if (getCmdEncoding() != null) {
            return new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
        }
    } catch (Exception e) {
        if (e instanceof SecurityException
                || e instanceof IOException
                || e instanceof NullPointerException
                || e instanceof IndexOutOfBoundsException) {
            e.printStackTrace();
        }
    }
    return new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
}

public static String getSubStringSubstractEmptyAndTabSpace(String word)
        throws NullPointerException, IndexOutOfBoundsException {
    if (word.length() > 0) {
        try {
            int length = word.length();
            int start = 0, end = length;
            for (int stringCharacter = 0; stringCharacter < length; stringCharacter++) {
                char c = word.charAt(stringCharacter);
                if (c == ' ' || c == '\t') {
                    start++;
                } else {
                    stringCharacter = length;
                }
            }
            for (int stringCharacter = length - 1; stringCharacter >= 0; stringCharacter--) {
                char c = word.charAt(stringCharacter);
                if (c == ' ' || c == '\t') {
                    end--;
                } else {
                    stringCharacter = -1;
                }
            }
            if (start == length) {
                return "";
            }
            if (end == 0) {
                return "";
            }
            if (start <= length - 1 && end >= 0) {
                return word.substring(start, end);
            }
        } catch (Exception e) {
            if (e instanceof NullPointerException
                    || e instanceof IndexOutOfBoundsException) {
                e.printStackTrace();
            }
        }
    }
    return word;
}

【讨论】:

  • 没有解释的代码转储很少有用。请编辑您的问题以添加一些上下文。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-07
相关资源
最近更新 更多