生成唯一的机器标识符

112

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

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

然而,我遇到了一个问题,一台双启动进入两个不同的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
14个回答

81

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

当然,任何人都可以轻松更改注册表项以伪造机器 GUID,但我发现这会影响到 Windows 许多组件的正常运行,在大多数情况下,不会有普通用户这样做(再次提醒要注意激进黑客)。


8
我想你可以使用 KEY_WOW64_64KEY 标志来确保始终获取注册表键的“真实”版本。 - Colen
13
如果您克隆一个磁盘映像,它将保持不变。因此,这并不是安全可靠的,非常不安全。 - bitbonk
20
为了澄清一点,当我在软件中使用数字版权管理措施时,我的主要目的是防止人们制作破解程序,使得“专业”的盗版者可以无限制地销售非法副本。我不太担心偶尔会有黑客复制他朋友的硬盘来使用我的软件这样的事情发生。在这种情况下,这些人通常比较注重时间而不是金钱,并且也不会为此付费。如果软件售价为100美元,而你的工资每小时超过50美元,那么你只需要付钱购买它。麻烦所花费的时间将超过2小时。 - Fabio Ceconello
7
特别是在通过克隆主机映像安装Windows的环境中,所有计算机的MachineGuid都将完全相同。 - nandhp
8
如果你使用sysprep并遵循法律程序,那么就不会有问题。对于那些使用盗版Windows并且只是“克隆”的人来说,情况就不同了。但是他们也不会这么容易停止。 - Fabio Ceconello
显示剩余9条评论

40

我们的许可证工具考虑以下组件:

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

但是,我们不仅仅对这些组件进行哈希处理并创建通过/不通过的系统。相反,我们创建了一个可比较的指纹,可用于确定两台计算机配置文件之间的差异有多大。如果差异评分高于指定的容差,则要求用户再次激活。

在过去8年中,数十万个最终用户安装中使用后,我们发现这种组合很好地提供了一个可靠的唯一机器ID - 即使是虚拟机和克隆的操作系统安装也是如此。


3
如何确定要使用哪个 MAC 地址?一台计算机可以有多个网络接口(NIC),这些接口是动态添加的(通过应用程序连接到新 VPN 将会添加虚拟 NIC)。有些接口是虚拟的,类型为以太网,很难识别为虚拟的。其他的接口则根据网络情况处于上/下状态(如 WiFi)。 - Marek
我们使用所有物理网卡 - 不包括虚拟网卡、蓝牙等。它们都被合并在一起创建统一的哈希值。 - Paul Alexander
为什么您建议不要使用CPU序列号? - Mojtaba Rezaeian
4
多年来,英特尔芯片中未启用 CPU 序列号。虽然系统调用仍存在,但它不会返回稳定的值。我无法记住它返回的是什么 - 或者是虚假数据,或者对于所有机器返回相同的值。无论哪种情况,它都不是可靠的硬件指标。 - Paul Alexander
1
@PaulAlexander,您提到的工具是否验证您提到的所有参数,还是只有其中几个有效?因为现在的系统通常不包含CD-ROM。 - FaizanHussainRabbani

27

15
请注意,这些函数至少需要 Windows Vista、Windows XP Professional x64 Edition、Windows Server 2008 或安装了 SP1 的 Windows Server 2003。 - jcoffland
40
请勿像我一样调用 GetSystemFirmwareTable('RSMB'...) 并对整个 SMBIOSTableData 缓冲区进行哈希。这种方法很有效,但当我遇到将 CPU 内部温度写入该表的工作站时,我的唯一标识符每几秒钟就会更改。 - Thomas
这个解决方案是否有可用的源代码? - Just Shadow
@Thomas 那是什么样的系统?它把CPU温度写入那个表格里,这很奇怪。 - Konrad
@Konrad 很抱歉,我不确定。从那时的一些电子邮件来看,我认为它是一组我们拼凑在一起作为处理农场的 Dell 台式机。可能是一个 bug。多年来我看过许多变量,比如笔记本电脑盖子打开/关闭、Wifi 连接等等。 - Thomas
显示剩余2条评论

3
仅使用处理器的唯一标识符怎么样?

14
这不是现在已经贬值的房产吗? - Jake Wilson
16
也许他的意思是“已弃用”……CPU制造商曾在某个阶段将唯一标识符放入CPU中,但由于隐私问题引起了反弹,他们又停止了这样做。因此,你会发现一些CPU有唯一的标识符,但大多数现代CPU没有。 - TripleAntigen
1
仅供参考,只有少量的奔腾III处理器批次具有可读取的CPU序列号。尽管后来的版本具有序列号,但默认情况下是禁用的。奔腾IV及以后的CPU根本不支持它。 - Paul Alexander

1
对于我的其中一个应用程序,如果它是非域计算机,则使用计算机名称,否则使用域机器帐户 SID。Mark Russinovich 在这篇博客文章中讨论了这个问题,Machine SID

如果分布式应用程序使用机器 SID 来唯一标识计算机,则SID重复的最终情况将是一个问题。没有 Microsoft 软件这样做,以这种方式使用机器 SID 是不起作用的,因为所有 DC 都有相同的机器 SID。依赖于唯一计算机标识的软件要么使用计算机名称,要么使用计算机域 SID(域中计算机帐户的 SID)。

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


1

4
这是一个闭源商业库。 - Gab
@Gab-源代码可用。而DLL的价格(29)与其他接近2000美元的库相比微不足道。所以,是的,它能胜任工作。 - Gabriel

1

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


7
不,它们并不是固定的。很多制造商允许您更改它们。当与集群一起使用时,这非常有帮助,因为某些供应商会给您提供具有相同MAC地址的所有计算机(我们几年前遇到了这个问题)。 - gizmo
在许多情况下,这是一个有效的想法,问题并没有指定防欺骗性或离线 - 如果您想在网络中进行标识,则通常需要生成唯一的ID。 - Hurda
同一台机器上可能有多个网络设备;不能保证它们总是以相同的顺序被检测到,或者它们不会在某个时候被替换。最好使用一些更加永久的硬件。 - Agi Hammerthief

1

我不想成为那个说“你做错了”的人(我总是讨厌那个人 ;) 但是...

它必须为唯一的机器重复生成吗?你能否只分配标识符或执行公共/私有密钥?也许如果你能够生成并存储该值,你可以从同一磁盘上的两个操作系统安装中访问它?

你可能已经探索了这些选项并且它们对你没有用,但如果没有,这是值得考虑的。

如果不涉及用户信任问题,你可以使用MAC地址。


7
如果机器没有网络卡,MAC地址将无法使用。 - Brian
7
@Brian - 你真的需要一个唯一值来识别那些没有网络卡的计算机吗?看起来这台机器有网卡是非常肯定的事情。 - romandas
1
你可以在短短的两分钟内欺骗和更改你的MAC地址。 - Gaspa79

1
在我的程序中,我首先检查终端服务器并使用WTSClientHardwareId。否则,本地PC的MAC地址应该足够。
如果您真的想使用您提供的属性列表,请省略像“Name”和“DriverVersion”,“Clockspeed”等这样的内容,因为它可能与操作系统有关。尝试在两个操作系统上输出相同的信息,并省略其中不同的部分。

0

我有一个额外的限制,那就是我正在使用 .net express,因此无法使用标准的硬件查询机制。所以我决定使用 PowerShell 进行查询。完整的代码如下:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接