最近做了一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制。事出突然,只能在现场开发(离开现场软件就不受我们控了)。花了不到两个小时实现了简单的注册机制,稍作整理。
        基本原理:1.软件一运行就把计算机的CPU、主板、BIOS、MAC地址记录下来,然后加密(key=key1)生成文件;2.注册机将该文件内容MD5加密后再进行一次加密(key=key2)保存成注册文件;3.注册验证的逻辑,计算机信息加密后(key=key1)加密md5==注册文件解密(key=key2);
另外,采用ConfuserEx将可执行文件加密;这样别人要破解也就需要点力气了(没打算防破解,本意只想防复制的),有能力破解的人也不在乎破解这个软件了(开发这个软件前后只花了一周时间而已);

技术上主要三个模块:1.获取电脑相关硬件信息(可参考);2.加密解密;3.读写文件;

1.获取电脑相关硬件信息代码:

  1. public class ComputerInfo
  2. {
  3. public static string GetComputerInfo()
  4. {
  5. string info = string.Empty;
  6. string cpu = GetCPUInfo();
  7. string baseBoard = GetBaseBoardInfo();
  8. string bios = GetBIOSInfo();
  9. string mac = GetMACInfo();
  10. info = string.Concat(cpu, baseBoard, bios, mac);
  11. return info;
  12. }
  13. private static string GetCPUInfo()
  14. {
  15. string info = string.Empty;
  16. info = GetHardWareInfo("Win32_Processor", "ProcessorId");
  17. return info;
  18. }
  19. private static string GetBIOSInfo()
  20. {
  21. string info = string.Empty;
  22. info = GetHardWareInfo("Win32_BIOS", "SerialNumber");
  23. return info;
  24. }
  25. private static string GetBaseBoardInfo()
  26. {
  27. string info = string.Empty;
  28. info = GetHardWareInfo("Win32_BaseBoard", "SerialNumber");
  29. return info;
  30. }
  31. private static string GetMACInfo()
  32. {
  33. string info = string.Empty;
  34. info = GetHardWareInfo("Win32_BaseBoard", "SerialNumber");
  35. return info;
  36. }
  37. private static string GetHardWareInfo(string typePath, string key)
  38. {
  39. try
  40. {
  41. ManagementClass managementClass = new ManagementClass(typePath);
  42. ManagementObjectCollection mn = managementClass.GetInstances();
  43. PropertyDataCollection properties = managementClass.Properties;
  44. foreach (PropertyData property in properties)
  45. {
  46. if (property.Name == key)
  47. {
  48. foreach (ManagementObject m in mn)
  49. {
  50. return m.Properties[property.Name].Value.ToString();
  51. }
  52. }
  53. }
  54. }
  55. catch (Exception ex)
  56. {
  57. //这里写异常的处理
  58. }
  59. return string.Empty;
  60. }
  61. private static string GetMacAddressByNetworkInformation()
  62. {
  63. string key = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
  64. string macAddress = string.Empty;
  65. try
  66. {
  67. NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
  68. foreach (NetworkInterface adapter in nics)
  69. {
  70. if (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet
  71. && adapter.GetPhysicalAddress().ToString().Length != 0)
  72. {
  73. string fRegistryKey = key + adapter.Id + "\\Connection";
  74. RegistryKey rk = Registry.LocalMachine.OpenSubKey(fRegistryKey, false);
  75. if (rk != null)
  76. {
  77. string fPnpInstanceID = rk.GetValue("PnpInstanceID", "").ToString();
  78. int fMediaSubType = Convert.ToInt32(rk.GetValue("MediaSubType", 0));
  79. if (fPnpInstanceID.Length > 3 &&
  80. fPnpInstanceID.Substring(0, 3) == "PCI")
  81. {
  82. macAddress = adapter.GetPhysicalAddress().ToString();
  83. for (int i = 1; i < 6; i++)
  84. {
  85. macAddress = macAddress.Insert(3 * i - 1, ":");
  86. }
  87. break;
  88. }
  89. }
  90. }
  91. }
  92. }
  93. catch (Exception ex)
  94. {
  95. //这里写异常的处理
  96. }
  97. return macAddress;
  98. }
  99. }

