50

I need in my program to tie a license to a hardware ID. I tried use WMI, but it still slow.

I need, for example, CPU, HDD, and motherboard info.

dsolimano
  • 8,870
  • 3
  • 48
  • 63
guaike
  • 2,471
  • 9
  • 31
  • 42

6 Answers6

80

For more details refer to this link

The following code will give you CPU ID:

namespace required System.Management

var mbs = new ManagementObjectSearcher("Select ProcessorId From Win32_processor");
ManagementObjectCollection mbsList = mbs.Get();
string id = "";
foreach (ManagementObject mo in mbsList)
{
    id = mo["ProcessorId"].ToString();
    break;
}

For Hard disk ID and motherboard id details refer this-link

To speed up this procedure, make sure you don't use SELECT *, but only select what you really need. Use SELECT * only during development when you try to find out what you need to use, because then the query will take much longer to complete.

ANeves
  • 6,219
  • 3
  • 39
  • 63
HotTester
  • 5,620
  • 15
  • 63
  • 97
  • 19
    Be warned, though, that these ids are not neccesarily unique, or even existant. The processorID just identifies the processor design, the VolumeSerialnumber can be changed by the user and there are mainboard manufacturers that do not set a Serialnumber. – Jens Feb 25 '10 at 10:39
  • 1
    The best way to generate a unique id is to make a id by combination of all of these id's i.e. cpu id, motherboard id and hard disk id. – HotTester Feb 25 '10 at 10:55
  • 1
    Thank you for your reply,But i think WMI still slow,do you have any other way with out WMI – guaike Feb 25 '10 at 14:47
  • You say that WMI is slow, but how often do you run these checks? You only really need to check it at startup, then at random intervals from different places. If it's blocking your app, you can move the check to a background thread, just make sure you keep all the calls to the routines on the same thread and Dispose your objects appropriately (due to COM rules). – Garo Yeriazarian Jan 07 '11 at 14:23
  • 2
    The original post shows that the ID is needed for a security (license) system. However, the code provided in the answers is reading the info from MS Windows. It is piece-a-cake to modify that information. However, the Hardware ID Extractor DLL gets the information directly from the CPU (hardware level). You cannot change the hardware ID of a CPU (unless you melt the CPU and rebuild it :) ) – thelight Mar 15 '14 at 14:23
  • 2
    Benchmark: when my code uses `Select * From Win32_processor` it takes ~1s to run, when it uses `Select ProcessorId From Win32_processor` it takes ~0.01s! – ANeves Oct 12 '17 at 17:41
27

I got here looking for the same thing and I found another solution. If you guys are interested I share this class:

