如何为每台计算机生成唯一的编号?

3

我正在使用C#开发软件锁。我需要为每台计算机生成一个唯一的数字。

我已经进行了研究并决定使用CPU号码和硬盘号码作为每台计算机的唯一数字。

我的代码:

private string UniqID()
{
    ////////////////CpuID
    string cpuInfo = string.Empty;
    ManagementClass mc = new ManagementClass("win32_processor");
    ManagementObjectCollection moc = mc.GetInstances();

    foreach (ManagementObject mo in moc)
    {
        cpuInfo = mo.Properties["processorID"].Value.ToString();
        break;
    }

    ////////////////HDD ID
    string drive = "C";
    ManagementObject dsk = new ManagementObject(
        @"win32_logicaldisk.deviceid=""" + drive + @":""");
    dsk.Get();
    string volumeSerial = dsk["VolumeSerialNumber"].ToString();

    return volumeSerial + cpuInfo;
}

这个方法可以使用,但是存在一个问题!当用户重新安装Windows操作系统并想要运行我的软件时,唯一的编号已经发生了改变。 为什么在重新安装Windows后唯一的编号会改变呢?CPU编号和硬盘编号是否取决于当前的Windows安装?


例如,获取硬盘序列号或混合一些值。 - Reza Aghaei
它们都有MAC地址。 - J. McCabe
1
没有什么是100%静态和可靠的。例如,如果用户不得不更换故障的主板,则主板序列号可能会更改。创建系统中几个内容的哈希,并准备在某些条件下发放替换许可证。 - Ňɏssa Pøngjǣrdenlarp
1
那么如果我更换硬件,我就不能使用我合法获取的软件了吗? - Hasan Emrah Süngü
1
@saeed,这并不同。你想要一种在标题中唯一标识计算机的方法(因为出于某种原因,你的标题问题和帖子问题完全不同)。所以我给了你一些需要考虑的事情清单,现在你却说这是离题的笑话。 - Qrchack
显示剩余5条评论
2个回答

4

实际上,您可以获取主板ID、CPU ID、磁盘序列号和MAC地址,但经验表明,它们中没有一项是100%准确的。

我们的统计数据显示:

  • 磁盘序列号缺失0.1%
  • MAC地址缺失1.3%
  • 主板ID缺失30%
  • CPU ID缺失99%

在测试的机器中,有0.04%的机器没有提供任何信息,我们甚至无法读取计算机名称。这可能是某种虚拟PC、Hyper-V或VMWare实例?

磁盘序列号最为可靠,但很容易更改;MAC地址可以更改,并且根据应用的过滤器不同,会因添加设备驱动程序(如Hyper-V、Wireshark等)而发生变化。

主板和CPU ID有时会返回占位符“NONE”等值。

您还应该注意,调用这些函数可能非常慢(即使在快速PC上也可能需要几秒钟),因此尽早在后台线程中启动它们可能是值得考虑的,您最好不要在这些函数上进行阻塞。

