I am trying to implement Hardware locked Licensing.I found the following code from codeproject that generates hardware id(Machine ID)
This code generates Hardware Key
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
}
}
.My aim is to implement strict licensing scheme.As shown in the diagram given below,I am able to generate a unique machine or Hardware ID using the above code.
Based on the Machine ID or Key,I wish to generate an Activation Key so that it would be unique and can be used only on one machine because the Activation key would be generated from that Machines MachineID
How can that be achieved?
Following is the image
I hope my doubt is clear.If not please let me know,I'll update the question with more information
The simple solution
The simple solution would be something like this. When the user buys your software, generate a unique GUID for the license. Let's call this the license key. When the user installs the software, you take your unique hardware key, concatenate that with the license key, and hash the result. The hash you generate will be the activation code that you're looking for. Store that value on your server. If the same license key is ever used to install the software on another machine, you will compare the computed activation code for that installation against the one you have stored on your server and deny the installation if the codes do not match.
The Catch
That being said... the way your current scheme is set up, you are going to risk making your customers very upset. For example, if I buy your software and my hard drive dies on me, with your current setup I would have no way to recover my software. If you're going to do hardware signature based licensing, you should try to restrict it to the features that are least likely to change. BIOS...ok maybe you're safe. But hard drive, network card, video card are much more likely to change.
Also, you might want to give your customers a way to transfer the license to another computer. The way your do this is have a custom action in your uninstaller that will revoke the activation code for the license so it will no longer be tied to that hardware ID.
Conclusion
In all of this, the key is to keep things as simple as possible for your customer. There obviously is a trade-off between security and ease of use, but you DO NOT want to lock out legitimate customers and risk alienating them.
All that being said, there are also plenty of existing commercials options for managing licenses. QLM is pretty good is you're willing to shell out the money. In everything, just consider the cost of securing your software versus the value of securing it.
Related
I was following this tutorial to generate a unique hardware ID for system. The problem is that the ID generated is different when internet is connected, and different when internet is disconnected.
This is the code I'm using:
private static string fingerPrint = string.Empty;
public static string GetUniqueID()
{
if (string.IsNullOrEmpty(fingerPrint))
{
fingerPrint = GetHash("CPU " + cpuId() + "\nBIOS " +
biosId() + "\nBASE " + baseId()
+ "\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;
}
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;
}
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)
{
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
private static string cpuId()
{
string retVal = identifier("Win32_Processor", "UniqueId");
if (retVal == "")
{
retVal = identifier("Win32_Processor", "ProcessorId");
if (retVal == "")
{
retVal = identifier("Win32_Processor", "Name");
if (retVal == "")
{
retVal = identifier("Win32_Processor", "Manufacturer");
}
retVal += identifier("Win32_Processor", "MaxClockSpeed");
}
}
return retVal;
}
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");
}
private static string diskId()
{
return identifier("Win32_DiskDrive", "Model")
+ identifier("Win32_DiskDrive", "Manufacturer")
+ identifier("Win32_DiskDrive", "Signature")
+ identifier("Win32_DiskDrive", "TotalHeads");
}
private static string baseId()
{
return identifier("Win32_BaseBoard", "Model")
+ identifier("Win32_BaseBoard", "Manufacturer")
+ identifier("Win32_BaseBoard", "Name")
+ identifier("Win32_BaseBoard", "SerialNumber");
}
private static string videoId()
{
return identifier("Win32_VideoController", "DriverVersion")
+ identifier("Win32_VideoController", "Name");
}
private static string macId()
{
return identifier("Win32_NetworkAdapterConfiguration",
"MACAddress", "IPEnabled");
}
GetUniqueID() is the function which hashes the various IDs. Why is the ID generated different with and without internet?
I think its because when you are disconnected, your network interface is disabled and as such, it is unable to retrieve MAC address.
instead of this 1000s of lines of complex logic, can't you simple use MAC id of the device. It will remain same all the time or Device Serial Key that is Bios serial of the device. Bios key will be available even if there's no network.
My team once tried to build a similar piece of code to generate a unique id based off of machine settings without using persistent storage. E.g Hash(hostname, username, domain name, mac address, etc...). Seemed like a good idea at the time, but turns out to be inherently unreliable as some of the APIs that should be consistent at returning these values, aren't always so.
The simpler and more reliable approach is to generate a GUID and persist it to the registry (or file on disk, or even the Windows Credential Store).
static string GetUniqueID()
{
string result;
string registry_path = "HKEY_CURRENT_USER\\Software\\MyApp"; // substitue your own app name here
Object obj = Registry.GetValue(registry_path, "UniqueID", null);
if ((obj == null) || !(obj is string))
{
result = Guid.NewGuid().ToString();
Registry.SetValue(registry_path, "UniqueID", result);
}
else
{
result = (string)obj;
}
return result;
}
It's also faster than making WMI calls too.
I think you’ve picked a wrong tutorial.
MAC changes when you connect/disconnect due to the 2 reasons. First, most PCs have more than 1 network card, and the order in which they appear in WMI is undefined. Second, by default, Windows 10 sometimes randomizes WiFi MAC address each time you connect to a WiFi network
The rest of the IDs you’re using are not much better.
videoId is unstable because driver version will update when you update the driver, BTW some windows updates include new versions of GPU drivers
diskId is unstable because users plug USB flash drives or external hard drives.
cpuId is unreliable because it only include information specific to CPU model, i.e. for a mainstream CPU you’ll have many millions of people in the world with the same cpuId.
I need to get the 'Commit size' (Windows Task Manager > Details) of a process in C#.
At first sight the Process class does not provide a relevant property.
Can somebody help me?
Edited
private static void ShowCommitSize(string processName)
{
Process process = Process.GetProcessesByName(processName).FirstOrDefault();
if (process != null)
{
var pagedMemMb = ConvertBytesToMegabytes(process.PagedMemorySize64);
Console.WriteLine(process.ProcessName + "\t" + process.Id + "\t" + Math.Round(pagedMemMb, 3) + " MB");
}
Console.ReadLine();
}
static double ConvertBytesToMegabytes(long bytes)
{
return (bytes / 1024f) / 1024f;
}
Output
There is a difference between my calculated Commit Size and the 'Commit Size' in Task Manager. Any ideas?
Solution
private static void ShowCommitSize(string processName)
{
var process = Process.GetProcessesByName(processName).FirstOrDefault();
if (process != null)
{
var memKb = ConvertBytesToKilobytes(process.PagedMemorySize64);
Console.WriteLine(process.ProcessName + "\t" + process.Id + "\t" + memKb.ToString("N") + " K");
}
Console.ReadLine();
}
static double ConvertBytesToKilobytes(long bytes)
{
return (bytes / 1024f);
}
This value is in the PagedMemorySize64 property. The documentation mentions that this the "Page File Size" process performance counter and over here it is documented that this is referred to as "Commit Size" in Task Manager on Vista/2008 (and I would assume newer OSes).
I'm using the following class to generate a unique hardware ID for a basic software licencing system.
The problem is that in some cases the fingerprint produced is different, without any hardware change.
I have not developed a client-side debugging system to isolate the component that causes the problem, so i'd like to ask if and under what conditions the following code could generate different IDs for the same hardware.
I already removed the network adaptor part (caused variations when many adaptors existed) and the hard disk part (problems when a usb drive was attached).
But the remaining components' IDs should remain the same, even after software changes and windows updates, isn't so?
public static class FingerPrint
{
private static string fingerPrint = string.Empty;
//--------------------------------------
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
//--------------------------------------
public static string Value()
{
string cpu = cpuId();
string bios = biosId();
string bas = baseId();
string video = videoId();
if (string.IsNullOrEmpty(fingerPrint))
{
fingerPrint = GetHash("CPU >> " + cpu + "\nBIOS >> " +
bios + "\nBASE >> " + bas
+ "\nVIDEO >> " + video
+ "\n some_salt");
}
return Base64Encode(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;
}
//--------------------------------------
//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 == "")
{
result = mo[wmiProperty].ToString();
break;
}
}
}
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 == "")
{
result = mo[wmiProperty].ToString();
break;
}
}
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");
}
}
}
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");
}
//--------------------------------------
//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", "Name");
}
}
I'm using this code to get cpu temperature, but I'm getting 'not supported' instead of the temperature.
public static string getCpuTemperature()
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSAcpi_ThermalZoneTemperature");
//Win32_TemperatureProbe
foreach (ManagementObject queryObj in searcher.Get())
{
double temp = Convert.ToDouble(queryObj["CurrentTemperature"].ToString());
double temp_critical = Convert.ToDouble(queryObj["CriticalTripPoint"].ToString());
double temp_cel = (temp / 10 - 273.15);
double temp_critical_cel = temp_critical / 10 - 273.15;
return temp_cel.ToString() + " _ " + temp_critical_cel.ToString();
}
}
catch (ManagementException e)
{
//MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
return e.Message.ToString();
}
return "";
}
I've googled the problem and have seen many answers for this including,
- the motherboard doesn't support this feature
- run VS with administration right
etc...
but none of them are true, because programs like OpenHardwareMonitor and SpeedFan show the temperature of cpu and gpu, Hdd temperature, cpu fan speed, and all other informations.
I want to know how do they do that? how is that I get 'not supported' message and these programs don't.
This is not a complete answer but hopefully it helps.
After perusing the code at https://code.google.com/p/open-hardware-monitor/source/browse/trunk/, I can't fully understand this code without downloading it all and investigating further.
The magic seems to happen here,
public override void Update() {
base.Update();
for (int i = 0; i < coreTemperatures.Length; i++) {
uint eax, edx;
// if reading is valid
if (Ring0.RdmsrTx(IA32_THERM_STATUS_MSR, out eax, out edx,
1UL << cpuid[i][0].Thread) && (eax & 0x80000000) != 0)
{
// get the dist from tjMax from bits 22:16
float deltaT = ((eax & 0x007F0000) >> 16);
float tjMax = coreTemperatures[i].Parameters[0].Value;
float tSlope = coreTemperatures[i].Parameters[1].Value;
coreTemperatures[i].Value = tjMax - tSlope * deltaT;
} else {
coreTemperatures[i].Value = null;
}
}
...
This code extracts the temperature data from the result of Ring0.RdmsrTx.
I believe Ring0 is a C implementation of a ring buffer, the code of which is in the repository here. This reads the Model Specific Register data from the CPU driver.
There is more detail in this question.
Easiest way would be probably to find a tool that can output the information you need in machine-readable way and then process that output. SpeedFan logs temperature to logs, you could just read the latest reading from the logs.
I realize this might not be an ideal solution, but it is the only universal. Querying CPU temperature in a Windows system is not an easy task.
I'm probably very late to answer this, but just in case someone stumbles upon this in the future, here's the way I did it:
public string getCPUTemp()
{
UpdateVisitor updateVisitor = new UpdateVisitor();
Computer computer = new Computer();
computer.Open();
computer.CPUEnabled = true;
computer.Accept(updateVisitor);
string res = "";
for (int i = 0; i < computer.Hardware.Length; i++)
{
if (computer.Hardware[i].HardwareType == HardwareType.CPU)
{
for (int j = 0; j < computer.Hardware[i].Sensors.Length; j++)
{
if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature) res = String.Concat(res, (computer.Hardware[i].Sensors[j].Name + ": " + computer.Hardware[i].Sensors[j].Value.ToString() + "ºC" + "\r"));
if (computer.Hardware[i].Sensors[j].Value.ToString() == "") { res = ""; return res; }
}
}
}
It worked perfectly with me (even though it didn't work for the GPU part). You just have to download OpenHardwareMonitor (https://openhardwaremonitor.org/), then add the reference to the OpenHardwareMonitorLib.dll which is in the \openhardwaremonitor\Bin\Debug folder, then add "using OpenHardwareMonitor.Hardware;" at the top.
Hope it can still help someone even if not OP!
In my application, I am gathering data regarding the performance of system, where I need to find
% Free Space
% Disk Time
% Disk Read Time
% Disk Write Time
% Idle Time
% Usage
% Usage Peak
using below function;
private void CollectnPopulatePerfCounters()
{
try
{
foreach (var pc in System.Diagnostics.PerformanceCounterCategory.GetCategories())
{
if (pc.CategoryName == "LogicalDisk" || pc.CategoryName == "Paging File" || pc.CategoryName == "ProcessorPerformance")
{
try
{
foreach (var insta in pc.GetInstanceNames())
{
try
{
foreach (PerformanceCounter cntr in pc.GetCounters(insta))
{
using (System.IO.StreamWriter sw = new System.IO.StreamWriter("C:\\amit.txt", true))
{
sw.WriteLine("--------------------------------------------------------------------");
sw.WriteLine("Category Name : " + pc.CategoryName);
sw.WriteLine("Counter Name : " + cntr.CounterName);
sw.WriteLine("Explain Text : " + cntr.CounterHelp);
sw.WriteLine("Instance Name: " + cntr.InstanceName);
sw.WriteLine("Value : " + Convert.ToString(cntr.RawValue)); //TODO:
sw.WriteLine("Counter Type : " + cntr.CounterType);
sw.WriteLine("--------------------------------------------------------------------");
}
}
}
catch (Exception) { }
}
}
catch (Exception) { }
}
}
}
catch (Exception) { }
}
When the code is executed the data is generated. While observing I found that the value against the above mentioned list [i.e. % free space, % disk time etc.] is not in correct form.
On my machine the value for
% Disk Read Time = 44553438000 for C Drive
% Usage Peak = 48386 for \??\C:\pagefile.sys
actually the value should be in the percent form [i.e within the range of 0 to 100 %]
Is there any way to get the exact value for all these except [% free Space for which I have calculated].
Or
Does anyone know how to calculate for rest of all headers.
Use following
sw.WriteLine("Value : " + Convert.ToString(Math.Round(cntr.NextValue(),2)) + "%");
More info at:
Why the cpu performance counter kept reporting 0% cpu usage?
All the best!
Don't forget to vote :-D