2.加密解密代码;

  1. public enum EncryptionKeyEnum
  2. {
  3. KeyA,
  4. KeyB
  5. }
  6. public class EncryptionHelper
  7. {
  8. string encryptionKeyA = "pfe_Nova";
  9. string encryptionKeyB = "WorkHard";
  10. string md5Begin = "Hello";
  11. string md5End = "World";
  12. string encryptionKey = string.Empty;
  13. public EncryptionHelper()
  14. {
  15. this.InitKey();
  16. }
  17. public EncryptionHelper(EncryptionKeyEnum key)
  18. {
  19. this.InitKey(key);
  20. }
  21. private void InitKey(EncryptionKeyEnum key = EncryptionKeyEnum.KeyA)
  22. {
  23. switch (key)
  24. {
  25. case EncryptionKeyEnum.KeyA:
  26. encryptionKey = encryptionKeyA;
  27. break;
  28. case EncryptionKeyEnum.KeyB:
  29. encryptionKey = encryptionKeyB;
  30. break;
  31. }
  32. }
  33. public string EncryptString(string str)
  34. {
  35. return Encrypt(str, encryptionKey);
  36. }
  37. public string DecryptString(string str)
  38. {
  39. return Decrypt(str, encryptionKey);
  40. }
  41. public string GetMD5String(string str)
  42. {
  43. str = string.Concat(md5Begin, str, md5End);
  44. MD5 md5 = new MD5CryptoServiceProvider();
  45. byte[] fromData = Encoding.Unicode.GetBytes(str);
  46. byte[] targetData = md5.ComputeHash(fromData);
  47. string md5String = string.Empty;
  48. foreach (var b in targetData)
  49. md5String += b.ToString("x2");
  50. return md5String;
  51. }
  52. private string Encrypt(string str, string sKey)
  53. {
  54. DESCryptoServiceProvider des = new DESCryptoServiceProvider();
  55. byte[] inputByteArray = Encoding.Default.GetBytes(str);
  56. des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
  57. des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
  58. MemoryStream ms = new MemoryStream();
  59. CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
  60. cs.Write(inputByteArray, 0, inputByteArray.Length);
  61. cs.FlushFinalBlock();
  62. StringBuilder ret = new StringBuilder();
  63. foreach (byte b in ms.ToArray())
  64. {
  65. ret.AppendFormat("{0:X2}", b);
  66. }
  67. ret.ToString();
  68. return ret.ToString();
  69. }
  70. private string Decrypt(string pToDecrypt, string sKey)
  71. {
  72. DESCryptoServiceProvider des = new DESCryptoServiceProvider();
  73. byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
  74. for (int x = 0; x < pToDecrypt.Length / 2; x++)
  75. {
  76. int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
  77. inputByteArray[x] = (byte)i;
  78. }
  79. des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
  80. des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
  81. MemoryStream ms = new MemoryStream();
  82. CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
  83. cs.Write(inputByteArray, 0, inputByteArray.Length);
  84. cs.FlushFinalBlock();
  85. StringBuilder ret = new StringBuilder();
  86. return System.Text.Encoding.Default.GetString(ms.ToArray());
  87. }
  88. }

注:这边在MD5时前后各加了一段字符,这样增加一点破解难度。

3.读写文件

  1. public class RegistFileHelper
  2. {
  3. public static string ComputerInfofile = "ComputerInfo.key";
  4. public static string RegistInfofile = "RegistInfo.key";
  5. public static void WriteRegistFile(string info)
  6. {
  7. WriteFile(info, RegistInfofile);
  8. }
  9. public static void WriteComputerInfoFile(string info)
  10. {
  11. WriteFile(info, ComputerInfofile);
  12. }
  13. public static string ReadRegistFile()
  14. {
  15. return ReadFile(RegistInfofile);
  16. }
  17. public static string ReadComputerInfoFile()
  18. {
  19. return ReadFile(ComputerInfofile);
  20. }
  21. public static bool ExistComputerInfofile()
  22. {
  23. return File.Exists(ComputerInfofile);
  24. }
  25. public static bool ExistRegistInfofile()
  26. {
  27. return File.Exists(RegistInfofile);
  28. }
  29. private static void WriteFile(string info, string fileName)
  30. {
  31. try
  32. {
  33. using (StreamWriter sw = new StreamWriter(fileName, false))
  34. {
  35. sw.Write(info);
  36. sw.Close();
  37. }
  38. }
  39. catch (Exception ex)
  40. {
  41. }
  42. }
  43. private static string ReadFile(string fileName)
  44. {
  45. string info = string.Empty;
  46. try
  47. {
  48. using (StreamReader sr = new StreamReader(fileName))
  49. {
  50. info = sr.ReadToEnd();
  51. sr.Close();
  52. }
  53. }
  54. catch (Exception ex)
  55. {
  56. }
  57. return info;
  58. }
  59. }

4.其他界面代码:

