在软件开发中,如何保护知识产权、控制软件使用权限是开发者经常面临的问题。本文将基于 Qt 框架,介绍一种简单有效的软件授权验证机制,该机制通过硬件绑定、时效控制和防篡改等手段,实现对软件使用权限的管理。
方案设计思路
本方案主要包含以下几个核心功能:
- 基于硬件信息生成唯一设备标识
- 记录软件首次运行时间,实现时效控制
- 防止用户通过修改系统时间绕过时效限制
- 将授权信息存储在隐藏目录中,提高安全性
核心代码实现
1. 接口类定义
首先定义一个哈希接口类HashInterface,提供单例实例和有效性验证方法:
// hashinterface.h
#pragma once
#include "hashinterface_global.h"
class HASHINTERFACE_EXPORT HashInterface
{
public:
HashInterface() = default;
bool validity();
static HashInterface& instance();
};
2. 硬件唯一标识生成
通过获取设备硬件信息(如磁盘序列号、CPU 信息等),生成唯一的设备标识,实现软件与设备的绑定:
// 生成设备唯一标识
QString getMachineID()
{
// 获取硬件序列号(Windows)
QStorageInfo storage = QStorageInfo::root();
QString diskSerial = storage.device();
// 获取CPU信息(可根据不同系统扩展)
QString cpuInfo = LISENCE_TAIL;
// 合并硬件信息并生成哈希
QString uniqueData = diskSerial + cpuInfo;
QByteArray hash = QCryptographicHash::hash(uniqueData.toUtf8(), QCryptographicHash::Sha256);
return QString(hash.toHex());
}
3. 授权文件存储
将授权信息存储在隐藏目录中,提高非授权用户的修改难度:
QString getHiddenStoragePath()
{
// 获取用户数据目录(隐藏目录)
QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
// 生成随机隐藏子目录名
QString hiddenDirName = QString("App%1").arg(QChar(0x20)) + "Data";
QString hiddenDirPath = QDir(basePath).filePath(hiddenDirName);
// 创建目录并设置隐藏属性
if (!QDir(hiddenDirPath).exists())
{
QDir().mkpath(hiddenDirPath);
QProcess::execute("attrib", QStringList() << "+h" << hiddenDirPath);
}
return hiddenDirPath;
}
4. 时效控制实现
记录软件首次运行时间,并在每次启动时校验是否过期:
// 首次运行记录时间
void saveFirstRunTime()
{
QDateTime installTime = QDateTime::currentDateTime();
QString machineId = getMachineID();
// 加密数据(示例使用Base64,实际应使用AES等更强加密)
QByteArray data = (installTime.toString(Qt::ISODate) + "|" + machineId).toUtf8();
data = data.toBase64();
// 存储到本地文件
saveLisenceData(data);
}
// 每次启动校验时间
bool checkExpiration()
{
// 读取加密文件
QByteArray data = getLisenceData();
QStringList parts = QString(data).split("|");
QDateTime installTime = QDateTime::fromString(parts[0], Qt::ISODate);
QString storeMachineID = parts[1];
QString currentMachineID = getMachineID();
// 校验设备标识
if (storeMachineID != currentMachineID)
{
return false;
}
// 计算使用天数
qint64 daysElapsed = installTime.daysTo(QDateTime::currentDateTime());
#ifdef QT_DEBUG
printf("[Attention] It has been running for %d days and has only %d days left!\n", daysElapsed, LISENCE_DAYS - daysElapsed);
#endif
return (daysElapsed <= LISENCE_DAYS);
}
5. 防时间篡改机制
通过记录上次运行时间,防止用户通过修改系统时间绕过时效限制:
// 保存上次运行时间
void saveLastRunTime()
{
QDateTime currentTime = QDateTime::currentDateTime();
QSettings settings(APP_COMPANY, APP_NAME);
settings.setValue(APP_PARAM, currentTime);
}
// 检查时间完整性
bool checkTimeIntegrity()
{
QSettings settings(APP_COMPANY, APP_NAME);
QDateTime lastRunTime = settings.value(APP_PARAM).toDateTime();
QDateTime currentTime = QDateTime::currentDateTime();;
if (currentTime < lastRunTime)
{
return false;
}
return true;
}
6. 验证入口函数
将上述功能整合,提供统一的验证入口:
bool HashInterface::validity()
{
if (!isLisenceDataExist())
{
// 首次运行,保存初始信息
saveFirstRunTime();
}
else
{
// 非首次运行,验证授权
if (!checkExpiration() || !checkTimeIntegrity())
{
printf("[ERROR] Expiration of registration code ,please contact developer!");
return false;
}
}
// 保存本次运行时间,用于下次验证
saveLastRunTime();
return true;
}
// 单例实现
HashInterface& HashInterface::instance()
{
static HashInterface manager;
return manager;
}
使用方法
在软件启动时,只需调用以下代码进行授权验证:
if (!HashInterface::instance().validity()) {
// 验证失败,处理逻辑(如退出程序)
return -1;
}
// 验证成功,继续运行程序
安全性考虑
- 示例中使用了简单的 Base64 编码,实际应用中应使用 AES 等加密算法
- 硬件信息的获取可以根据不同操作系统进行扩展,提高唯一性
- 隐藏目录的命名方式可以进一步优化,增加隐蔽性
- 可以增加授权文件的签名验证,防止文件被篡改
总结
本方案通过硬件绑定、时效控制和防篡改等多重机制,实现了一个基础的软件授权验证系统。开发者可以根据实际需求,在此基础上扩展更复杂的授权逻辑,如网络验证、授权码激活等功能,进一步提高软件的安全性。
3356

被折叠的 条评论
为什么被折叠?



