当前位置: 首页 > news >正文

Qt设置软件使用期限【新版防修改系统时间】

在工业软件或其他领域中,经常会对软件进行授权,软件需要付费进行有期限的使用。以下是我用Qt设计的设置软件使用期限的两种方案。

主体思想:

1.软件需要绑定机器,让用户无法通过复制在另一台机器上运行。

2.由厂家提供激活码供用户激活,每个激活码只对应指定的机器有效,且激活码需包含使用期限。为保证激活码不能重复使用,激活码需包含当天的日期信息,令激活码仅当天有效,软件过期或许可证丢失后无法使用之前激活码进行激活。

3.由于2的限制,因此需要在每台机器上产生机器码,供厂家用来生成激活码。

4.需有校验功能,校验激活码是否有效,校验是否过期。为了避免用户修改系统时间来延长使用期限,需要验证许可证中最后使用日期是否大于当前日期,若是,则说明用户修改了系统时间,校验不通过,此时可以在代码中删除许可证,或直接退出软件。

5.需要保存许可证或注册表。许可证和注册表信息存储的是当前激活的密钥和最后使用日期、有效期限。并在每次开启和关闭软件时对许可证内的最后使用日期进行更新。

一、获取机器码

要绑定机器,就要获取到机器的唯一标识,网卡的MAC地址是个不错的选择,因此可以拿MAC地址当做机器码。

QString getMachineCode(){QString text;//获取非00-00-00-00-00-00的mac地址QRegExp regmac("00.00.00.00.00.00");foreach(QNetworkInterface interface,QNetworkInterface::allInterfaces()){text = interface.hardwareAddress();if(text.indexOf(regmac)>=0)continue;elsebreak;}QString machineCode;for(int i=0;i<6;i++){machineCode.append(text.mid(0,2));text.remove(0,3);}return machineCode;
}

二、生成带使用期限的激活码

激活码可以自己编写一些算法,通过各种计算、移位、换位等操作来生成。下面是我的示例:

QString newFunction(QString mc, int day)//mc为机器码,day为使用期限
{QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}
//激活码中日期信息QDate date = QDate::currentDate();int y=date.year()-2000;int m=date.month();int d=date.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);qDebug()<<dts;int dt = dts.toInt(nullptr,2);QString dthex = QString::number(dt,16);QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);QStringList binlst;binlst.append(hexToBin(copycode.mid(0,2)));binlst.append(hexToBin(copycode.mid(2,2)));binlst.append(hexToBin(copycode.mid(4,2)));binlst.append(hexToBin(copycode.mid(6,2)));binlst.append(hexToBin(copycode.mid(8,2)));binlst.append(hexToBin(copycode.mid(10,2)));int jy = 0;for(int i=7;i>=0;i--){int nums=0;for(int j=0;j<6;j++){if(binlst.at(j).at(i)=='1')nums++;}if(nums%2==1)jy += 1<<i;}qDebug()<<jy;jy += day;int local = day%6;copycode.insert(local*2,tenToHexL(jy));copycode.append(dthex);qDebug()<<copycode;return copycode;
}

三、校验激活码

校验的过程其实就是生成激活码(不带期限),与带期限的激活码进行比对和运算,判断其是否有效,若有效则计算使用期限。

