如何保护软件版权,最常用的办法就是设计一套license验证框架。
1、我们的常规需求如下:
1.可以限制软件只能在一台机器上使用; 目前很多软件都是一机一码的销售,软件换一台机器则不能使用,想要几台机器使用就得购买几个license; 2.可以设置一个使用期限; 试用版软件一般有几十天的免费使用期,销售时也可以分为一年版、终生版等; 3.可以设置能使用的权限; 试用版软件对处理能力有限制,比如短信发送软件设置发送条数限制,抽奖软件设置总人数限制,打印软件试用版插一个软件广告等等;
进一步分析如下:
试用版:无需License,安装后的默认版本;有使用期限;有功能限制或插入广告等;
有限期限版:需要License;有使用期限;无功能限制;
终身免费版:需要License;无限制;
一般破解的办法有以下几种:
1.试用版到期后修改系统时间;
2.试用版到期后找到license文件并修改或删除;
3.试用版到期后卸载软件,重新安装;
4.黑客直接反编译软件,屏蔽掉验证License的逻辑;
2、License结构设计
针对以上需求,我们来对应设计License的结构如下:
using System; namespace LicenseDemo { /// <summary> /// License信息 /// </summary> [Serializable] public class LicenseModel { //客户机器唯一识别码,由客户端生成 public string CustomMachineCode { get; set; } //最后使用时间 public DateTime LastUseTime { get; set; } //过期时间expire public DateTime ExpireTime { get; set; } //权限类型(如可分为 0: 15天试用版 1:1年版 2:终身版) public RoleType CustomRole { get; set; } } /// <summary> /// 几种角色类型 /// </summary> [Serializable] public enum RoleType { /// <summary> /// 试用版 /// </summary> Trial=0, /// <summary> /// 有期限版 /// </summary> Expiration=1, /// <summary> /// 终身免费版 /// </summary> Free=2 } }
结构说明:
为什么这样设计就可以基本达到要求呢?首先一机一码就要包含客户机器的唯一标识,可以通过获取机器硬件CPU、主板、Bios、Mac地址、显卡、声卡等的ID来生成;然后需要有个会员类型来区分是试用版、有限期限版还是永久免费版;过期时间是用来限制使用时间的,就不用多说;最后使用时间这个字段是为了防止用户通过修改系统时间,简单的跨过试用期限;当然我们业务层还可以加一下其他功能限制或广告来继续促成用户使用正版;
用户购买License后,这个license如何保存,试用版本的License如何保证即使用户卸载了软件重装,也依然不能改变试用时间。这就要保存好License,可以放到隐藏系统文件里面、注册表里面、远程服务器端,安全系数会依次提高;
具体采用什么方式也跟你的软件被什么客户群使用有关系,比如你的软件主要用于上市公司,那么你都不用担心盗版问题,上市公司自己会找你买正版,他得规避法律风险;你的license就可以放在明处,比如著名的图像算法处理软件Haclon,就是每个月发布一次试用版的License,你自己去放到自己的软件文件夹下面;如果你删掉他的license,那么软件直接打不开。
如果你的客户是C端个人用户,那么就得考虑法律罪责比较难的问题了,只能从加强自己的软件验证水平,防破解了;
然后设计一下License分发和验证的流程:
试用版的客户端,是不需要license的,软件第一次启动时先找一下本地是否有License,如果没有则默认生成一个试用版License,下次直接读取到的就是试用版License。后续用户购买正版License后可以在软件中重新激活正版License。
3、会使用到的一些工具类
生成客户机器码的工具类:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Management; using System.Security.Cryptography; namespace LicenseDemo { /// <summary> /// 硬件码生成器 /// 作者博客:https://www.cnblogs.com/tuyile006/ /// </summary> public class HardwareInfo { private static string myMachineCode = ""; /// <summary> /// 生成一个16字节的机器唯一码 /// 如: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9 /// </summary> /// <returns></returns> public static string GetMachineCode() { if (string.IsNullOrEmpty(myMachineCode)) { string omsg = " CPU >> " + CpuId() + " BIOS >> " + BiosId() + " BASE >> " + BaseId(); // + " DISK >> " + DiskId() + " VIDEO >> " + //VideoId() + " MAC >> " + MacId(); myMachineCode = MD5(omsg); } return myMachineCode; } /// <summary> /// MD5哈希加密 /// </summary> /// <param name="scr">原始string数据</param> /// <returns>加密后的数据</returns> private static string MD5(string scr) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] palindata = Encoding.Default.GetBytes(scr);//将要加密的字符串转换为字节数组 byte[] encryptdata = md5.ComputeHash(palindata);//将字符串加密后也转换为字符数组 return GetHexString(encryptdata);//将加密后的字节数组转换为加密字符串 } /// <summary> /// byte[]转换成十六进制 /// </summary> /// <param name="bt"></param> /// <returns></returns> private static string GetHexString(byte[] bt) { string s = string.Empty; for (int i = 0; i < bt.Length; i++) { byte b = bt[i];