[Qt學習筆記]Qt程序加密坏匪,實現(xiàn)軟件運行次數(shù)和硬件信息綁定

前言

程序員為了防止自己的成果被白嫖拟逮,或者發(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ù)深夯。


111.JPG

這里設定軟件的剩余使用次數(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、效果展示

20220803222718.gif

源碼放到gitee倉庫:Code_Encryption源碼

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拦英,一起剝皮案震驚了整個濱河市蜒什,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疤估,老刑警劉巖灾常,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铃拇,居然都是意外死亡钞瀑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門慷荔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雕什,“玉大人,你說我怎么就攤上這事显晶〈叮” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵磷雇,是天一觀的道長偿警。 經(jīng)常有香客問我,道長唯笙,這世上最難降的妖魔是什么螟蒸? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任盒使,我火速辦了婚禮,結果婚禮上七嫌,老公的妹妹穿的比我還像新娘少办。我一直安慰自己,他們只是感情好诵原,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布英妓。 她就那樣靜靜地躺著,像睡著了一般绍赛。 火紅的嫁衣襯著肌膚如雪鞋拟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天惹资,我揣著相機與錄音,去河邊找鬼航闺。 笑死褪测,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的潦刃。 我是一名探鬼主播侮措,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乖杠!你這毒婦竟也來了分扎?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤胧洒,失蹤者是張志新(化名)和其女友劉穎畏吓,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卫漫,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡菲饼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了列赎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宏悦。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖包吝,靈堂內(nèi)的尸體忽然破棺而出饼煞,到底是詐尸還是另有隱情,我是刑警寧澤诗越,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布砖瞧,位于F島的核電站,受9級特大地震影響掺喻,放射性物質發(fā)生泄漏芭届。R本人自食惡果不足惜储矩,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褂乍。 院中可真熱鬧持隧,春花似錦、人聲如沸逃片。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褥实。三九已至呀狼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間损离,已是汗流浹背哥艇。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留僻澎,地道東北人貌踏。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像窟勃,于是被迫代替她去往敵國和親祖乳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容