int Widget::getValidity(QString code)
{QDate date = QDate::currentDate();int y=date.year()-2000;int m=date.month();int d=date.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = dts.toInt(nullptr,2);QString dthex = QString::number(dt,16);if(dthex!=code.mid(16,4)){//激活码内日期与当前日期不符,激活码过期qDebug()<<"code over time!";return 0;}code.remove(16,4);QString mc = getMachineCode();QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);QStringList binlst;binlst.append(hexToBin(copycode.mid(0,2)));binlst.append(hexToBin(copycode.mid(2,2)));binlst.append(hexToBin(copycode.mid(4,2)));binlst.append(hexToBin(copycode.mid(6,2)));binlst.append(hexToBin(copycode.mid(8,2)));binlst.append(hexToBin(copycode.mid(10,2)));int jy = 0;for(int i=7;i>=0;i--){int nums=0;for(int j=0;j<6;j++){if(binlst.at(j).at(i)=='1')nums++;}if(nums%2==1)jy += 1<<i;}int validity=0;for(int i=0;i<12;i+=2){if(copycode.mid(i,2)!=code.mid(i,2)){validity = code.mid(i,4).toInt(nullptr,16)-jy;code.remove(i,4);break;}}if(copycode==code){//激活码有效,生成许可证writeLicense(copycode,dthex,validity);return validity;}elsereturn 0;
}

四、生成许可证

为了后续校验方便,许可证内的激活码可以省略最后几个步骤。许可证内容由三部分组成:激活码、最后使用日期、软件有效期。

void writeLicense(QString code,QString dthex,int days)
{QDate yxq = QDate::currentDate().addDays(days);int y=yxq.year()-2000;int m=yxq.month();int d=yxq.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = dts.toInt(nullptr,2);QString yxqhex = QString::number(dt,16);QFile file("license.dat");file.open(QIODevice::WriteOnly);QDataStream ds(&file);QByteArray ba;ba.resize(10);for(int i=0;i<6;i++){ba[i]=uchar(code.mid(i*2,2).toUInt(nullptr,16));}ba[6]=uchar(dthex.mid(0,2).toUInt(nullptr,16));ba[7]=uchar(dthex.mid(2,2).toUInt(nullptr,16));ba[8]=uchar(yxqhex.mid(0,2).toUInt(nullptr,16));ba[9]=uchar(yxqhex.mid(2,2).toUInt(nullptr,16));ds<<(QByteArray)ba;file.flush();file.close();
}

五、软件每次启动时校验许可证

void Widget::checkLicense()
{QFile file("license.dat");file.open(QIODevice::ReadOnly);QDataStream ds(&file);QByteArray ba;ds>>ba;QString code = ba.toHex();QString shortcode = code.mid(0,12);QString mc = getMachineCode();QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);if(shortcode!=copycode){//激活码错误qDebug()<<"校验不通过";return;}QDate lastDate;QString dts = code.mid(12,4);int idt = dts.toInt(nullptr,16);int y = idt>>9;int m = (idt>>5) & ((1<<4)-1);int d = idt & ((1<<5)-1);lastDate.setDate(y+2000,m,d);if(lastDate.daysTo(QDate::currentDate())<0){//用户修改了系统时间qDebug()<<"时间非法";return;}QDate today = QDate::currentDate();y=today.year()-2000;m=today.month();d=today.day();QString s_today = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = s_today.toInt(nullptr,2);QString s_yxq = code.mid(16,4);if(s_yxq.toInt(nullptr,16)<dt){//许可证已过期qDebug()<<"已过期";return;}
}

六、更新许可证

为防止用户篡改系统时间以达到延长使用期限的目的,许可证中加入了最后使用日期进行校验。在每次软件启动校验成功后、软件关闭时,更新许可证中的最后使用日期。

void updateLicense()
{QFile file("license.dat");file.open(QIODevice::ReadWrite);QDataStream ds(&file);QByteArray ba;ds>>ba;QDate today = QDate::currentDate();int y=today.year()-2000;int m=today.month();int d=today.day();QString s_today = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = s_today.toInt(nullptr,2);QString hex = QString::number(dt,16);ba[6]=uchar(hex.mid(0,2).toUInt(nullptr,16));ba[7]=uchar(hex.mid(2,2).toUInt(nullptr,16));file.resize(0);file.seek(0);ds<<ba;file.flush();file.close();
}

以上内容为本地生成许可证的方式,也可以用写注册表的方式来代替,主体思想不变。

想要完成代码的朋友可以私信作者获取。

请大家多多关注与支持!

http://www.dtcms.com/a/340858.html

相关文章:

  • 一个 WPF 文档和工具窗口布局容器
  • GitHub宕机应急指南:无缝协作方案
  • Eclipse 里Mybatis的xml的头部报错
  • 软考高级--系统架构设计师--案例分析真题解析
  • Java项目基本流程(五)
  • DeepSeek API 申请与 Node.js 对接指南
  • 服务器硬件电路设计之 SPI 问答(一):解密 SPI—— 从定义到核心特性
  • 服务器硬件电路设计之 SPI 问答(三):SPI 信号完整性守护与时钟频率的硬件设计羁绊
  • PCL+Spigot服务器+python进行MC编程2(使用RCON)---可以生成角色
  • 图论Day6学习心得
  • 源码编译部署 LAMP 架构详细步骤说明
  • 算法第五十二天:图论part03(第十一章)
  • 《算法导论》第 34 章 - NP 完全性
  • HTTP的协议
  • 【爬虫实战-IP代理的重要性二】 以Selenium为例
  • 在 Golang 中复用 HTTP 连接
  • JavaFx 动画-笔记
  • Docker操作速查表
  • MFQ测试分析与测试设计方法学习总结 (KYM)
  • 嵌入式开发学习———Linux环境下网络编程学习(四)
  • Java设计模式-命令模式
  • GitHub 热榜项目 - 日榜(2025-08-20)
  • Flask 之 Request 对象详解:全面掌握请求数据处理
  • 【NFTurbo】基于Redisson滑动窗口实现验证码发送限流
  • 如何在高并发下,保证共享数据的一致性
  • RabbitMQ的架构设计是什么样的
  • Unity 之如何使用Pico4u锚点功能实现一个世界锁GameRoot
  • 第二十七天:游戏组队问题
  • 【GPT入门】第49课 LlamaFacotory 训练千问
  • Mac电脑 Pixelmator Pro 专业图像处理【媲美PS】