C#软件license管理(简单软件注册机制)
最近做了一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制。事出突然,只能在现场开发(离开现场软件就不受我们控了)。花了不到两个小时实现了简单的注册机制,稍作整理。
基本原理:1.软件一运行就把计算机的CPU、主板、BIOS、MAC地址记录下来,然后加密(key=key1)生成文件;2.注册机将该文件内容MD5加密后再进行一次加密(key=key2)保存成注册文件;3.注册验证的逻辑,计算机信息加密后(key=key1)加密md5==注册文件解密(key=key2);
另外,采用ConfuserEx将可执行文件加密;这样别人要破解也就需要点力气了(没打算防破解,本意只想防复制的),有能力破解的人也不在乎破解这个软件了(开发这个软件前后只花了一周时间而已);
技术上主要三个模块:1.获取电脑相关硬件信息(可参考);2.加密解密;3.读写文件;
1.获取电脑相关硬件信息代码:
- public class ComputerInfo
- {
- public static string GetComputerInfo()
- {
- string info = string.Empty;
- string cpu = GetCPUInfo();
- string baseBoard = GetBaseBoardInfo();
- string bios = GetBIOSInfo();
- string mac = GetMACInfo();
- info = string.Concat(cpu, baseBoard, bios, mac);
- return info;
- }
- private static string GetCPUInfo()
- {
- string info = string.Empty;
- info = GetHardWareInfo("Win32_Processor", "ProcessorId");
- return info;
- }
- private static string GetBIOSInfo()
- {
- string info = string.Empty;
- info = GetHardWareInfo("Win32_BIOS", "SerialNumber");
- return info;
- }
- private static string GetBaseBoardInfo()
- {
- string info = string.Empty;
- info = GetHardWareInfo("Win32_BaseBoard", "SerialNumber");
- return info;
- }
- private static string GetMACInfo()
- {
- string info = string.Empty;
- info = GetHardWareInfo("Win32_BaseBoard", "SerialNumber");
- return info;
- }
- private static string GetHardWareInfo(string typePath, string key)
- {
- try
- {
- ManagementClass managementClass = new ManagementClass(typePath);
- ManagementObjectCollection mn = managementClass.GetInstances();
- PropertyDataCollection properties = managementClass.Properties;
- foreach (PropertyData property in properties)
- {
- if (property.Name == key)
- {
- foreach (ManagementObject m in mn)
- {
- return m.Properties[property.Name].Value.ToString();
- }
- }
- }
- }
- catch (Exception ex)
- {
- //这里写异常的处理
- }
- return string.Empty;
- }
- private static string GetMacAddressByNetworkInformation()
- {
- string key = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
- string macAddress = string.Empty;
- try
- {
- NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
- foreach (NetworkInterface adapter in nics)
- {
- if (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet
- && adapter.GetPhysicalAddress().ToString().Length != 0)
- {
- string fRegistryKey = key + adapter.Id + "\\Connection";
- RegistryKey rk = Registry.LocalMachine.OpenSubKey(fRegistryKey, false);
- if (rk != null)
- {
- string fPnpInstanceID = rk.GetValue("PnpInstanceID", "").ToString();
- int fMediaSubType = Convert.ToInt32(rk.GetValue("MediaSubType", 0));
- if (fPnpInstanceID.Length > 3 &&
- fPnpInstanceID.Substring(0, 3) == "PCI")
- {
- macAddress = adapter.GetPhysicalAddress().ToString();
- for (int i = 1; i < 6; i++)
- {
- macAddress = macAddress.Insert(3 * i - 1, ":");
- }
- break;
- }
- }
- }
- }
- }
- catch (Exception ex)
- {
- //这里写异常的处理
- }
- return macAddress;
- }
- }
2.加密解密代码;
- public enum EncryptionKeyEnum
- {
- KeyA,
- KeyB
- }
- public class EncryptionHelper
- {
- string encryptionKeyA = "pfe_Nova";
- string encryptionKeyB = "WorkHard";
- string md5Begin = "Hello";
- string md5End = "World";
- string encryptionKey = string.Empty;
- public EncryptionHelper()
- {
- this.InitKey();
- }
- public EncryptionHelper(EncryptionKeyEnum key)
- {
- this.InitKey(key);
- }
- private void InitKey(EncryptionKeyEnum key = EncryptionKeyEnum.KeyA)
- {
- switch (key)
- {
- case EncryptionKeyEnum.KeyA:
- encryptionKey = encryptionKeyA;
- break;
- case EncryptionKeyEnum.KeyB:
- encryptionKey = encryptionKeyB;
- break;
- }
- }
- public string EncryptString(string str)
- {
- return Encrypt(str, encryptionKey);
- }
- public string DecryptString(string str)
- {
- return Decrypt(str, encryptionKey);
- }
- public string GetMD5String(string str)
- {
- str = string.Concat(md5Begin, str, md5End);
- MD5 md5 = new MD5CryptoServiceProvider();
- byte[] fromData = Encoding.Unicode.GetBytes(str);
- byte[] targetData = md5.ComputeHash(fromData);
- string md5String = string.Empty;
- foreach (var b in targetData)
- md5String += b.ToString("x2");
- return md5String;
- }
- private string Encrypt(string str, string sKey)
- {
- DESCryptoServiceProvider des = new DESCryptoServiceProvider();
- byte[] inputByteArray = Encoding.Default.GetBytes(str);
- des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
- des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
- MemoryStream ms = new MemoryStream();
- CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
- cs.Write(inputByteArray, 0, inputByteArray.Length);
- cs.FlushFinalBlock();
- StringBuilder ret = new StringBuilder();
- foreach (byte b in ms.ToArray())
- {
- ret.AppendFormat("{0:X2}", b);
- }
- ret.ToString();
- return ret.ToString();
- }
- private string Decrypt(string pToDecrypt, string sKey)
- {
- DESCryptoServiceProvider des = new DESCryptoServiceProvider();
- byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
- for (int x = 0; x < pToDecrypt.Length / 2; x++)
- {
- int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
- inputByteArray[x] = (byte)i;
- }
- des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
- des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
- MemoryStream ms = new MemoryStream();
- CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
- cs.Write(inputByteArray, 0, inputByteArray.Length);
- cs.FlushFinalBlock();
- StringBuilder ret = new StringBuilder();
- return System.Text.Encoding.Default.GetString(ms.ToArray());
- }
- }
注:这边在MD5时前后各加了一段字符,这样增加一点破解难度。
3.读写文件
- public class RegistFileHelper
- {
- public static string ComputerInfofile = "ComputerInfo.key";
- public static string RegistInfofile = "RegistInfo.key";
- public static void WriteRegistFile(string info)
- {
- WriteFile(info, RegistInfofile);
- }
- public static void WriteComputerInfoFile(string info)
- {
- WriteFile(info, ComputerInfofile);
- }
- public static string ReadRegistFile()
- {
- return ReadFile(RegistInfofile);
- }
- public static string ReadComputerInfoFile()
- {
- return ReadFile(ComputerInfofile);
- }
- public static bool ExistComputerInfofile()
- {
- return File.Exists(ComputerInfofile);
- }
- public static bool ExistRegistInfofile()
- {
- return File.Exists(RegistInfofile);
- }
- private static void WriteFile(string info, string fileName)
- {
- try
- {
- using (StreamWriter sw = new StreamWriter(fileName, false))
- {
- sw.Write(info);
- sw.Close();
- }
- }
- catch (Exception ex)
- {
- }
- }
- private static string ReadFile(string fileName)
- {
- string info = string.Empty;
- try
- {
- using (StreamReader sr = new StreamReader(fileName))
- {
- info = sr.ReadToEnd();
- sr.Close();
- }
- }
- catch (Exception ex)
- {
- }
- return info;
- }
- }
4.其他界面代码:
主界面代码:
- public partial class FormMain : Form
- {
- private string encryptComputer = string.Empty;
- private bool isRegist = false;
- private const int timeCount = 30;
- public FormMain()
- {
- InitializeComponent();
- Control.CheckForIllegalCrossThreadCalls = false;
- }
- private void FormMain_Load(object sender, EventArgs e)
- {
- string computer = ComputerInfo.GetComputerInfo();
- encryptComputer = new EncryptionHelper().EncryptString(computer);
- if (CheckRegist() == true)
- {
- lbRegistInfo.Text = "已注册";
- }
- else
- {
- lbRegistInfo.Text = "待注册,运行十分钟后自动关闭";
- RegistFileHelper.WriteComputerInfoFile(encryptComputer);
- TryRunForm();
- }
- }
- /// <summary>
- /// 试运行窗口
- /// </summary>
- private void TryRunForm()
- {
- Thread threadClose = new Thread(CloseForm);
- threadClose.IsBackground = true;
- threadClose.Start();
- }
- private bool CheckRegist()
- {
- EncryptionHelper helper = new EncryptionHelper();
- string md5key = helper.GetMD5String(encryptComputer);
- return CheckRegistData(md5key);
- }
- private bool CheckRegistData(string key)
- {
- if (RegistFileHelper.ExistRegistInfofile() == false)
- {
- isRegist = false;
- return false;
- }
- else
- {
- string info = RegistFileHelper.ReadRegistFile();
- var helper = new EncryptionHelper(EncryptionKeyEnum.KeyB);
- string registData = helper.DecryptString(info);
- if (key == registData)
- {
- isRegist = true;
- return true;
- }
- else
- {
- isRegist = false;
- return false;
- }
- }
- }
- private void CloseForm()
- {
- int count = 0;
- while (count < timeCount && isRegist == false)
- {
- if (isRegist == true)
- {
- return;
- }
- Thread.Sleep(1 * 1000);
- count++;
- }
- if (isRegist == true)
- {
- return;
- }
- else
- {
- this.Close();
- }
- }
- private void btnRegist_Click(object sender, EventArgs e)
- {
- if (lbRegistInfo.Text == "已注册")
- {
- MessageBox.Show("已经注册~");
- return;
- }
- string fileName = string.Empty;
- OpenFileDialog openFileDialog = new OpenFileDialog();
- if (openFileDialog.ShowDialog() == DialogResult.OK)
- {
- fileName = openFileDialog.FileName;
- }
- else
- {
- return;
- }
- string localFileName = string.Concat(
- Environment.CurrentDirectory,
- Path.DirectorySeparatorChar,
- RegistFileHelper.RegistInfofile);
- if (fileName != localFileName)
- File.Copy(fileName, localFileName, true);
- if (CheckRegist() == true)
- {
- lbRegistInfo.Text = "已注册";
- MessageBox.Show("注册成功~");
- }
- }
- }
注册机代码:
- public partial class FormMain : Form
- {
- public FormMain()
- {
- InitializeComponent();
- }
- private void btnRegist_Click(object sender, EventArgs e)
- {
- string fileName = string.Empty;
- OpenFileDialog openFileDialog = new OpenFileDialog();
- if (openFileDialog.ShowDialog() == DialogResult.OK)
- {
- fileName = openFileDialog.FileName;
- }
- else
- {
- return;
- }
- string localFileName = string.Concat(
- Environment.CurrentDirectory,
- Path.DirectorySeparatorChar,
- RegistFileHelper.ComputerInfofile);
- if (fileName != localFileName)
- File.Copy(fileName, localFileName, true);
- string computer = RegistFileHelper.ReadComputerInfoFile();
- EncryptionHelper help = new EncryptionHelper(EncryptionKeyEnum.KeyB);
- string md5String = help.GetMD5String(computer);
- string registInfo = help.EncryptString(md5String);
- RegistFileHelper.WriteRegistFile(registInfo);
- MessageBox.Show("注册码已生成");
- }
- }