主界面代码:

  1. public partial class FormMain : Form
  2. {
  3. private string encryptComputer = string.Empty;
  4. private bool isRegist = false;
  5. private const int timeCount = 30;
  6. public FormMain()
  7. {
  8. InitializeComponent();
  9. Control.CheckForIllegalCrossThreadCalls = false;
  10. }
  11. private void FormMain_Load(object sender, EventArgs e)
  12. {
  13. string computer = ComputerInfo.GetComputerInfo();
  14. encryptComputer = new EncryptionHelper().EncryptString(computer);
  15. if (CheckRegist() == true)
  16. {
  17. lbRegistInfo.Text = "已注册";
  18. }
  19. else
  20. {
  21. lbRegistInfo.Text = "待注册,运行十分钟后自动关闭";
  22. RegistFileHelper.WriteComputerInfoFile(encryptComputer);
  23. TryRunForm();
  24. }
  25. }
  26. /// <summary>
  27. /// 试运行窗口
  28. /// </summary>
  29. private void TryRunForm()
  30. {
  31. Thread threadClose = new Thread(CloseForm);
  32. threadClose.IsBackground = true;
  33. threadClose.Start();
  34. }
  35. private bool CheckRegist()
  36. {
  37. EncryptionHelper helper = new EncryptionHelper();
  38. string md5key = helper.GetMD5String(encryptComputer);
  39. return CheckRegistData(md5key);
  40. }
  41. private bool CheckRegistData(string key)
  42. {
  43. if (RegistFileHelper.ExistRegistInfofile() == false)
  44. {
  45. isRegist = false;
  46. return false;
  47. }
  48. else
  49. {
  50. string info = RegistFileHelper.ReadRegistFile();
  51. var helper = new EncryptionHelper(EncryptionKeyEnum.KeyB);
  52. string registData = helper.DecryptString(info);
  53. if (key == registData)
  54. {
  55. isRegist = true;
  56. return true;
  57. }
  58. else
  59. {
  60. isRegist = false;
  61. return false;
  62. }
  63. }
  64. }
  65. private void CloseForm()
  66. {
  67. int count = 0;
  68. while (count < timeCount && isRegist == false)
  69. {
  70. if (isRegist == true)
  71. {
  72. return;
  73. }
  74. Thread.Sleep(1 * 1000);
  75. count++;
  76. }
  77. if (isRegist == true)
  78. {
  79. return;
  80. }
  81. else
  82. {
  83. this.Close();
  84. }
  85. }
  86. private void btnRegist_Click(object sender, EventArgs e)
  87. {
  88. if (lbRegistInfo.Text == "已注册")
  89. {
  90. MessageBox.Show("已经注册~");
  91. return;
  92. }
  93. string fileName = string.Empty;
  94. OpenFileDialog openFileDialog = new OpenFileDialog();
  95. if (openFileDialog.ShowDialog() == DialogResult.OK)
  96. {
  97. fileName = openFileDialog.FileName;
  98. }
  99. else
  100. {
  101. return;
  102. }
  103. string localFileName = string.Concat(
  104. Environment.CurrentDirectory,
  105. Path.DirectorySeparatorChar,
  106. RegistFileHelper.RegistInfofile);
  107. if (fileName != localFileName)
  108. File.Copy(fileName, localFileName, true);
  109. if (CheckRegist() == true)
  110. {
  111. lbRegistInfo.Text = "已注册";
  112. MessageBox.Show("注册成功~");
  113. }
  114. }
  115. }

注册机代码:

  1. public partial class FormMain : Form
  2. {
  3. public FormMain()
  4. {
  5. InitializeComponent();
  6. }
  7. private void btnRegist_Click(object sender, EventArgs e)
  8. {
  9. string fileName = string.Empty;
  10. OpenFileDialog openFileDialog = new OpenFileDialog();
  11. if (openFileDialog.ShowDialog() == DialogResult.OK)
  12. {
  13. fileName = openFileDialog.FileName;
  14. }
  15. else
  16. {
  17. return;
  18. }
  19. string localFileName = string.Concat(
  20. Environment.CurrentDirectory,
  21. Path.DirectorySeparatorChar,
  22. RegistFileHelper.ComputerInfofile);
  23. if (fileName != localFileName)
  24. File.Copy(fileName, localFileName, true);
  25. string computer = RegistFileHelper.ReadComputerInfoFile();
  26. EncryptionHelper help = new EncryptionHelper(EncryptionKeyEnum.KeyB);
  27. string md5String = help.GetMD5String(computer);
  28. string registInfo = help.EncryptString(md5String);
  29. RegistFileHelper.WriteRegistFile(registInfo);
  30. MessageBox.Show("注册码已生成");
  31. }
  32. }

最后采用ConfuserEx将可执行文件加密(ConfuserEx介绍),这样就不能反编译获得源码。

至此全部完成,只是个人的一些实践,对自己是一个记录,同时希望也能对别人有些帮助,如果有什么错误,还望不吝指出,共同进步,转载请保留原文地址

示例源码下载

