前言
程序員為了防止自己的成果被白嫖拟逮,或者發(fā)布的軟件在公司層面上要做一些防抄襲處理,這時就需要在軟件層面上加鎖适滓、加密等操作敦迄。
1、單機終端軟件
這類軟件一般在未聯(lián)網(wǎng)的情況下使用凭迹,所以不能通過網(wǎng)絡去判定是否得到授權罚屋,一般采用綁定硬件信息來對軟件進行加密,這樣軟件與設備綁定就無法進行隨意使用嗅绸。
2脾猛、遠程授權監(jiān)控
終端軟件在啟動后就會跟服務器通訊來檢查當前設備是否已經(jīng)得到授權,可實現(xiàn)遠程鎖定程序鱼鸠,設置程序的使用時間和使用次數(shù)猛拴。
以上兩種方法都是最基礎的軟件加密方法,根據(jù)加密的算法的復雜度其破解的難度也不同蚀狰,不過作為普通的一種加密方法已經(jīng)夠用了愉昆,市面上有比較成熟的加密加殼的軟件,其安全程度要遠高于軟件加密的方法麻蹋,下次抽時間介紹一下軟件VMProtect的加跛溉、解密過程。
1哥蔚、思路分析
單機軟件想要每次啟動前去驗證是否有授權倒谷,需要從軟件的配置中獲取授權的驗證信息,這里以軟件的使用次數(shù)來舉例糙箍,我們需要把軟件的可使用次數(shù)寫入配置文件ini或數(shù)據(jù)庫中渤愁。每次在軟件重新啟動時,我們根據(jù)配置文件中信息來判斷軟件剩余的使用次數(shù)深夯。
這里設定軟件的剩余使用次數(shù)為2次抖格,不過這里有一個很明顯的缺點诺苹,就是明文寫到配置文件里,就可以自己修改雹拄,然后就失去了加密的屬性收奔,這里就需要對這個信息進行加密后再寫入。這里使用Qt自帶的base64對字符串進行加密滓玖。
2坪哄、實現(xiàn)函數(shù)
//加密
QString Widget::Encode(QString row)
{
QByteArray byteArray = row.toUtf8();
byteArray = byteArray.toBase64();
return byteArray;
}
//解密
QString Widget::Decode(QString passwd)
{
QByteArray byteArray = passwd.toUtf8();
byteArray = QByteArray::fromBase64(byteArray);
return byteArray;
}
//從配置文件獲取信息
QString Widget::getInfoFromIni(QString str)
{
QString info;
QFile file(str);
if(!file.exists()) { //如果文件不存在
QString times_str = "RemainTime:"+time;
WriteInfo2Ini(str, times_str);
}
file.open(QFile::ReadWrite | QFile::Text);
info = file.readAll(); //讀取信息
file.close();
return info;
}
//將信息寫入到配置文件
void Widget::WriteInfo2Ini(QString str, QString info_text)
{
QFile file(str);
file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate);
file.write(Encode(info_text).toUtf8()); //寫入信息
file.close();
}
這種方法有一種弊端,就是如果重新覆蓋配置文件可以跳出限制势篡,比如這里如果事前拷貝一份ini文件翩肌,當軟件次數(shù)為0后,重新拷貝原始ini文件后又獲得初始的軟件使用次數(shù)禁悠。
如果考慮不使用ini文件來記錄授權信息念祭,而是使用注冊表來記錄授權信息,這樣軟件使用者就不容易去發(fā)現(xiàn)授權信息的位置
void Widget::WriteInfo2Registry(QString str)
{
//寫入注冊表
QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat);
settings.setValue("remain_times",Encode(str).toUtf8());
}
QString Widget::getInfoFromRegistry()
{
QString info;
//通過寫入注冊表來判斷
QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat);
info = settings.value("remain_times").toString();
return info;
}
3碍侦、示例代碼
widget.cpp
#pragma execution_character_set("utf-8")
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QString str = getCpuId();
qDebug()<<"cpu id is"<<str;
// QString times_str = "RemainTime:"+time;
// WriteInfo2Registry(times_str);
Judge_Authorize_times(1);
}
Widget::~Widget()
{
delete ui;
}
QString Widget::getWMIC(const QString &cmd)
{
//獲取cpu名稱:wmic cpu get Name
//獲取cpu核心數(shù):wmic cpu get NumberOfCores
//獲取cpu線程數(shù):wmic cpu get NumberOfLogicalProcessors
//查詢cpu序列號:wmic cpu get processorid
//查詢主板序列號:wmic baseboard get serialnumber
//查詢BIOS序列號:wmic bios get serialnumber
//查看硬盤:wmic diskdrive get serialnumber
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;
}
QString Widget::getCpuId() //獲取CPU序列號
{
return getWMIC("wmic cpu get processorid");
}
QString Widget::getDiskNum() //獲取硬盤序列號
{
return getWMIC("wmic diskdrive where index=0 get serialnumber");
}
QString Widget::Encode(QString row)
{
QByteArray byteArray = row.toUtf8();
byteArray = byteArray.toBase64();
return byteArray;
}
QString Widget::Decode(QString passwd)
{
QByteArray byteArray = passwd.toUtf8();
byteArray = QByteArray::fromBase64(byteArray);
return byteArray;
}
QString Widget::getInfoFromIni(QString str)
{
QString info;
QFile file(str);
if(!file.exists()) { //如果文件不存在
QString times_str = "RemainTime:"+time;
WriteInfo2Ini(str, times_str);
}
file.open(QFile::ReadWrite | QFile::Text);
info = file.readAll(); //讀取信息
file.close();
return info;
}
void Widget::WriteInfo2Ini(QString str, QString info_text)
{
QFile file(str);
file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate);
file.write(Encode(info_text).toUtf8()); //寫入信息
file.close();
}
void Widget::WriteInfo2Registry(QString str)
{
//寫入注冊表
QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat);
settings.setValue("remain_times",Encode(str).toUtf8());
}
QString Widget::getInfoFromRegistry()
{
QString info;
//通過寫入注冊表來判斷
QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat);
info = settings.value("remain_times").toString();
return info;
}
void Widget::Judge_Authorize_times(int type)
{
QString times_info;
if(type == 0)
{
//通過ini配置文件進行判斷
times_info = getInfoFromIni("System.ini");
}
else
{
//通過寫入注冊表來判斷
times_info = getInfoFromRegistry();
}
if(times_info.isEmpty())
{
QMessageBox::about(this,"提示","授權信息為空粱坤,請檢查!");
exit(0);
}
else
{
QString info = Decode(times_info); //解碼
if(info.contains(':')) { //信息正確
QStringList list = info.split(':');
if(list.length()>=1) {
if(list[1].toInt() <= 0) { //程序剩余使用次數(shù)不足
QMessageBox::about(this,"提示","請注冊后再使用瓷产!");
exit(0); //程序退出
}else { //程序還有剩余使用次數(shù)
QString time_remain = QString::number(list[1].toInt()-1); //程序剩余使用次數(shù)減1
QString str = "RemainTime:"+time_remain;
if(type == 0) WriteInfo2Ini("System.ini", str);
else {
//寫入注冊表
WriteInfo2Registry(str);
}
QMessageBox::about(this,"提示","程序剩余使用次數(shù):"+time_remain+"次");
}
}
}
}
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QFile>
#include <QMessageBox>
#include <QProcess>
#include <QDebug>
#include <QSettings>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QString getWMIC(const QString &cmd);
QString getCpuId();
QString getDiskNum();
//加密
QString Encode(QString row);
//解密
QString Decode(QString passwd);
//判斷授權信息 0:使用ini方法判斷站玄;1:使用注冊表方法判斷
void Judge_Authorize_times(int type);
//從ini獲取授權信息
QString getInfoFromIni(QString str);
//寫入授權信息到ini
void WriteInfo2Ini(QString str, QString info_text);
//從注冊表獲取授權信息
QString getInfoFromRegistry();
//寫入授權信息到注冊表
void WriteInfo2Registry(QString str);
//授權程序使用次數(shù)為2次
QString time = "2";
};
#endif // WIDGET_H
4、效果展示
源碼放到gitee倉庫:Code_Encryption源碼