using System;
using System.Management;
using System.Security.Cryptography;
using System.Security;
using System.Collections;
using System.Text;
namespace Security
{
    /// <summary>
    /// Generates a 16 byte Unique Identification code of a computer
    /// Example: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9
    /// </summary>
    public class FingerPrint  
    {
        private static string fingerPrint = string.Empty;
        public static string Value()
        {
            if (string.IsNullOrEmpty(fingerPrint))
            {
                fingerPrint = GetHash("CPU >> " + cpuId() + "\nBIOS >> " + 
            biosId() + "\nBASE >> " + baseId() +
                            //"\nDISK >> "+ diskId() + "\nVIDEO >> " + 
            videoId() +"\nMAC >> "+ macId()
                                     );
            }
            return fingerPrint;
        }
        private static string GetHash(string s)
        {
            MD5 sec = new MD5CryptoServiceProvider();
            ASCIIEncoding enc = new ASCIIEncoding();
            byte[] bt = enc.GetBytes(s);
            return GetHexString(sec.ComputeHash(bt));
        }
        private static string GetHexString(byte[] bt)
        {
            string s = string.Empty;
            for (int i = 0; i < bt.Length; i++)
            {
                byte b = bt[i];
                int n, n1, n2;
                n = (int)b;
                n1 = n & 15;
                n2 = (n >> 4) & 15;
                if (n2 > 9)
                    s += ((char)(n2 - 10 + (int)'A')).ToString();
                else
                    s += n2.ToString();
                if (n1 > 9)
                    s += ((char)(n1 - 10 + (int)'A')).ToString();
                else
                    s += n1.ToString();
                if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
            }
            return s;
        }
        #region Original Device ID Getting Code
        //Return a hardware identifier
        private static string identifier
        (string wmiClass, string wmiProperty, string wmiMustBeTrue)
        {
            string result = "";
            System.Management.ManagementClass mc = 
        new System.Management.ManagementClass(wmiClass);
            System.Management.ManagementObjectCollection moc = mc.GetInstances();
            foreach (System.Management.ManagementObject mo in moc)
            {
                if (mo[wmiMustBeTrue].ToString() == "True")
                {
                    //Only get the first one
                    if (result == "")
                    {
                        try
                        {
                            result = mo[wmiProperty].ToString();
                            break;
                        }
                        catch
                        {
                        }
                    }
                }
            }
            return result;
        }
        //Return a hardware identifier
        private static string identifier(string wmiClass, string wmiProperty)
        {
            string result = "";
            System.Management.ManagementClass mc = 
        new System.Management.ManagementClass(wmiClass);
            System.Management.ManagementObjectCollection moc = mc.GetInstances();
            foreach (System.Management.ManagementObject mo in moc)
            {
                //Only get the first one
                if (result == "")
                {
                    try
                    {
                        result = mo[wmiProperty].ToString();
                        break;
                    }
                    catch
                    {
                    }
                }
            }
            return result;
        }
        private static string cpuId()
        {
            //Uses first CPU identifier available in order of preference
            //Don't get all identifiers, as it is very time consuming
            string retVal = identifier("Win32_Processor", "UniqueId");
            if (retVal == "") //If no UniqueID, use ProcessorID
            {
                retVal = identifier("Win32_Processor", "ProcessorId");
                if (retVal == "") //If no ProcessorId, use Name
                {
                    retVal = identifier("Win32_Processor", "Name");
                    if (retVal == "") //If no Name, use Manufacturer
                    {
                        retVal = identifier("Win32_Processor", "Manufacturer");
                    }
                    //Add clock speed for extra security
                    retVal += identifier("Win32_Processor", "MaxClockSpeed");
                }
            }
            return retVal;
        }
        //BIOS Identifier
        private static string biosId()
        {
            return identifier("Win32_BIOS", "Manufacturer")
            + identifier("Win32_BIOS", "SMBIOSBIOSVersion")
            + identifier("Win32_BIOS", "IdentificationCode")
            + identifier("Win32_BIOS", "SerialNumber")
            + identifier("Win32_BIOS", "ReleaseDate")
            + identifier("Win32_BIOS", "Version");
        }
        //Main physical hard drive ID
        private static string diskId()
        {
            return identifier("Win32_DiskDrive", "Model")
            + identifier("Win32_DiskDrive", "Manufacturer")
            + identifier("Win32_DiskDrive", "Signature")
            + identifier("Win32_DiskDrive", "TotalHeads");
        }
        //Motherboard ID
        private static string baseId()
        {
            return identifier("Win32_BaseBoard", "Model")
            + identifier("Win32_BaseBoard", "Manufacturer")
            + identifier("Win32_BaseBoard", "Name")
            + identifier("Win32_BaseBoard", "SerialNumber");
        }
        //Primary video controller ID
        private static string videoId()
        {
            return identifier("Win32_VideoController", "DriverVersion")
            + identifier("Win32_VideoController", "Name");
        }
        //First enabled network card ID
        private static string macId()
        {
            return identifier("Win32_NetworkAdapterConfiguration", 
                "MACAddress", "IPEnabled");
        }
        #endregion
    }
}

I won't take any credit for this because I found it here It worked faster than I expected for me. Without the graphic card, mac and drive id's I got the unique ID in about 2-3 seconds. With those above included I got it in about 4-5 seconds.

Note: Add reference to System.Management.

Javid
  • 2,755
  • 2
  • 33
  • 60
Alex Sutu
  • 580
  • 7
  • 12
  • The DLL presented below retrieves the information in less than 1 microsecond. – thelight Mar 15 '14 at 13:45
  • This Code is Nice. Tnq – Majid Sabzalian Nov 01 '17 at 12:55
  • 1)Nice.. 2) will this still generate Same ID if i use this code 1 or 2 month later?. Will this exclude removable usb hdd, usb wifi adpter, virtual network card by virtualization softwares ?? – bh_earth0 May 30 '18 at 10:19
  • 1
    After using this code for a while - there are issues: plugging in USB drives will change the key since it pulls info from any item with no empty value. Actually the whole identifier method is written badly and calling it multiple times for each property has to create the Management Class each time... – Mladen Mihajlovic Sep 07 '20 at 15:31
  • Will MaxClockSpeed change when it is overclocked? – LostPhysx Feb 11 '21 at 11:48
23

The following approach was inspired by this answer to a related (more general) question.

The approach is to read the MachineGuid value in registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography. This value is generated during OS installation.