最后采用ConfuserEx将可执行文件加密(ConfuserEx介绍),这样就不能反编译获得源码。
至此全部完成,只是个人的一些实践,对自己是一个记录,同时希望也能对别人有些帮助,如果有什么错误,还望不吝指出,共同进步,转载请保留原文地址。
C#软件license管理(简单软件注册机制)的更多相关文章
- C#实现软件授权,限定MAC运行(软件license管理,简单软件注册机制)
一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制.事出突然,只能在现场开发(离开现场软件就不受我们控了).花了不到两个小时实现了简单的注册机制,稍作整理. 基本原理:1.软件一运 ...
- C# 简单软件有效期注册的实现
◆需求:公司一直以来对开发的产品都没有进行使用时间的控制,要么就是将日期限制写死在程序里面,每次都要编译新程序再发给客户,很不方便.于是公司让我写个模块,要求如下:1.无论哪个新开发的程序只要调用这个 ...
- 软件License设计
如何保护软件版权,最常用的办法就是设计一套license验证框架. 1.我们的常规需求如下: .可以限制软件只能在一台机器上使用: 目前很多软件都是一机一码的销售,软件换一台机器则不能使用,想要几台机 ...
- Linux软件安装管理
1.软件包管理简介 1.软件包分类 源码包 脚本安装包 二进制包(RPM包.系统默认包) 2.源码包 源码包的优点是: 开源,如果有足够的能力,可以修改源代码 可以自由选择所需要的功能 软件设计编译安 ...
- 软件License认证方案的设计思路
销售license是商业软件的贯用商业模式.用户向商家购买软件安装盘搭载license许可,才可以使用该软件.我们作为软件开发者,为了保护自身的权益,在软件开发过程中也不可避免的会设计license管 ...
- Linux 学习 (十一) 软件安装管理
Linux软件安装管理 学习笔记 软件包简介 软件包分类: 源码包 :脚本安装包 二进制包(RPM 包.系统默认包) 源码包的优点: 开源,如果有足够的能力,可以修改源代码 可以自由选择所需的功能 软 ...
- MySQL介绍及安装&MySQL软件基本管理
mysql介绍 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下公司.MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是最好 ...
- Ubuntu的软件安装管理---dpkg与apt-*详解
摘要:软件厂商先在他们的系统上面编译好了我们用户所需要的软件,然后将这个编译好并可执行的软件直接发布给用户安装.不同的 Linux 发行版使用不同的打包系统,一般而言,大多数发行版分别属于两大包管理技 ...
- [MySQL数据库之数据库相关概念、MySQL下载安装、MySQL软件基本管理、SQL语句]
[MySQL数据库之数据库相关概念.MySQL下载安装.MySQL软件基本管理.SQL语句] 数据库相关概念 数据库管理软件的由来 数据库管理软件:本质就是个C/S架构的套接字程序. 我们在编写任何程 ...
随机推荐
- Python_oldboy_自动化运维之路_全栈考试(七)
1. 计算100-300之间所有能被3和7整除的所有数之和 # -*- coding: UTF-8 -*- #blog:http://www.cnblogs.com/linux-chenyang/ c ...
- Matlab读取txt中用空格分隔的数据文件到矩阵
转载...哪儿 忘记了 由于要做的项目中涉及到数据处理,初涉及到matlab.今天需要把一组只用空格分开的数据读取到一个三维矩阵,然后对这个矩阵进行处理. 思路是:首先用importdata读入txt ...
- 异步消息框架netty
Netty-WebSocket长连接推送服务 http://blog.csdn.net/z69183787/article/details/52505249 http://blog.csdn.net/ ...
- Python基础 - MySQLdb模块
安装 pip install MySQLdb 使用 去除一个数据库中所有的表 import MySQLdb def db_test(): conn = MySQLdb.connect(user='&l ...
- AdvStringGrid 列宽度、列移动、行高度、自动调节
那么有没有办法,让客户自己去调整列的宽度呢? 那么有没有办法 让列宽度.行高度 随着内容而自动变换呢: unit Unit5; interface uses Winapi.Windows, Winap ...
- C#和PHP 长整型时间互转
//2018/5/14 16:03:05转换:1526284985 public static double ConvertToDouble(DateTime date) { , , )); var ...
- Spark(十一)Spark分区
一.分区的概念 分区是RDD内部并行计算的一个计算单元,RDD的数据集在逻辑上被划分为多个分片,每一个分片称为分区,分区的格式决定了并行计算的粒度,而每个分区的数值计算都是在一个任务中进行的,因此任务 ...
- linux 101 hacks 4stat diff ac
stat 命令 stat 命令那个可以用来查看文件或者文件系统的状态和属性.显示一个文件或目录的属性 $ stat /etc/my.cnf File: `/etc/my.cnf' Size: Bloc ...
- jquery 分页 下拉框
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Java 中byte 与 char 的相互转换 Java基础 但是很重要
char转化为byte: public static byte[] charToByte(char c) { byte[] b = new byte[2]; b[0] = ...