利用注册表和配置文件限制用户对软件的使用次数和天数。
XML配置文件字段如下:
0
Kv3cEciR3L
1995.09.02
4
3
字段代表的意思分别为:
1、是否被设为永久使用
字段为1,则说明该用户有永久使用权,不必再进行天数和次数的计算和判断;字段为0,则说明该用户为试用用户,要继续判断是否过期。
2 、配置文件序列号
每一次生成新的配置文件,序列号都不一致。软件第一次运行时,因注册表中不含该序列号,程序会判定为首次运行。
这防止了用户复制初始配置文件,并循环使用的问题。
之后每次运行都会将配置文件里序列号与注册表里的做判断。如果序列号不一致,则判定配置文件是新生成的,接下来按首次运行处理;否则则判定是同一配置文件,进行试用期的计算。
3 、首次启动日期
用来与当前日期作差,更新可使用次数。
另外,当发现本地日期小于首次启动日期时,则判定为用户修改了本地日期,终止使用。
4 、剩余使用天数
5、 剩余使用次数
注册表信息如下:
另外对配置文件采用加密处理,增强安全性。
这里贴出几个重要代码:
1 生成任意长度字符串作为序列号
QString Trialtool::getRandomString(int length)
{
qsrand(QDateTime::currentMSecsSinceEpoch());
const char chrs[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int chrs_size = sizeof(chrs);
char* ch = new char[length + 1];
memset(ch, 0, length + 1);
int randomx = 0;
for (int i = 0; i < length; ++i)
{
randomx= rand() % (chrs_size - 1);
ch[i] = chrs[randomx];
}
QString ret(ch);
delete[] ch;
return ret;
}
2 获取网络时间
QString QVerification::getNetTime()
{
QStringList urls;
urls<<"time-b-g.nist.gov"<<"time-c-g.nist.gov"<<"time-d-g.nist.gov"
<<"time-e-g.nist.gov"<<"time-a-wwv.nist.gov"<<"time-b-wwv.nist.gov"
<<"time-c-wwv.nist.gov"<<"time-d-wwv.nist.gov"<<"time-e-wwv.nist.gov"
<<"time-a-b.nist.gov"<<"time-b-b.nist.gov"<<"time-c-b.nist.gov"
<<"time-d-b.nist.gov"<<"time-e-b.nist.gov"<<"time.nist.gov"
<<"utcnist.colorado.edu"<<"utcnist2.colorado.edu";
QString netTime;
QTcpSocket *socket = new QTcpSocket();
for (int i=0; iconnectToHost(urls.at(i), 13);
//QCoreApplication::processEvents();
if (socket->waitForConnected())
{
if (socket->waitForReadyRead())
{
QString str(socket->readAll());
netTime = str.trimmed();
netTime = str.section(" ", 1, 2);
qDebug()<close();
}
delete socket;
return netTime;
}
3 计算日期间隔
int mon[12] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
int cal(int y, int m, int d)
{
return y * 365 + y / 4 - y / 100 + y / 400 +
mon[m - 1] + d - 1 +
(((y % 100 != 0 && y % 4 == 0) || y % 400 == 0) && m > 2);
}
//...
int iDateBefore = cal(iyearBefor, imonthBefor, idayBefor);
int iDateAfter = cal(iYear, iMonth, iDay);
//检测时间是否被修改
if (iDateBefore > iDateAfter)
{
//...
}
试用期判定类的代码如下:
/**
试用期校验类
**/
#ifndef QVERIFICATION_H
#define QVERIFICATION_H
#include
class QVerification : public QObject
{
Q_OBJECT
public:
QVerification(QObject *parent = NULL);
~QVerification();
//1:永久使用
//0:可以使用
//-1:找不到xml文件
//-2:复制了XML
//-3: 时间被修改
//-4:试用结束
//-5:文件解密失败
//-6:文件加密失败
int verification();
private:
void writeRegedit(QString key, QString val);
QString getRegedit(QString key);
void removeRegedit(QString key);
QString getNetTime();
void firstRun(QString CDKey, int iDays, int iTimes, QString date);
};
#endif // QVERIFICATION_H
#include "qverification.h"
#include "XmlTools.h"
#include
#include
#include
#include
#include
#include "base64.h"
int mon[12] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
int cal(int y, int m, int d)
{
return y * 365 + y / 4 - y / 100 + y / 400 +
mon[m - 1] + d - 1 +
(((y % 100 != 0 && y % 4 == 0) || y % 400 == 0) && m > 2);
}
QVerification::QVerification(QObject *parent)
: QObject(parent)
{
QCoreApplication::setOrganizationName("Zhangzhihao");
QCoreApplication::setApplicationName("testTrailTool");
}
QVerification::~QVerification()
{
qDebug()<<"jkl";
}
void QVerification::writeRegedit(QString key, QString val)
{
QSettings Setting(QSettings::NativeFormat, QSettings::SystemScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
Setting.setValue(key, val);
}
QString QVerification::getRegedit(QString key)
{
QSettings Setting(QSettings::NativeFormat, QSettings::SystemScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
QString val = Setting.value(key).toString();
return val;
}
void QVerification::removeRegedit(QString key)
{
QSettings Setting(QSettings::NativeFormat, QSettings::SystemScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
Setting.remove(key);
}
QString QVerification::getNetTime()
{
QStringList urls;
urls<<"time-b-g.nist.gov"<<"time-c-g.nist.gov"<<"time-d-g.nist.gov"
<<"time-e-g.nist.gov"<<"time-a-wwv.nist.gov"<<"time-b-wwv.nist.gov"
<<"time-c-wwv.nist.gov"<<"time-d-wwv.nist.gov"<<"time-e-wwv.nist.gov"
<<"time-a-b.nist.gov"<<"time-b-b.nist.gov"<<"time-c-b.nist.gov"
<<"time-d-b.nist.gov"<<"time-e-b.nist.gov"<<"time.nist.gov"
<<"utcnist.colorado.edu"<<"utcnist2.colorado.edu";
QString netTime;
QTcpSocket *socket = new QTcpSocket();
for (int i=0; iconnectToHost(urls.at(i), 13);
//QCoreApplication::processEvents();
if (socket->waitForConnected())
{
if (socket->waitForReadyRead())
{
QString str(socket->readAll());
netTime = str.trimmed();
netTime = str.section(" ", 1, 2);
qDebug()<close();
}
delete socket;
return netTime;
}
int QVerification::verification()
{
QString msg;
Base64 base64;
QString filePath = QCoreApplication::applicationDirPath().append("/").append("usage.xml");
//Base64解密
if (!base64.Decrypt(filePath))
{
QMessageBox::critical(0, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("读配置文件,解密失败!"));
qDebug() << QString::fromLocal8Bit("读配置文件,解密失败!");
return -5;
}
bool bRet = XmlTools::GetInstance()->LoadXmlFile(filePath.toLocal8Bit().constData());
//找不到配置文件时失败
if (!bRet)
{
QMessageBox::critical(0, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("加载秘钥文件失败!"));
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return -1;
}
//获取xml信息
bool bIsPermanent = QString(XmlTools::GetInstance()->GetValue("UsageConfig/IsPermanent")).trimmed().toInt();
QString CDKey = QString(XmlTools::GetInstance()->GetValue("UsageConfig/CDKey")).trimmed();
QString fisrtUsageDate = QString(XmlTools::GetInstance()->GetValue("UsageConfig/fisrtUsageDate")).trimmed();
int iViableDays = QString(XmlTools::GetInstance()->GetValue("UsageConfig/viableDays")).trimmed().toInt();
int iViableTimes = QString(XmlTools::GetInstance()->GetValue("UsageConfig/viableTimes")).trimmed().toInt();
//永久使用
if (bIsPermanent)
{
QMessageBox::critical(0, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("你已获得永久使用权!"));
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return 1;
}
//获取网络时间,失败则试用本地时间
QString timeNet = getNetTime();
QDateTime currentime = QDateTime::currentDateTime();
if (timeNet.isNull())
{
timeNet = currentime.toString("yyyy-MM-dd hh:mm:ss");
}
else
{
timeNet = QString("20").append(timeNet);
}
//拆分日期
int iYear, iMonth, iDay;
QStringList temp = timeNet.split(" ").at(0).split("-");
iYear = temp.at(0).toInt();
iMonth = temp.at(1).toInt();
iDay = temp.at(2).toInt();
//次数减一
iViableTimes--;
QStringList dateList;
dateList< 0 && iViableTimes >= 0)
{
//计算时间间隔
QStringList temp = fisrtUsageDate.split(".");
int iyearBefor = temp.at(0).toInt();
int imonthBefor = temp.at(1).toInt();
int idayBefor = temp.at(2).toInt();
int iDateBefore = cal(iyearBefor, imonthBefor, idayBefor);
int iDateAfter = cal(iYear, iMonth, iDay);
//检测时间是否被修改
if (iDateBefore > iDateAfter)
{
QMessageBox::critical(0, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("检测到系统时间被改变!"));
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return -3;
}
//次数更新
int iGap = iDateAfter - iDateBefore;
iViableDays = iViableDays - iGap;
if (iViableDays < 0)
{
msg = QString::fromLocal8Bit("软件试用已结束,请联系供应商注册!");
QMessageBox::critical(0, QString::fromLocal8Bit("提示"), msg);
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return -4;
}
XmlTools::GetInstance()->SetValue("UsageConfig/viableDays", QString::number(iViableDays).toStdString().c_str());
XmlTools::GetInstance()->SetValue("UsageConfig/viableTimes", QString::number(iViableTimes).toStdString().c_str());
msg = QString::fromLocal8Bit("%1日后的24:00时或启动%2次后试用结束!").arg(iViableDays).arg(iViableTimes);
QMessageBox::critical(0, QString::fromLocal8Bit("提示"), msg);
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return 0;
}
else
{
msg = QString::fromLocal8Bit("软件试用已结束,请联系供应商注册!");
QMessageBox::critical(0, QString::fromLocal8Bit("提示"), msg);
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return -4;
}
}
}
//否则如果不是同一个,则是新的秘钥文件要先清除注册表,当首次运行处理
else
{
//写入首次启动日期,更新xml日期及次数
msg = QString::fromLocal8Bit("%1日后的24:00时或启动%2次后试用结束!").arg(iViableDays).arg(iViableTimes);
QMessageBox::critical(0, QString::fromLocal8Bit("提示"), msg);
firstRun(CDKey, iViableDays, iViableTimes, date);
if (!base64.Encrypt(filePath))
{
qDebug() << QStringLiteral("读配置文件,加密失败!");
return -5;
}
return 0;
}
}
void QVerification::firstRun(QString CDKey, int iDays, int iTimes, QString date)
{
//删除历史信息
removeRegedit("cdKey");
//removeRegedit("firstRunDate");
XmlTools::GetInstance()->SetValue("UsageConfig/fisrtUsageDate", date.toLocal8Bit().constData());
XmlTools::GetInstance()->SetValue("UsageConfig/viableDays", QString::number(iDays).toStdString().c_str());
XmlTools::GetInstance()->SetValue("UsageConfig/viableTimes", QString::number(iTimes).toStdString().c_str());
//32位程序运行在WOW64模式下,setting被存储在 HKEY_LOCAL_MACHINE\Software\WOW6432Node上
//writeRegedit("firstRunDate", date);
writeRegedit("cdKey", CDKey);
}
试用期设置界面如下:
完整源码以及测试环境连接如下:
https://download.csdn.net/download/qq_24282081/11431425