主板ID

    private static void FetchMotherboardIdInternal()
    {
        try
        {
            ManagementScope scope = new ManagementScope("\\\\" + Environment.MachineName + "\\root\\cimv2");
            scope.Connect();

            using (ManagementObject wmiClass = new ManagementObject(scope, new ManagementPath("Win32_BaseBoard.Tag=\"Base Board\""), new ObjectGetOptions()))
            {
                object motherboardIDObj = wmiClass["SerialNumber"];
                if (motherboardIDObj != null)
                {
                    string motherboardID = motherboardIDObj.ToString().Trim();
                    Trace.WriteLine("MotherboardID = " + motherboardID);
                    if (IsValidMotherBoardID(motherboardID))
                    {
                        _motherboardID = motherboardID;
                    }
                }
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read MotherbaordID\r\n" + ex.Message);
        }
    }
    public static bool IsValidMotherBoardID(string value)
    {
        if (value == null)
            return false;
        string motherboardID = value.Trim();
        return !(   motherboardID.Replace(".", "").Replace(" ", "").Replace("\t", "").Trim().Length < 5 ||
                   motherboardID.ToUpper().Contains("BASE") ||
                   motherboardID.Contains("2345") ||
                   motherboardID.ToUpper().StartsWith("TO BE") ||
                   motherboardID.ToUpper().StartsWith("NONE") ||
                   motherboardID.ToUpper().StartsWith("N/A") ||
                   motherboardID.ToUpper().Contains("SERIAL") ||
                   motherboardID.ToUpper().Contains("OEM") ||
                   motherboardID.ToUpper().Contains("AAAAA") ||
                   motherboardID.ToUpper().Contains("ABCDE") ||
                   motherboardID.ToUpper().Contains("XXXXX") ||
                   motherboardID.ToUpper().Contains("NOT") ||
                   motherboardID.ToUpper().StartsWith("00000")
                );

    }

CPU ID

    private static void FetchCpuIdInternal()
    {
        try
        {
            using (ManagementClass mc = new ManagementClass("Win32_Processor"))
            {
                using (ManagementObjectCollection moc = mc.GetInstances())
                {
                    foreach (ManagementObject mo in moc)
                    {
                        if (mo.Properties["UniqueId"] != null && mo.Properties["UniqueId"].Value != null)
                        {
                            // only return cpuInfo from first CPU
                            Trace.WriteLine("CPU ID = " + mo.Properties["UniqueId"].Value.ToString());
                            _cpuID = mo.Properties["UniqueId"].Value.ToString();
                        }
                        mo.Dispose();
                    }
                }
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read CPUID\r\n" + ex.Message);
        }
    }

第一张卡的MAC地址

    private static void FecthMACAddressInternal()
    {
        try
        {
            using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"))
            {
                using (ManagementObjectCollection moc = mc.GetInstances())
                {
                    if (moc != null)
                    {
                        foreach (ManagementObject mo in moc)
                        {
                            Trace.WriteLine(mo["Index"] + " Mac " + mo["Caption"] + " : " + mo["MacAddress"] + " Enabled " + (bool)mo["IPEnabled"]);
                            if (string.IsNullOrEmpty(_macAdderss))  // only return MAC Address from first card
                            {
                                if ( mo["MacAddress"] != null && mo["IPEnabled"] != null && (bool)mo["IPEnabled"] == true)
                                {
                                    _macAdderss = mo["MacAddress"].ToString();
                                }
                            }
                            mo.Dispose();
                        }
                    }
                }
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
        }
        if (_macAdderss != null)
            _macAdderss = _macAdderss.Replace(":", "");
    }

驱动器序列号

    /// <summary>
    /// return Volume Serial Number from hard drive
    /// </summary>
    /// <param name="strDriveLetter">[optional] Drive letter</param>
    /// <returns>[string] VolumeSerialNumber</returns>
    public static string GetVolumeSerial(char driveLetter)
    {
        try
        {
            using (ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + driveLetter + ":\""))
            {
                if (disk == null)
                    return null;
                disk.Get();
                object diskObj = disk["VolumeSerialNumber"];
                if (diskObj != null)
                    return diskObj.ToString();
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
        }

        try
        {
            uint serialNum, serialNumLength, flags;
            StringBuilder volumename = new StringBuilder(256);
            StringBuilder fstype = new StringBuilder(256);

            bool ok = GetVolumeInformation(driveLetter.ToString() + ":\\", volumename, (uint)volumename.Capacity - 1, out serialNum, out serialNumLength, out flags, fstype, (uint)fstype.Capacity - 1);
            if (ok)
            {
                return string.Format("{0:X4}{1:X4}", serialNum >> 16, serialNum & 0xFFFF);
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex2)
        {
            Trace.TraceWarning("Failed to read DiskID\r\n" + ex2.Message);
        }

        return null;
    }


  [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    static extern bool GetVolumeInformation(string Volume, StringBuilder VolumeName, uint VolumeNameSize, out uint SerialNumber, out uint SerialNumberLength, out uint flags, StringBuilder fs, uint fs_size);

谢谢你的代码,我可以问一下你从哪里获取了“GetVolumeInformation”吗? - Luishg
1
这是一个DllImport("kernel32.dll"的代码... 我已将代码添加到答案中。 - Sprotty

1
使用 System.Management 可以提取所有硬件信息。通过这些值,您可以创建一个 ID,可能是加密的,然后保存它。
这里有一个参考链接: Link 我使用 MAC 地址和主板 ID,对我很有效。
希望这可以帮到您!

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