首页 > 其他分享 >软件License设计

软件License设计

时间:2023-05-17 10:11:30浏览次数:42  
标签:License license LicenseModel 试用版 设计 软件 public

如何保护软件版权,最常用的办法就是设计一套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、会使用到的一些工具类

生成客户机器码的工具类:

 View Code

说明:上面的HardwareInfo类就是帮助生成机器唯一信息的。实际运用中,mac地址、声卡网卡等容易变动,可以不加到信息里面。

对象序列化帮助工具:

 View Code

以及加解密工具:EncodeHelper    源码见我的另一篇文章:

常见加密算法简析

 注册表操作类:  View Code

注册表操作需要用到管理员权限,否则会提示无权限操作注册表。解决办法是在项目中添加“app.manifest"文件

并修改manifest中的如下部分。

 

 其实存到注册表依然不是好办法,最好还是将用户 license保存到服务端,用从服务端请求的方式。或者两者结合,有网络的时候进行网络验证。

最后的License管理器:

复制代码
using System;

namespace LicenseDemo
{
    /// <summary>
    /// License管理器
    /// 作者博客:https://www.cnblogs.com/tuyile006/
    /// </summary>
    public class LicenseManage
    {
        /// <summary>
        /// 当前程序的license  业务层需配合控制权限
        /// </summary>
        public static LicenseModel ApplicationLicense = null;
        
        /// <summary>
        /// 提取客户机器信息,返回编码
        /// </summary>
        /// <returns></returns>
        public static string GetMachineCode()
        {
            return HardwareInfo.GetMachineCode();
        }

        private const string regeditkey = "lic";//注册表键名
        private const string aeskey = "小y加;&tu@"; //密钥
        /// <summary>
        /// 服务端生成License文本  可授权给客户
        /// </summary>
        /// <param name="lic">LicenseModel对象,由客户提供机器码,并由商业提供期限和权限角色</param>
        /// <returns></returns>
        public static string CreateLicenseString(LicenseModel lic)
        {
            byte[] licByte = SerializeHelper.SerializeToBinary(lic);
            return EncodeHelper.AES(Convert.ToBase64String(licByte), aeskey);
        }

        /// <summary>
        /// 客户端获取本地的license  根据自己设计的存储介质,可以是从文件中取、也可以是注册表或远程服务器上取。
        /// </summary>
        /// <returns></returns>
        public static LicenseModel GetLicense()
        {
            if (LicenseManage.ApplicationLicense != null) return LicenseManage.ApplicationLicense;
            
            try
            {
                //如果以前装过,则从注册表取值 这里可以改成从数据库、文件、或服务端
                //未取到键则建一个
                if (!RegistryHelper.IsRegeditExit(regeditkey))
                {
                    //第一次使用默认是试用版
                    LicenseModel license = new LicenseModel()
                    {
                        CustomMachineCode = GetMachineCode(),
                        CustomRole = RoleType.Trial,
                        LastUseTime=DateTime.Now,
                        ExpireTime = DateTime.Now.AddDays(30)
                    };
                    RegistryHelper.WriteRegedit(regeditkey, CreateLicenseString(license));
                    LicenseManage.ApplicationLicense = license;
                }
                else
                {
                    string licFromReg = RegistryHelper.GetRegistData(regeditkey);
                    try
                    {
                        string strlic = EncodeHelper.AESDecrypt(licFromReg, aeskey);
                        byte[] licbyte = Convert.FromBase64String(strlic);
                        LicenseModel lm = SerializeHelper.DeserializeWithBinary<LicenseModel>(licbyte);
                        //取到的值还原license并返回
                        LicenseManage.ApplicationLicense = lm;
                    }
                    catch(Exception ex1)
                    {
                        //_log.Error(ex1);
                        //如果从注册表中取到的值发现被篡改,则直接试用版到期,不给使用。
                        LicenseModel licenseErr = new LicenseModel()
                        {
                            CustomMachineCode = GetMachineCode(),
                            CustomRole = RoleType.Trial,
                            LastUseTime = DateTime.Now,
                            ExpireTime = DateTime.Now
                        };
                    }
                }
            }
            catch(Exception ex)
            {
                //_log.Error(ex);
            }
            return LicenseManage.ApplicationLicense;
        }

        /// <summary>
        /// 客户端验证License,存储
        /// </summary>
        /// <param name="lic">服务端授权给客户的License密文</param>
        /// <returns></returns>
        public static bool VerifyLicense(string lic)
        {
            if(string.IsNullOrEmpty(lic)) return false;
            try
            {
                string strlic = EncodeHelper.AESDecrypt(lic, aeskey);
                byte[] licbyte = Convert.FromBase64String(strlic);
                LicenseModel lm = SerializeHelper.DeserializeWithBinary<LicenseModel>(licbyte);
                //简单验证机器码、role、期限。具体角色权限限制需要在业务系统中实现。
                if (VerifyLicense(lm))
                {
                    LicenseManage.ApplicationLicense = lm;
                    return true;
                }
                
            }
            catch
            {
                //_log.Error(ex);
            }
            //否则直接返回原始试用版
            return false;
        }

        /// <summary>
        /// 简单验证licensemode对象是否合法,不存储
        /// </summary>
        /// <param name="licmod"></param>
        /// <returns></returns>
        public static bool VerifyLicense(LicenseModel licmod)
        {
            //简单验证机器码、role、期限。具体角色权限限制需要在业务系统中实现。
            bool isHaveRight = false;
            if (licmod.CustomMachineCode == GetMachineCode())
            {
                if (licmod.CustomRole == RoleType.Free)
                {
                    isHaveRight = true;
                }
                else if (licmod.LastUseTime < DateTime.Now && licmod.ExpireTime > DateTime.Now)
                {
                    isHaveRight = true;
                }
            }

            if (isHaveRight)
            {
                licmod.LastUseTime = DateTime.Now;
                RegistryHelper.WriteRegedit(regeditkey, CreateLicenseString(licmod));
            }

            return isHaveRight;
        }

