来源 | 嵌入式应用研究院 整理&排版 | 嵌入式应用研究院
在工作中,为了方便项目调试,一般情况下我们都会选择开发一个上位机来实现简单的控制和数据读取的功能;但是,这个工具仅限于研发人员使用。为了防止别有用心的测试或者其它人员将这个APP通过U盘的形式拷贝走然后到另外一台电脑上运行,我们可以有以下两种简单的设计方案(以下内容默认用户已了解QT上位机开发,故屏蔽许多细节):
(1)设计一个简单的输入密码逻辑,当输入密码与自己设定的密码匹配时,即进入软件界面。这种方法比较简单,也很容易被破解。
(2)提前通过另外一个软件读取本机的硬件信息(我们称之为注册机),然后通过某种编码格式将该信息编码为其它的格式并生成一个文件(将该文件放到系统较为隐蔽的目录下)。当我们使用的APP打开时,按照约定格式打开并将该文件里的数据转换为硬件信息,然后进行匹配,如果发现没有该文件或者硬件信息不匹配,则提示软件未注册,否则,正常打开该软件。
第一种方法比较简单,初学QT应用编程的小白都可以很容易将它实现,我们就不多说了。我们重点来讲解一下第二种方法的实现。
以下几个命令可以在Window cmd上运行即可以看到对应的信息:
代码语言:javascript复制获取cpu名称
wmic cpu get Name
获取cpu核心数
wmic cpu get NumberOfCores
获取cpu线程数
wmic cpu get NumberOfLogicalProcessors
查询cpu序列号
wmic cpu get processorid
查询主板序列号
wmic baseboard get serialnumber
查询BIOS序列号
wmic bios get serialnumber
查看硬盘
wmic diskdrive get serialnumber
这是我的电脑硬件信息:
其中,CPU序列号是一个唯一的ID号,它是厂家在制造CPU的时候烧入到内部的。我在工作中主要使用这个来进行加密,当然你也可以使用其它的内容。接下来我们可以实现一个简单的注册机逻辑:
- 实现获取硬件信息接口
- 将硬件信息经过Base64格式转换
- 显示Base64格式转换为的结果
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
//获取cpu名称:wmic cpu get Name
//获取cpu核心数:wmic cpu get NumberOfCores
//获取cpu线程数:wmic cpu get NumberOfLogicalProcessors
//查询cpu序列号:wmic cpu get processorid
//查询主板序列号:wmic baseboard get serialnumber
//查询BIOS序列号:wmic bios get serialnumber
//查看硬盘:wmic diskdrive get serialnumber
QString MainWindow::getMachineInfo(const QString &cmd)
{
QProcess p;
p.start(cmd);
p.waitForFinished();
QString result = QString::fromLocal8Bit(p.readAllStandardOutput());
QStringList list = cmd.split(" ");
result = result.remove(list.last(), Qt::CaseInsensitive);
result = result.replace("r", "");
result = result.replace("n", "");
result = result.simplified();
return result;
}
QByteArray MainWindow::Encode(QByteArray data)
{
return data.toBase64();
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("注册机");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_GenerateCode_clicked()
{
QString Code = getMachineInfo("wmic cpu get processorid");
QFile file("D:/Register.txt");
//打开文件,不存在则创建
file.open(QIODevice::ReadWrite | QIODevice::Text);
//写入文件需要字符串为QByteArray格式
if(file.write(Encode(Code.toLatin1())) > 0)
{
ui->CodeDisplay->setText(Encode(Code.toLatin1()));
QMessageBox::information(NULL, "提示", "注册成功", QMessageBox::Ok);
}
else
QMessageBox::information(NULL, "提示", "注册失败", QMessageBox::Ok);
file.close();
}
编译运行后,当我们点击生成注册码时,则会显示硬件信息通过Base64
编码的结果,如下所示:
一个简单的注册机写完以后,APP在加载运行的时候需要加上以下逻辑:
代码语言:javascript复制#include "mainwindow.h"
#include <QApplication>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
QString getMachineInfo(const QString &cmd)
{
QProcess p;
p.start(cmd);
p.waitForFinished();
QString result = QString::fromLocal8Bit(p.readAllStandardOutput());
QStringList list = cmd.split(" ");
result = result.remove(list.last(), Qt::CaseInsensitive);
result = result.replace("r", "");
result = result.replace("n", "");
result = result.simplified();
return result;
}
int main(int argc, char *argv[])
{
uint8_t RunFlag = 0;
QByteArray DecodeStr;
QString CpuSerialNumber;
QApplication a(argc, argv);
//1.获取CPU序列号
CpuSerialNumber = getMachineInfo("wmic cpu get processorid");
//2.打开注册码文件,读取加密字符串并进行匹配加密字符串
QFile file("D:/Register.txt");
if(!file.open(QIODevice::ReadOnly))
{
QMessageBox::warning(NULL, "Error", "注册码不存在,请导入注册码!",QMessageBox::Yes);
return -1;
}
else
{
//读取文件所有的内存
QByteArray EncodeStr = file.readAll();
//将读取的内容进行解码
DecodeStr = fromBase64(EncodeStr);
//将解码的结果与当前PC的CPU序列号进行比较
QString Str(DecodeStr);
if(0 == Str.compare(CpuSerialNumber))
RunFlag = 1;
}
//3.如果匹配成功,运行软件
if(RunFlag)
{
MainWindow w;
w.show();
return a.exec();
}
else
{
QMessageBox::warning(NULL, "Error", "注册码无效,请联系厂商获取注册码!",QMessageBox::Yes);
return -1;
}
return 0;
}
实现注册机更好的方案则可以直接将信息写入注册表,然后APP去注册表中读取相应的内容。关于硬件信息的加密和解密方式,用户可以有其它的实现方法。
这里留一个问题,如何将APP启动信息与其它平台进行关联呢?例如Qt ARM端、Mac端、Android端?