There are few ways around the uniqueness of the Hardware-ID per machine using this approach. One method is editing the registry value, but this would cause complications on the user's machine afterwards. Another method is to clone a drive image which would copy the MachineGuid value.

However, no approach is hack-proof and this will certainly be good enough for normal users. On the plus side, this approach is quick performance-wise and simple to implement.

public string GetMachineGuid()
{
   string location = @"SOFTWARE\Microsoft\Cryptography";
   string name = "MachineGuid";

   using (RegistryKey localMachineX64View = 
       RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
   {
       using (RegistryKey rk = localMachineX64View.OpenSubKey(location))
       {
           if (rk == null)
               throw new KeyNotFoundException(
                   string.Format("Key Not Found: {0}", location));

           object machineGuid = rk.GetValue(name);
           if (machineGuid == null)
               throw new IndexOutOfRangeException(
                   string.Format("Index Not Found: {0}", name));

           return machineGuid.ToString();
       }
   }
}
Community
  • 1
  • 1
Derek W
  • 9,708
  • 5
  • 58
  • 67
  • editing registry value is fast and `not necessarily produces problems on the user machine` - you can edit it, do what you want (in the s/w) and revert the value back. – NSGaga-mostly-inactive Jan 24 '18 at 17:32
  • not really useful, when you install bulk systems via OS images. You would have to manually set the GUID for each single machine. – Lama Dec 22 '20 at 14:21
2

We use a combination of the processor id number (ProcessorID) from Win32_processor and the universally unique identifier (UUID) from Win32_ComputerSystemProduct:

ManagementObjectCollection mbsList = null;
ManagementObjectSearcher mos = new ManagementObjectSearcher("Select ProcessorID From Win32_processor");
mbsList = mos.Get();
string processorId = string.Empty;
foreach (ManagementBaseObject mo in mbsList)
{
    processorId = mo["ProcessorID"] as string;
}

mos = new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct");
mbsList = mos.Get();
string systemId = string.Empty;
foreach (ManagementBaseObject mo in mbsList)
{
    systemId = mo["UUID"] as string;
}

var compIdStr = $"{processorId}{systemId}";

Previously, we used a combination: processor ID ("Select ProcessorID From Win32_processor") and the motherboard serial number ("SELECT SerialNumber FROM Win32_BaseBoard"), but then we found out that the serial number of the motherboard may not be filled in, or it may be filled in with uniform values:

  • To be filled by O.E.M.
  • None
  • Default string

Therefore, it is worth considering this situation.

Also keep in mind that the ProcessorID number may be the same on different computers.

Andrej
  • 141
  • 1
  • 4
1

I have refactored Alex Sutu approach to be faster and simpler code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
using System.Security.Cryptography;

namespace Test
{
    /// <summary>
    /// Generates a Guid based on the current computer hardware
    /// Example: C384B159-8E36-6C85-8ED8-6897486500FF
    /// </summary>
    public class SystemGuid
    {
        private static string _systemGuid = string.Empty;
        public static string Value()
        {
            if (string.IsNullOrEmpty(_systemGuid))
            {
                var lCpuId = GetCpuId();
                var lBiodId = GetBiosId();
                var lMainboard = GetMainboardId();
                var lGpuId = GetGpuId();
                var lMac = GetMac();
                var lConcatStr = $"CPU: {lCpuId}\nBIOS:{lBiodId}\nMainboard: {lMainboard}\nGPU: {lGpuId}\nMAC: {lMac}";
                _systemGuid = GetHash(lConcatStr);
            }
            return _systemGuid;
        }
        private static string GetHash(string s)
        {
            try
            {
                var lProvider = new MD5CryptoServiceProvider();
                var lUtf8 = lProvider.ComputeHash(ASCIIEncoding.UTF8.GetBytes(s));
                return new Guid(lUtf8).ToString().ToUpper();
            }
            catch (Exception lEx)
            {
                return lEx.Message;
            }
        }

        #region Original Device ID Getting Code
    
        //Return a hardware identifier
        private static string GetIdentifier(string pWmiClass, List<string> pProperties)
        {
            string lResult = string.Empty;
            try
            {
                foreach (ManagementObject lItem in new ManagementClass(pWmiClass).GetInstances())
                {
                    foreach (var lProperty in pProperties)
                    {
                        try
                        {
                            switch(lProperty)
                            {
                                case "MACAddress":
                                    if (string.IsNullOrWhiteSpace(lResult) == false)
                                        return lResult; //Return just the first MAC

                                    if (lItem["IPEnabled"].ToString() != "True")
                                        continue;
                                break;
                            }                                

                            var lItemProperty = lItem[lProperty];
                            if (lItemProperty == null)
                                continue;

                            var lValue = lItemProperty.ToString();
                            if (string.IsNullOrWhiteSpace(lValue) == false)
                                lResult += $"{lValue}; ";
                        }
                        catch { }
                    }

                }
            }
            catch{}
            return lResult.TrimEnd(' ', ';');
        }

        private static List<string> ListOfCpuProperties = new List<string>{ "UniqueId", "ProcessorId", "Name", "Manufacturer" };

        private static string GetCpuId()
        {
            return GetIdentifier("Win32_Processor", ListOfCpuProperties);
        }

        private static List<string> ListOfBiosProperties = new List<string> { "Manufacturer", "SMBIOSBIOSVersion", "IdentificationCode", "SerialNumber", "ReleaseDate", "Version" };
        //BIOS Identifier
        private static string GetBiosId()
        {
            return GetIdentifier("Win32_BIOS", ListOfBiosProperties);
        }

        private static List<string> ListOfMainboardProperties = new List<string> { "Model", "Manufacturer", "Name", "SerialNumber" };
        //Motherboard ID
        private static string GetMainboardId()
        {
            return GetIdentifier("Win32_BaseBoard", ListOfMainboardProperties);
        }

        private static List<string> ListOfGpuProperties = new List<string> { "Name" };
        //Primary video controller ID
        private static string GetGpuId()
        {
            return GetIdentifier("Win32_VideoController", ListOfGpuProperties);
        }

        private static List<string> ListOfNetworkProperties = new List<string> { "MACAddress" };
        private static string GetMac()
        {
            return GetIdentifier("Win32_NetworkAdapterConfiguration", ListOfNetworkProperties);
        }

        #endregion
    }
}
user2029101
  • 116
  • 9
-1

Here is a DLL that shows:
* Hard drive ID (unique hardware serial number written in drive's IDE electronic chip)
* Partition ID (volume serial number)
* CPU ID (unique hardware ID)
* CPU vendor
* CPU running speed
* CPU theoretic speed
* Memory Load ( Total memory used in percentage (%) )
* Total Physical ( Total physical memory in bytes )
* Avail Physical ( Physical memory left in bytes )
* Total PageFile ( Total page file in bytes )
* Available PageFile( Page file left in bytes )
* Total Virtual( Total virtual memory in bytes )
* Available Virtual ( Virtual memory left in bytes )
* Bios unique identification numberBiosDate
* Bios unique identification numberBiosVersion
* Bios unique identification numberBiosProductID
* Bios unique identification numberBiosVideo

(text grabbed from original web site)
It works with C#.

Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • 2
    the idea was to do it in C# – Fredrik Feb 01 '14 at 11:59
  • 2
    @ Frederic - The original post shows that the ID is needed for a security (license) system. However, the code provided in the answers is reading the info from MS Windows. It is piece-a-cake to modify that information. However, the Hardware ID Extractor DLL gets the information directly from the CPU (hardware level). You cannot change the hardware ID of a CPU (unless you melt the CPU and rebuild it :) ) – thelight Mar 15 '14 at 13:43
  • 1
    Additionally it gets the information in less than 1 microsecond. While retrieving info from MS Windows takes up to 5 seconds! – thelight Mar 15 '14 at 13:45
  • 1
    @FredrikRedin - Can't C# import DLLs? – thelight Sep 17 '15 at 08:17
  • Not always - permission wise – Roland Jun 23 '16 at 02:29
  • I keep reading that there is no unique ID for processors (or any of the hardware) burned into the chips. How come this site claims that there is (and that they can retrieve it)? – GDS Jul 11 '16 at 23:59
  • Win10 gives [warning](http://i.imgur.com/RQqkCTJ.png) that this might not be safe. Combined with screenshots from a Samsung utility, and the AV safe images being self-hosted not coming from a third party I'm concerned that even if this was a legit company at one point it may have gone rogue. – Dan Is Fiddling By Firelight Jun 15 '17 at 14:58
  • 2
    This is the scan from Google's VirusTotal.com. Only 3 (not-so-famous) antivirus products out of 62 shows a (false) positive alarm. All BIG (kaspersky, norton, panda, etc) av products shows the file clean. https://virustotal.com/en/file/ff46403f20b7434f8da6e68d6c51ea0ad9acea39b5e0f1be613d06b2461d69f7/analysis/ – Gabriel Jun 15 '17 at 16:27