        public static void DeleteLicense()
        {
            RegistryHelper.DeleteRegist(regeditkey);
            LicenseManage.ApplicationLicense = null;
        }

    }
}
复制代码

 

管理器的使用Demo如下:

           

Demo下载

做好了License架构,是不是软件版权保护就完成了呢?答案是否定的。现在我们已经造了银行保险柜的门,却只有篱笆一样容易攻破的墙,黑客直接反编译你的软件,去掉权限验证的逻辑再重新编译,就可以终身永久免费使用你的劳动成果,所以不加密的软件在黑客眼里就像在裸奔。混淆、加壳是另一个更加复杂的技术,下面介绍几款混淆工具。

4.混淆工具介绍:

Eziriz .NET Reactor:

主要功能包括:NecroBit IL(转为非托管代码)、反 ILDASM(反编译器)、混淆代码、合并、压缩源码、支持命令行等,支持所有 .NET 框架和几乎所有开发语言,如 C#、C++.NET、VB.NET、Delphi.NET、J# 等等。

 使用教程:https://blog.csdn.net/jyxyscf/article/details/78478631

ConfuserEx:

是一款开源.net混淆器。

使用教程:https://www.cnblogs.com/tuyile006/p/8461326.html

Dotfuscator:

这款大家应该比较熟悉了,官方自带的。

使用教程:https://www.cnblogs.com/tuyile006/p/9183925.html

 

-----------------------------------------------------------------

标签:License,license,LicenseModel,试用版,设计,软件,public
From: https://www.cnblogs.com/lidabo/p/17407669.html

相关文章

  • 面向对象程序设计 之 文件输入输出流
    石家庄铁道大学实验报告课程名称面向对象程序设计班级 姓名 学号 实验日期2023.5.16评分100 实验项目名称:输入输出流一、实验目的掌握文本文件和二进制文件的基本访问方法;了解一般I/O流和文件流的关系;了解文件与......
  • 一个程序设计业务中,如果需要这个表数据对应3种业务,但是唯独其中一种要多几个字段去展
    作为一个AI助手,我可以为您提供一些设计思路,但是最终的决定应该基于具体场景和业务需求。一种解决方案是在原表基础上新增字段。这种方法简单快捷,可以避免复杂的表关联,但是会使得表结构变得臃肿,不利于维护和拓展。如果这个表在后续的业务中还需要扩展字段,就会更加困难。另一种解......
  • 原型设计工具adobe xd介绍
    AdobeXD是一款由adobe公司出版的软件,是一个协作式易用平台,可以帮助我们为网站,移动应用程序,语音界面,游戏等创建设计。adobexd的美化功能栏有7大功能板块,分别为竖线布局设计、横线布局设计、重复网格、图形大小和位置、响应式调整大小、文字美化以及外观美化。这七大块内容,能够......
  • 实验三 Web数据库程序设计
     实  验  报  告  课程名称:  WEB应用开发技术  任课教师:   雷 宇         实验日期: 2023.5.16          班   级:     信2105-2班                                    ......
  • 人件集 人性化的软件开发阅读笔记01
    《人件集:人性化的软件开发》第一部分团队开发第一章决策,决策讲述了中庸的风险以及轻度领导研究表明,集体的决策比从集体中的个体独立做选择更具有风险倾向。如果将这种决策模式应用于软件编程,我们可能会看到这样的结果:团队可能使用更奇特的数据结构、更古怪的算法或者更......
  • 【尺取法】【二分】河南省第十三届ICPC大学生程序设计竞赛 C题
    题目链接:https://ac.nowcoder.com/acm/contest/57784/C来源:牛客网题目描述有一个长度为\(n\)的序列\(a_i\)和常数\(K\)。总共选\(m\)次,每次选一个连续区间\([L_i,R_i]\),问这个区间中存在多少个连续子区间满足,区间中不同的数的个数不小于\(K\)。首先用尺取法统......
  • Java设计模式-装饰模式
    简介装饰模式在Java领域是一种常见的设计模式,它能够在不改变对象原有结构的情况下,动态地为对象添加新的功能。它通过封装原有对象,在运行时动态地为对象添加新的行为或者修改原有行为,以扩展对象的功能。这种方式避免了继承的静态特性,让对象的行为可以根据需要进行动态变化。在装......
  • 原型设计工具介绍
    原型是整个产品面市之前的一个框架设计。设计师可以利用它引导每个人都参与到项目中来。原型展示了各个部分之间的比重以及各个部分之间的联系。原型不仅仅只是表面的东西,它能够说明用户将如何与产品进行交互。与其他工作一样,完成原型设计需要相应的工具协助。本文将主要......
  • AutoMagic设计思路简介及新增自定义关键字实例
    目录  简介  AutoMagic介绍  SeleniumKey介绍  自定义关键字简介AutoMagic是一个基于WebUI的自动化管理平台。为什么叫AutoMagic呢?因为自动化在执行起来的时候是一个很神奇的事情,它可以无人值守的模拟人的操作,就像魔术(Magic)一样。所以我给她取名叫AutoMagic。Aut......
  • 软件测试人员必须了解的DevOps
    软件测试人员必须了解的DevOps前言什么是DevOps工作原则方法如何着手DevOps变更流程管理技巧挑战总结参考前言对很多软件测试人员而言,可能尚未接触到DevOps,本文的内容基于笔者日常学习,针对测试人员所记录的一些关键信息,算是给大家深入学习DevOps的一个引子。什么是DevOpsDevOps是开......