C#软件授权、注册、加密、解密模块源码解析并制作注册机生成license
最近做了一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制。事出突然,只能在现场开发(离开现场软件就不受我们控了)。花了不到两个小时实现了简单的注册机制,稍作整理。
基本原理:1.软件一运行就把计算机的CPU、主板、BIOS、MAC地址记录下来,然后加密(key=key1)生成文件;2.注册机将该文件内容MD5加密后再进行一次加密(key=key2)保存成注册文件;3.注册验证的逻辑,计算机信息加密后(key=key1)加密md5==注册文件解密(key=key2);
另外,采用ConfuserEx将可执行文件加密;这样别人要破解也就需要点力气了(没打算防破解,本意只想防复制的),有能力破解的人也不在乎破解这个软件了(开发这个软件前后只花了一周时间而已);
技术上主要三个模块:1.获取电脑相关硬件信息(可参考);2.加密解密;3.读写文件;
1.获取电脑相关硬件信息代码:
[csharp] view plain copy
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.加密解密代码;
[csharp] view plain copy
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.读写文件
[csharp] view plain copy
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.其他界面代码:
主界面代码:
[csharp] view plain copy
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("注册成功~");
}
}
}
注册机代码:
[csharp] view plain copy
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介绍),这样就不能反编译获得源码。
至此全部完成,只是个人的一些实践,对自己是一个记录,同时希望也能对别人有些帮助,如果有什么错误,还望不吝指出,共同进步,转载请保留原文地址。
---------------------
作者:weixin_37691493
来源:CSDN
原文:https://blog.csdn.net/weixin_37691493/article/details/79716050
版权声明:本文为博主原创文章,转载请附上博文链接!
C#软件授权、注册、加密、解密模块源码解析并制作注册机生成license的更多相关文章
- gorm的日志模块源码解析
gorm的日志模块源码解析 如何让gorm的日志按照我的格式进行输出 这个问题是<如何为gorm日志加traceId>之后,一个群里的朋友问我的.如何让gorm的sql日志不打印到控制台, ...
- 「从零单排canal 06」 instance模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- 基于新唐M0的XXTEA加密解密算法源码
/*-------------------------------------------------------------------------------------------------- ...
- 「从零单排canal 05」 server模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- 「从零单排canal 07」 parser模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- php 日志模块源码解析
php日志模块设计 Monolog 是PHP的一个日志类库解析 整体介绍:monolog日志模块遵循 PSR3 的接口规范.主要有日志格式类接口(格式化日志信息),处理类接口(写日志的驱动,通过扩展写 ...
- Spring5源码解析2-register方法注册配置类
接上回已经讲完了this()方法,现在来看register(annotatedClasses);方法. // new AnnotationConfigApplicationContext(AppCon ...
- Mybatis源码解析-MapperRegistry代理注册mapper接口
知识储备 SqlsessionFactory-mybatis持久层操作数据的前提,具体的解析是通过SqlSessionFactoryBean生成的,可见>>>Spring mybat ...
- Dubbo源码解析之registry注册中心
阅读须知 dubbo版本:2.6.0 spring版本:4.3.8 文章中使用/* */注释的方法会做深入分析 正文注册中心是Dubbo的重要组成部分,主要用于服务的注册与发现,我们可以选择Redis ...
随机推荐
- Angular的第一个helloworld
在安装了node,npm,angular-cli,vscode之后,我们来创建一个angular的应用 创建第一个hello world 使用的IDE工具为vscode 打开vscode,打开一个命令 ...
- 2 springboot多模块项目
一般来说创建一个springboot工程基本就可以了,但是有的时候可能需要将业务模块逻辑划分,每块业务模块都是一个工程,下边演示下多模块进行开发 目录结构 ...somefun ......somef ...
- Intellij IDEA run coverage之覆盖率测试
Intellij IDEA run coverage之覆盖率测试 idea 的coverage + 我们自己写的测试用例.最后看一下,我们要测的代码有没有测试到,这是一个不错的提高代码质量的方法. i ...
- Q:判断链表中是否存在环的相关问题
问题:如何判断一个单向链表中是否存在环? 例如: 链表中存在环(B-->D): <-- <--^ | | v | A-->B-->C-->D 链表中不存在环: A- ...
- python数据类型之简单数据类型
变量使用注意事项 慎用小写字母l和大写字母O,因为它们可能被人看成数值1和0. 应使用小写的python变量名. 字符串 在python中,用引号括起来的都是字符串,其中的引号可以是单引号和双引号. ...
- WinForm中使用CrystalReport水晶报表——基础,分组统计,自定义数据源
开篇 本篇文章主要是帮助刚开始接触CrystalReport报表的新手提供一个循序渐进的教程.该教程主要分为三个部分1)CrystalReport的基本使用方法:2)使用CrystalReport对数 ...
- cf444E. DZY Loves Planting(并查集)
题意 题目链接 Sol 神仙题啊Orzzzzzz 考场上的时候直接把树扔了对着式子想,想1h都没得到啥有用的结论. 然后cf正解居然是网络流??出给NOIP模拟赛T1???¥%--&((--% ...
- Scala + Thrift+ Zookeeper+Flume+Kafka配置笔记
1. 开发环境 1.1. 软件包下载 1.1.1. JDK下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downl ...
- Scala安装时的坑
重新安装了Scala(2.11.12版本)到d:\Program Files下,查看版本时,报如下异常: 百度了一下,竟然是不允许空格,太low了. 装到d:\Scala后问题解决
- Flutter 案例学习之:GridView
GitHub:https://github.com/happy-python/flutter_demos/tree/master/gridview_demo 在 ListView 中,如果将屏幕的方向 ...