【问题标题】:Generating a unique machine id生成唯一的机器 ID
【发布时间】:2010-09-11 02:56:36
【问题描述】:

我需要编写一个函数,为运行 Windows 操作系统的给定机器生成一个唯一的 id。

目前,我正在使用 WMI 来查询各种硬件参数并将它们连接在一起并散列它们以派生唯一 id。我的问题是,我应该使用哪些建议参数? 目前,我正在使用 bios\cpu\disk 数据的组合来生成唯一 ID。如果每个指标有多个结果,我将使用第一个结果。

但是,我遇到了一个问题,即双启动到 2 个不同 Windows 操作系统的机器会在每个操作系统上生成不同的站点代码,这在理想情况下不应该发生。

作为参考,这些是我目前使用的指标:

Win32_Processor:UniqueID,ProcessorID,Name,Manufacturer,MaxClockSpeed
Win32_BIOS:Manufacturer
Win32_BIOS:SMBIOSBIOSVersion,IdentificationCode,SerialNumber,ReleaseDate,Version
Win32_DiskDrive:Model, Manufacturer, Signature, TotalHeads
Win32_BaseBoard:Model, Manufacturer, Name, SerialNumber
Win32_VideoController:DriverVersion, Name

【问题讨论】:

    标签: windows winapi wmi uniqueidentifier


    【解决方案1】:

    我遇到了同样的问题,经过一番研究后,我决定最好的办法是按照@Agnus 的建议,在注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography 中读取MachineGuid。它是在操作系统安装期间生成的,除非您重新安装操作系统,否则它不会更改。根据操作系统版本,它可能包含嵌入的网络适配器 MAC 地址(加上一些其他数字,包括随机数)或伪随机数,后者用于较新的操作系统版本(我相信在 XP SP2 之后,但不确定)。如果它是理论上的伪随机,它可以被伪造 - 如果两台机器具有相同的初始状态,包括实时时钟。在实践中,这种情况很少见,但请注意,如果您希望它成为可能被铁杆黑客攻击的安全基础。

    当然,任何人也可以轻松更改注册表项以伪造机器 GUID,但我发现这会破坏许多 Windows 组件的正常运行,在大多数情况下没有普通用户会这样做(再次,小心铁杆黑客)。

    【讨论】:

    • 我认为,您可以使用 KEY_WOW64_64KEY 标志来确保您始终获得“真实”版本的注册表项。
    • 如果您克隆一个驱动器映像,这将保持不变。所以这根本不是篡改安全的,而且非常不安全。
    • 为了澄清这一点,当我在软件中加入 DRM 措施时,我的主要目标是防止人们制造破解,使“专业”盗版者能够不受限制地出售软件的非法副本。我并不担心偶尔会有黑客克隆他朋友的驱动器只是为了能够使用我的软件。在这种情况下,这些人通常拥有的时间多于金钱,而且无论如何也不会为此付出代价。如果软件成本为 100 美元,而您的工资超过 50 美元/小时,您只需支付费用即可。麻烦将花费您超过 2 小时的时间。
    • 特别是,在通过克隆主机映像安装 Windows 的环境中,所有机器的 MachineGuid 都是相同的。
    • 如果您使用 sysprep & all 正确且合法地执行此操作,则不会。对于那些拥有盗版 Windows 和“只是克隆”的人来说,这是另一回事。但无论如何,它们不会那么容易被阻止。
    【解决方案2】:

    对于我们的licensing tool,我们考虑以下组件

    • MAC 地址
    • CPU(不是序列号,而是实际的 CPU 配置文件,如步进和型号)
    • 系统驱动器序列号(不是卷标)
    • 内存
    • CD-ROM 型号和供应商
    • 显卡型号和供应商
    • IDE 控制器
    • SCSI 控制器

    但是,我们不只是对组件进行散列处理并创建通过/失败系统,而是创建一个comparable fingerprint,可用于确定两个机器配置文件的差异程度。如果差异等级高于指定的容差,则要求用户再次激活。

    在过去 8 年中,我们发现数十万最终用户安装使用这种组合非常有效,可以提供可靠的唯一机器 ID,即使对于虚拟机和克隆的操作系统安装也是如此。

    【讨论】:

    • 如何确定您使用的 MAC 地址?一台机器可以有多个 NIC,这些是动态添加的(通过小程序连接到新的 VPN 将添加一个虚拟 NIC)。有些是虚拟的,具有以太网类型,很难识别为虚拟。其他取决于网络条件(wifi)的Up/Down
    • 我们使用所有物理网卡 - 不包括虚拟网卡、蓝牙等。它们都被组合起来以创建统一的哈希。
    • 为什么不建议使用CPU序列号?
    • 英特尔芯片多年未启用 CPU 序列号。系统调用仍然存在,但它不会返回稳定值。我不记得它返回什么 - 虚拟数据或所有机器的相同值。无论哪种方式,它都不是可靠的硬件指标。
    • @PaulAlexander 您提到的工具可以验证您提到的所有参数,或者其中一些参数会起作用?因为现在的系统通常不包含 CD-ROM
    【解决方案3】:

    自己解析SMBIOS 并将其散列到任意长度。请参阅PDF specification 了解所有可用的 SMBIOS 结构。

    要从 Windows 查询 SMBIOS 信息,您可以使用 EnumSystemFirmwareEntriesEnumSystemFirmwareTablesGetSystemFirmwareTable

    IIRC,CPUID 指令中的“唯一 ID”已从 P3 和更新版本中弃用。

    【讨论】:

    • 请注意,这些功能至少需要 Windows Vista、Windows XP Professional x64 Edition、Windows Server 2008 或带有 SP1 的 Windows Server 2003。
    • 注意不要做我所做的,即调用 GetSystemFirmwareTable('RSMB'...);并散列整个 SMBIOSTableData 缓冲区。它工作得很好,直到我遇到一个将其 cpu 内部温度写入该表的工作站,这意味着我的唯一 ID 每隔几秒就会改变一次。
    • 这个解决方案有源代码吗?
    • @Thomas 那么您最终选择了哪种解决方案?
    • @Smith 我的目标是一个 8 字符的小 ID。阅读规范后,我决定哪些字段可能会有所不同并排除它们。然后多年来,我从机器中剔除了更多不是常量的字段。最后,我最终存储了用作输入的原始数据的加密副本,并创建了一个closeEnough 函数,以便如果它仅在 2 个字段中变化,我将接受不匹配的 id。我还在哈希中包含有关处理器和系统硬盘驱动器的详细信息,因为早期我在相同系统之间发生了冲突。
    【解决方案4】:

    只使用处理器的 UniqueID 怎么样?

    【讨论】:

    • 现在这不是折旧的财产吗?
    • 也许他的意思是“已弃用”... CPU 制造商在某个阶段开始使用唯一 ID,但由于对隐私问题的强烈反对,他们又停止了。因此,您会发现有些具有唯一 ID,但大多数现代 CPU 没有。
    • 作为参考,只有一小部分 Pentium III 具有可以读取的 CPU 序列号。虽然后来的版本有一个序列号,但默认情况下它是禁用的。 Pentium IV 和更高版本的 CPU 根本不支持它。
    【解决方案5】:

    我讨厌成为那种说“你做错了”的人(我一直讨厌那个人;)但是......

    是否必须为独特的机器重复生成?你可以只分配标识符或做一个公钥/私钥吗?也许如果您可以生成并存储该值,您可以从同一磁盘上的两个操作系统安装访问它?

    您可能已经探索过这些选项,但它们对您不起作用,但如果不是,则需要考虑。

    如果不是用户信任问题,您可以只使用 MAC 地址。

    【讨论】:

    • 如果机器没有网卡,MAC地址将不起作用。
    • @Brian - 你真的需要一个唯一值来识别没有网卡的计算机吗?似乎很安全的赌注机器有一张卡片。
    • 您可以在 2 分钟内欺骗和更改您的 MAC 地址。
    【解决方案6】:

    您应该考虑使用网卡上的 MAC 地址(如果存在)。这些通常是独一无二的,但可以伪造。我使用了根据您的网络适配器 MAC 地址生成许可证文件的软件,因此它被认为是区分计算机的一种相当可靠的方法。

    【讨论】:

    • 不,他们不是。许多制造商允许您更改它们。这在使用集群时非常有用,因为一些供应商会为您提供具有相同 MAC 地址的所有计算机(我们在几年前遇到过这个问题)。
    • 这在许多情况下是有效的想法,问题没有指定防欺骗或离线 - 如果您想在网络中识别,您通常需要生成唯一 ID
    • 同一台机器可以有多个网络设备;您不能保证它们总是以相同的顺序被检测到,或者它们在某些时候不会被替换。最好使用一些可能更永久的硬件。
    【解决方案7】:

    对于我的一个应用程序,如果它是非域计算机,我要么使用计算机名称,要么使用域计算机的域计算机帐户 SID。 Mark Russinovich 在这篇博文中谈到了它,Machine SID

    如果分布式应用程序使用机器 SID 来唯一标识计算机,则会出现 SID 重复问题的最后一种情况。没有 Microsoft 软件会这样做,并且以这种方式使用机器 SID 并不能仅仅因为所有 DC 都具有相同的机器 SID 的事实。依赖于唯一计算机身份的软件使用计算机名称或计算机域 SID(域中计算机帐户的 SID)。

    您可以通过 LDAP 或System.DirectoryServices 访问域机器帐户 SID。

    【讨论】:

      【解决方案8】:

      在我的程序中,我首先检查终端服务器并使用 WTSClientHardwareId。否则本地PC的MAC地址就足够了。

      如果您真的想使用您提供的属性列表,请忽略NameDriverVersionClockspeed 等内容,因为它可能取决于操作系统。尝试在两个操作系统上输出相同的信息,并忽略不同的信息。

      【讨论】:

        【解决方案9】:

        有一个库可用于获取硬件特定信息:Hardware serial number extractor (CPU, RAM, HDD, BIOS)

        【讨论】:

        • 它是一个闭源商业图书馆。
        • @Gab-源代码可用。而且 DLL (29) 的价格与其他甚至接近 2000 美元的库相比是微不足道的。所以,是的,它完成了这项工作。
        【解决方案10】:

        为什么不用网卡的MAC地址?

        【讨论】:

        • Mac地址可以被欺骗
        • 这在许多情况下是有效的想法,问题没有指定防欺骗或离线 - 如果您想在网络中识别,您通常需要生成唯一 ID
        【解决方案11】:

        也许有点作弊,但现在机器以太网适配器的 MAC 地址很少在不改变主板的情况下改变。

        【讨论】:

        • 很多制造商允许您更改它们。这在使用集群时非常有用,因为一些供应商会为您提供具有相同 MAC 地址的所有计算机(几年前我们遇到过这个问题)。
        • MAC 完全不可靠,因为它可以很容易地更改(只需在谷歌搜索,您就会看到很多免费工具正在这样做)。 WMI 也是如此。
        【解决方案12】:

        你能提取某种制造商序列号或服务标签吗?

        我们的商店是戴尔商店,因此我们使用每台机器唯一的服务标签来识别它们。我知道可以从 BIOS 中查询它,至少在 Linux 中是这样,但我不知道如何在 Windows 中进行查询。

        【讨论】:

          【解决方案13】:

          我有一个额外的限制,我使用的是 .net express,所以我不能使用标准的硬件查询机制。所以我决定使用 power shell 来进行查询。完整代码如下所示:

          Private Function GetUUID() As String
              Dim GetDiskUUID As String = "get-wmiobject Win32_ComputerSystemProduct  | Select-Object -ExpandProperty UUID"
              Dim X As String = ""
              Dim oProcess As New Process()
              Dim oStartInfo As New ProcessStartInfo("powershell.exe", GetDiskUUID)
              oStartInfo.UseShellExecute = False
              oStartInfo.RedirectStandardInput = True
              oStartInfo.RedirectStandardOutput = True
              oStartInfo.CreateNoWindow = True
              oProcess.StartInfo = oStartInfo
              oProcess.Start()
              oProcess.WaitForExit()
              X = oProcess.StandardOutput.ReadToEnd
              Return X.Trim()
          End Function
          

          【讨论】:

            【解决方案14】:

            查找一个选项的 CPUID。多 CPU 系统可能存在一些问题。

            【讨论】:

              【解决方案15】:

              试试这个,它给出了一个唯一的硬盘 ID:Port of DiskId32 for Delphi 7-2010

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-07-07
                • 2011-06-14
                • 2014-05-26
                • 2012-02-22
                • 1970-01-01
                相关资源
                最近更新 更多