- APP神圣官网 > 官方版本 > 正文
迄今最全面授权保护商业软件(领取回复加密代码混淆)「软件授权协议 商业授权」
【作者】科技、互联网行业优质创作者【专注领域】.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造点击右上方“关注”,里面有很多高价值技术文章,是你刻苦努力也积累不到的经验,能助你快速成长。升职+涨薪。
。
前言首先,对于.NET/C#生成的托管的代码,没有100%的保护措施,因为它们的程序执行最终会到二进制/汇编这个层面。而二进制/汇编层面可以针对性的对于指令集(Risc-v/Arm64/x64/Loongarch64)进行反汇编逆向重构。所以,对于.NET/C#生成的托管的代码,能做的只能是有限度的保护、增加理解难度。软件保护20年前,.Net刚诞生的时候有个笑话。有人嘲讽微软做托管代码,是为了方便别人破解。事实证明,托管确实比非托管更容易破解和篡改。MSIL遵循了一整套的ECMA-335的规范,对于这个规范了如指掌的程序开发人员来说,托管代码就像纸糊的一样,戳哪儿哪儿就破。但绝大多数99%的软件工程师是在做业务开发、为商业服务,他们往往只需要懂.NET/C#这种高级语言就够了,很少有人会去研究&也没必要关心MSIL以及汇编这类低级语言(往往只有黑客、做编译器、驱动开发的那1%的程序员需要懂低级语言)。所以,只需要对.NET/C#托管代码进行混淆加密,就能防范住99%的破解。.Net加密工具目前市面上流行的.Net加壳软件大致有如下:Dotfuscator:Visual Stuido自带的,你可以自己去安装使用。混淆后的程序改变了方法名和一些变量名,降低了代码可读性。dotNET Reactor:主要功能:NecroBit IL(转为非托管代码)、反 ILDASM(反编译器)、混淆代码、合并、压缩源码等。效果比VS自带的Dotfuscator要好。ILProtector:可保护您的 .NET 代码免受逆向工程、反编译和修改。Xenocode Fox:反编译工具,混淆工具,只能针对早期.NET Framework代码使用。SmartAssembly:一款.NET代码加密保护软件,里面内置的选项方面是蛮多的,能够往程序里面注入一些没用的方法和类来混淆代码结构。使用该软件加密混淆后效果比.NET Reactor好一些。DNGuard HVM:加密功能很强大,混淆后的程序很难被破解,效果更好。商业授权我们做的商业软件需要进行售卖,为了收取费用,一般需要一个软件使用许可证,然后输入这个许可到软件里就能够使用软件(比如,一串序列码或者一个许可证文件)。于是有的小伙伴就开始好奇这个许可是怎么实现的。实现许可证的关键点1. 如何控制只在指定设备上使用如果不控制指定设备,那么下发了许可证,只要把软件复制多份安装则可到处使用,不利于版权维护。但我们想想,有什么办法唯一标识一台电脑?答案就是:mac地址,ip地址,主板序列号等。在许可证中指定这些唯一标识即可实现指定设备使用。实现许可证的关键点2. 如何控制软件使用期限为了版权可持续性收益,对软件使用设置期限,到期续费等,则需要在许可证中配置使用起止日期。其实,在前述的.Net加密工具中,往往就附带有制作许可证实现商业授权的功能。但我想各位小伙伴可能更想知道具体的实现原理、以及后期自己开发此类功能?下面就把关键的【核心源码】展现给大家参考:【核心源码】1.1 电脑信息获取主要通过ManagementClass进行获取客户端电脑硬件相关配置信息,如下所示:using Microsoft.Win32;using System;using System.Collections.Generic;using System.Linq;using System.Management;using System.Net.NetworkInformation;using System.Text;using System.Threading.Tasks; namespace DemoLicence.Common{ public class ComputerHelper { public static Dictionary<string,string> GetComputerInfo() { var info = new Dictionary<string,string>(); string cpu = GetCPUInfo(); string baseBoard = GetBaseBoardInfo(); string bios = GetBIOSInfo(); string mac = GetMACInfo(); info.Add("cpu", cpu); info.Add("baseBoard", baseBoard); info.Add("bios", bios); info.Add("mac", 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 = GetMacAddress();//GetHardWareInfo("Win32_NetworkAdapterConfiguration", "MACAddress"); return info; } private static string GetMacAddress() { var mac = ""; var mc = new ManagementClass("Win32_NetworkAdapterConfiguration"); var moc = mc.GetInstances(); foreach (var o in moc) { var mo = (ManagementObject)o; if (!(bool)mo["IPEnabled"]) continue; mac = mo["MacAddress"].ToString(); break; } return mac; } 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; } }}
1.2 RSA非对称加密主要对客户端提供的电脑信息及有效期等内容,进行非对称加密,如下所示:public class RSAHelper{ private static string keyContainerName = "star"; private static string m_PriKey = string.Empty; private static string m_PubKey = string.Empty; public static string PriKey { get { return m_PriKey; } set { m_PriKey = value; } } public static string PubKey { get { return m_PubKey; } set { m_PubKey = value; } } public static string Encrypto(string source) { if (string.IsNullOrEmpty(m_PubKey) && string.IsNullOrEmpty(m_PriKey)) { generateKey(); } return getEncryptoInfoByRSA(source); } public static string Decrypto(string dest) { if (string.IsNullOrEmpty(m_PubKey) && string.IsNullOrEmpty(m_PriKey)) { generateKey(); } return getDecryptoInfoByRSA(dest); } public static void generateKey() { CspParameters m_CspParameters; m_CspParameters = new CspParameters(); m_CspParameters.KeyContainerName = keyContainerName; RSACryptoServiceProvider asym = new RSACryptoServiceProvider(m_CspParameters); m_PriKey = asym.ToXmlString(true); m_PubKey = asym.ToXmlString(false); asym.PersistKeyInCsp = false; asym.Clear(); } private static string getEncryptoInfoByRSA(string source) { byte[] plainByte = Encoding.ASCII.GetBytes(source); //初始化参数 RSACryptoServiceProvider asym = new RSACryptoServiceProvider(); asym.FromXmlString(m_PubKey); int keySize = asym.KeySize / 8;//非对称加密,每次的长度不能太长,否则会报异常 int bufferSize = keySize - 11; if (plainByte.Length > bufferSize) { throw new Exception("非对称加密最多支持【" + bufferSize + "】字节,实际长度【" + plainByte.Length + "】字节。"); } byte[] cryptoByte = asym.Encrypt(plainByte, false); return Convert.ToBase64String(cryptoByte); } private static string getDecryptoInfoByRSA(string dest) { byte[] btDest = Convert.FromBase64String(dest); //初始化参数 RSACryptoServiceProvider asym = new RSACryptoServiceProvider(); asym.FromXmlString(m_PriKey); int keySize = asym.KeySize / 8;//非对称加密,每次的长度不能太长,否则会报异常 //int bufferSize = keySize - 11; if (btDest.Length > keySize) { throw new Exception("非对称解密最多支持【" + keySize + "】字节,实际长度【" + btDest.Length + "】字节。"); } byte[] cryptoByte = asym.Decrypt(btDest, false); return Encoding.ASCII.GetString(cryptoByte); }}
1.3 生成文件主要是加密后的信息,和解密秘钥等内容,保存到文件中,如下所示:using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace DemoLicence.Common{ public class RegistFileHelper { public static string ComputerInfofile = "ComputerInfo.key"; public static string RegistInfofile = "Licence.key"; public static void WriteRegistFile(string info,string keyFile) { string tmp = string.IsNullOrEmpty(keyFile)?RegistInfofile:keyFile; WriteFile(info, tmp); } public static void WriteComputerInfoFile(string info) { WriteFile(info, ComputerInfofile); } public static string ReadRegistFile(string keyFile) { string tmp = string.IsNullOrEmpty(keyFile) ? RegistInfofile : keyFile; return ReadFile(tmp); } public static string ReadComputerInfoFile(string file) { string tmp = string.IsNullOrEmpty(file) ? ComputerInfofile : file; return ReadFile(tmp); } 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; } }}
以上这三部分,各个功能相互独立,通过LicenceHelper相互调用,如下所示:using System;using System.Collections.Generic;using System.Linq;using System.Runtime.CompilerServices;using System.Text;using System.Threading.Tasks; namespace DemoLicence.Common{ public class LicenceHelper { /// <summary> /// 获取电脑信息,并生成文件 /// </summary> public static string GetComputerInfoAndGenerateFile() { string computerKeyFile = string.Empty; try { var info = GetComputerInfo(); if (info != null && info.Count > 0) { //获取到电脑信息 var strInfo = new StringBuilder(); foreach (var computer in info) { strInfo.AppendLine($"{computer.Key}={computer.Value}"); } RegistFileHelper.WriteComputerInfoFile(strInfo.ToString()); computerKeyFile = RegistFileHelper.ComputerInfofile; } }catch(Exception ex) { throw ex; } return computerKeyFile; } public static Dictionary<string,string> GetComputerInfo() { var info = ComputerHelper.GetComputerInfo(); return info; } public static bool CheckLicenceKeyIsExists() { var keyFile = RegistFileHelper.RegistInfofile; if (File.Exists(keyFile)) { return true; } else { return false; } } public static string GetComputerInfo(string computerInfoFile) { return RegistFileHelper.ReadComputerInfoFile(computerInfoFile); } public static void GenerateLicenceKey(string info,string keyfile) { string encrypto = RSAHelper.Encrypto(info); string priKey = RSAHelper.PriKey;//公钥加密,私钥解密 byte[] priKeyBytes = Encoding.ASCII.GetBytes(priKey); string priKeyBase64=Convert.ToBase64String(priKeyBytes); StringBuilder keyInfo= new StringBuilder(); keyInfo.AppendLine($"prikey={priKeyBase64}"); keyInfo.AppendLine($"encrypto={encrypto}"); RegistFileHelper.WriteRegistFile(keyInfo.ToString(), keyfile); } public static string ReadLicenceKey(string keyfile) { var keyInfo = RegistFileHelper.ReadRegistFile(keyfile); if (keyInfo == null) { return string.Empty; } string[] keyInfoArr = keyInfo.Split("\r\n"); var priKeyBase64 = keyInfoArr[0].Substring(keyInfoArr[0].IndexOf("=")+1); var encrypto = keyInfoArr[1].Substring(keyInfoArr[1].IndexOf("=")+1); var priKeyByte= Convert.FromBase64String(priKeyBase64); var priKey = Encoding.ASCII.GetString(priKeyByte); RSAHelper.PriKey= priKey; var info = RSAHelper.Decrypto(encrypto); return info; } public static string GetDefaultRegisterFileName() { return RegistFileHelper.RegistInfofile; } public static string GetDefaultComputerFileName() { return RegistFileHelper.ComputerInfofile; } public static string GetPublicKey() { if (string.IsNullOrEmpty(RSAHelper.PubKey)) { RSAHelper.generateKey(); } return RSAHelper.PubKey; } public static string GetPrivateKey() { if (string.IsNullOrEmpty(RSAHelper.PriKey)) { RSAHelper.generateKey(); } return RSAHelper.PriKey; } }}
写在最后请点击上方“关注”我,里面有很多高价值技术文章,是你刻苦努力也积累不到的经验,能助你快速成长。升职+涨薪。
。
推荐15个顶级C#/.NET/.NET Core视频教程领取方式:在我的个人主页的第一篇置顶文章中领取回复'面试',获取C#/.NET/.NET Core面试宝典回复'C#',领取零基础学习C#编程回复'NET',领取.NET零基础入门到实战回复'Linux',领取Linux从入门到精通回复'WPF',领取高薪热门【WPF上位机+工业互联网】从零手写实战回复'Modbus',领取初识C#+上位机Modbus通信回复'PLC',领取C#语言与西门子PLC的通信实操回复'blazor',领取blazor从入门到实战回复'TypeScript',领取前端热门TypeScript系统教程回复'vue',领取vue前端从入门到精通回复'23P',领取C#实现23种常见设计模式回复'MongoDB',领取MongoDB实战回复'Trans',领取分布式事务回复'Lock',领取分布式锁实践回复'Docker',领取微服务+Docker综合实战回复'K8s',领取K8s部署微服务回复'加群',进.NET技术社区交流群领取方式:在我的个人主页的第一篇置顶文章中领取
联系我们
在线咨询:
0 评论