3

I am working on a software lock using C#. I need to generate a unique number for every computer.

I have researched and decided to use the CPU number and hard drive number as a unique number for every computer.

My Code :

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;
}

That works, but there is a problem! When a user re-installs Windows (OS) and wants to run my software, the unique number has been changed. Why does the unique number change when Windows is installed again? Do the CPU number and HDD number depend on the current windows installation?

Blackwood
  • 4,504
  • 16
  • 32
  • 41
saeed
  • 49
  • 2
  • 8
  • Or [Get Hard disk serial Number](http://stackoverflow.com/questions/4084402/get-hard-disk-serial-number) for example, or mix some values. – Reza Aghaei Nov 19 '16 at 18:23
  • @Qrchack no the content of question is different – saeed Nov 19 '16 at 18:30
  • Why not use the computer's MAC address, which you can get from the Win32_NetworkAdapterConfiguration ? – J. McCabe Nov 19 '16 at 18:30
  • @J.McCabe All of computers have network adapter? – saeed Nov 19 '16 at 18:31
  • They all have MAC addresses – J. McCabe Nov 19 '16 at 18:32
  • @J.McCabe I suspect all PCs have Card network – saeed Nov 19 '16 at 18:34
  • 1
    Nothing will ever be 100% static and reliable. For instance the motherboard serial could change if the user has to replace a faulty one. Create a hash of several things in the system and be prepared to have to issue a replacement license under certain conditions – Ňɏssa Pøngjǣrdenlarp Nov 19 '16 at 18:40
  • 1
    So if i change my hardware, I can not use my legally obtained software? – Hasan Emrah Süngü Nov 19 '16 at 18:40
  • 1
    @saeed it is *not* different. You want a way to uniquely identify a computer, at least in the title (because for some reason your title question and post question are totally different). So I gave you a list of things to consider and now you call that off-topic lol – Qrchack Nov 19 '16 at 18:42
  • I'm not sure about the CPU number, though I think it is often blocked for privacy reasons. The volume serial number is just that, the serial number of the file system, nothing to do with the serial number of the hard disk drive. The de-facto standard is to use the MAC address on the motherboard's built-in network adapter. – Harry Johnston Nov 19 '16 at 22:17

2 Answers2

4

You realistically have MotherboardID, CPUID, Disk Serial and MAC address, from experience none of them are 100%.

Our stats show

  • Disk serial Is missing 0.1 %
  • MAC Is missing 1.3 %
  • Motherboard ID Is missing 30 %
  • CPUID Is missing 99 %

0.04% of machines tested they yielded no information, we couldn't even read the computer name. It maybe that these were some kind over virtual PC, HyperV or VMWare instance?

Disk serial is the most reliable, but easy to change, mac can be changed and depending on the filtering applied can change if device drivers are added (hyperv, wireshark etc).

Motherboard and CPUID sometimes return values that are placeholders "NONE" etc.

You should also note that these functions can be very slow to call (they may take a few seconds even on a fast PC), so it may be worth kicking them off on a background thread as early as possible, you ideally don't want to be blocking on them.

Motherboard 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 Adress of first card

    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(":", "");
    }

Drive Serial Number

    /// <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);
Sprotty
  • 5,676
  • 3
  • 33
  • 52
1

Using System.Management you can extract all Hardware information. with this you can create an ID from this values, meaby a crypted id and save it.

Here is a reference: Link

I use MAC Address, Motherboard id and works fine to me.

I hope this help!

M84
  • 727
  • 6
  • 14