C#软件license管理(简单软件注册机制)的更多相关文章

  1. C#实现软件授权,限定MAC运行(软件license管理,简单软件注册机制)

    一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制.事出突然,只能在现场开发(离开现场软件就不受我们控了).花了不到两个小时实现了简单的注册机制,稍作整理. 基本原理:1.软件一运 ...

  2. C# 简单软件有效期注册的实现

    ◆需求:公司一直以来对开发的产品都没有进行使用时间的控制,要么就是将日期限制写死在程序里面,每次都要编译新程序再发给客户,很不方便.于是公司让我写个模块,要求如下:1.无论哪个新开发的程序只要调用这个 ...

  3. 软件License设计

    如何保护软件版权,最常用的办法就是设计一套license验证框架. 1.我们的常规需求如下: .可以限制软件只能在一台机器上使用: 目前很多软件都是一机一码的销售,软件换一台机器则不能使用,想要几台机 ...

  4. Linux软件安装管理

    1.软件包管理简介 1.软件包分类 源码包 脚本安装包 二进制包(RPM包.系统默认包) 2.源码包 源码包的优点是: 开源,如果有足够的能力,可以修改源代码 可以自由选择所需要的功能 软件设计编译安 ...

  5. 软件License认证方案的设计思路

    销售license是商业软件的贯用商业模式.用户向商家购买软件安装盘搭载license许可,才可以使用该软件.我们作为软件开发者,为了保护自身的权益,在软件开发过程中也不可避免的会设计license管 ...

  6. Linux 学习 (十一) 软件安装管理

    Linux软件安装管理 学习笔记 软件包简介 软件包分类: 源码包 :脚本安装包 二进制包(RPM 包.系统默认包) 源码包的优点: 开源,如果有足够的能力,可以修改源代码 可以自由选择所需的功能 软 ...

  7. MySQL介绍及安装&MySQL软件基本管理

    mysql介绍 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下公司.MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是最好 ...

  8. Ubuntu的软件安装管理---dpkg与apt-*详解

    摘要:软件厂商先在他们的系统上面编译好了我们用户所需要的软件,然后将这个编译好并可执行的软件直接发布给用户安装.不同的 Linux 发行版使用不同的打包系统,一般而言,大多数发行版分别属于两大包管理技 ...

  9. [MySQL数据库之数据库相关概念、MySQL下载安装、MySQL软件基本管理、SQL语句]

    [MySQL数据库之数据库相关概念.MySQL下载安装.MySQL软件基本管理.SQL语句] 数据库相关概念 数据库管理软件的由来 数据库管理软件:本质就是个C/S架构的套接字程序. 我们在编写任何程 ...

随机推荐

  1. TObject、TPersisent 、TComponent、TControl、TGraphicControl、TWinControl 关系图

    VCL的类图结构               TObject                 |               TPersisent                 |         ...

  2. 如何使用 JMeter 调用你的 Restful Web Service?进行简单的压力测试和自动化测试

    表述性状态传输(REST)作为对基于 SOAP 和 Web 服务描述语言(WSDL)的 Web 服务的简单替代,在 Web 开发上得到了广泛的接受.能够充分证明这点的是主流 Web 2.0 服务提供商 ...

  3. MySQL学习笔记:从一个表update到另外一个表

    # ---- 测试数据 ---- # 表1 CREATE TABLE temp_x AS AS c_id, 1.11 AS c_amount FROM DUAL UNION ALL AS c_id, ...

  4. Introduction to MWB Minor Mode

    Introduction to MWB Minor Mode */--> Table of Contents 1. Introduction 2. Usage 1 Introduction MW ...

  5. EFK收集Kubernetes应用日志

    本节内容: EFK介绍 安装配置EFK 配置efk-rbac.yaml文件 配置 es-controller.yaml 配置 es-service.yaml 配置 fluentd-es-ds.yaml ...

  6. 手动安装pydev

    在网上下载pydev.zip,解压后有两个文件夹,features和plugins.把这两个文件夹复制到eclipse目录下的dropins文件夹下.

  7. 【转】TCP建立连接三次握手和释放连接四次握手

    在谈及TCP建立连接和释放连接过程,先来简单认识一下TCP报文段首部格式的的几个名词(这里只是简单说明,具体请查看相关教程) 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数 ...

  8. 黑马程序员_java基础笔记(09)...HTML基本知识、CSS、JavaScript、DOM

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流! —————————— 基本标签(a.p.img.li.table.div.span).表单标签.ifra ...

  9. 7-1 FireTruck 消防车 uva208

    题意: 输入一个n <=20 个结点的无向图以及某个结点k   按照字典序从小到大顺序输出从结点1到结点k的所有路径  要求结点不能重复经过 标准回溯法 要实现从小到大字典序 现在数组中排序好即 ...

  10. 为mongodb数据库增加用户名密码权限

    加固mongodb建议:修改数据库默认端口,添加数据库访问权限: 启动数据库(裸奔):C:\mongodb\bin>mongod --dbpath C:\MongoDB\data(同时用--db ...