Qt設置軟件使用期限【新版防修改系統時間】

在工業軟件或其他領域中,經常會對軟件進行授權,軟件需要付費進行有期限的使用。以下是我用Qt設計的設置軟件使用期限的兩種方案。

主體思想:

1.軟件需要綁定機器,讓用戶無法通過復制在另一臺機器上運行。

2.由廠家提供激活碼供用戶激活,每個激活碼只對應指定的機器有效,且激活碼需包含使用期限。為保證激活碼不能重復使用,激活碼需包含當天的日期信息,令激活碼僅當天有效,軟件過期或許可證丟失后無法使用之前激活碼進行激活。

3.由于2的限制,因此需要在每臺機器上產生機器碼,供廠家用來生成激活碼。

4.需有校驗功能,校驗激活碼是否有效,校驗是否過期。為了避免用戶修改系統時間來延長使用期限,需要驗證許可證中最后使用日期是否大于當前日期,若是,則說明用戶修改了系統時間,校驗不通過,此時可以在代碼中刪除許可證,或直接退出軟件。

5.需要保存許可證或注冊表。許可證和注冊表信息存儲的是當前激活的密鑰和最后使用日期、有效期限。并在每次開啟和關閉軟件時對許可證內的最后使用日期進行更新。

一、獲取機器碼

要綁定機器,就要獲取到機器的唯一標識,網卡的MAC地址是個不錯的選擇,因此可以拿MAC地址當做機器碼。

QString getMachineCode(){QString text;//獲取非00-00-00-00-00-00的mac地址QRegExp regmac("00.00.00.00.00.00");foreach(QNetworkInterface interface,QNetworkInterface::allInterfaces()){text = interface.hardwareAddress();if(text.indexOf(regmac)>=0)continue;elsebreak;}QString machineCode;for(int i=0;i<6;i++){machineCode.append(text.mid(0,2));text.remove(0,3);}return machineCode;
}

二、生成帶使用期限的激活碼

激活碼可以自己編寫一些算法,通過各種計算、移位、換位等操作來生成。下面是我的示例:

QString newFunction(QString mc, int day)//mc為機器碼,day為使用期限
{QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}
//激活碼中日期信息QDate date = QDate::currentDate();int y=date.year()-2000;int m=date.month();int d=date.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);qDebug()<<dts;int dt = dts.toInt(nullptr,2);QString dthex = QString::number(dt,16);QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);QStringList binlst;binlst.append(hexToBin(copycode.mid(0,2)));binlst.append(hexToBin(copycode.mid(2,2)));binlst.append(hexToBin(copycode.mid(4,2)));binlst.append(hexToBin(copycode.mid(6,2)));binlst.append(hexToBin(copycode.mid(8,2)));binlst.append(hexToBin(copycode.mid(10,2)));int jy = 0;for(int i=7;i>=0;i--){int nums=0;for(int j=0;j<6;j++){if(binlst.at(j).at(i)=='1')nums++;}if(nums%2==1)jy += 1<<i;}qDebug()<<jy;jy += day;int local = day%6;copycode.insert(local*2,tenToHexL(jy));copycode.append(dthex);qDebug()<<copycode;return copycode;
}

三、校驗激活碼

校驗的過程其實就是生成激活碼(不帶期限),與帶期限的激活碼進行比對和運算,判斷其是否有效,若有效則計算使用期限。

int Widget::getValidity(QString code)
{QDate date = QDate::currentDate();int y=date.year()-2000;int m=date.month();int d=date.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = dts.toInt(nullptr,2);QString dthex = QString::number(dt,16);if(dthex!=code.mid(16,4)){//激活碼內日期與當前日期不符,激活碼過期qDebug()<<"code over time!";return 0;}code.remove(16,4);QString mc = getMachineCode();QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);QStringList binlst;binlst.append(hexToBin(copycode.mid(0,2)));binlst.append(hexToBin(copycode.mid(2,2)));binlst.append(hexToBin(copycode.mid(4,2)));binlst.append(hexToBin(copycode.mid(6,2)));binlst.append(hexToBin(copycode.mid(8,2)));binlst.append(hexToBin(copycode.mid(10,2)));int jy = 0;for(int i=7;i>=0;i--){int nums=0;for(int j=0;j<6;j++){if(binlst.at(j).at(i)=='1')nums++;}if(nums%2==1)jy += 1<<i;}int validity=0;for(int i=0;i<12;i+=2){if(copycode.mid(i,2)!=code.mid(i,2)){validity = code.mid(i,4).toInt(nullptr,16)-jy;code.remove(i,4);break;}}if(copycode==code){//激活碼有效,生成許可證writeLicense(copycode,dthex,validity);return validity;}elsereturn 0;
}

四、生成許可證

為了后續校驗方便,許可證內的激活碼可以省略最后幾個步驟。許可證內容由三部分組成:激活碼、最后使用日期、軟件有效期。

void writeLicense(QString code,QString dthex,int days)
{QDate yxq = QDate::currentDate().addDays(days);int y=yxq.year()-2000;int m=yxq.month();int d=yxq.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = dts.toInt(nullptr,2);QString yxqhex = QString::number(dt,16);QFile file("license.dat");file.open(QIODevice::WriteOnly);QDataStream ds(&file);QByteArray ba;ba.resize(10);for(int i=0;i<6;i++){ba[i]=uchar(code.mid(i*2,2).toUInt(nullptr,16));}ba[6]=uchar(dthex.mid(0,2).toUInt(nullptr,16));ba[7]=uchar(dthex.mid(2,2).toUInt(nullptr,16));ba[8]=uchar(yxqhex.mid(0,2).toUInt(nullptr,16));ba[9]=uchar(yxqhex.mid(2,2).toUInt(nullptr,16));ds<<(QByteArray)ba;file.flush();file.close();
}

五、軟件每次啟動時校驗許可證

void Widget::checkLicense()
{QFile file("license.dat");file.open(QIODevice::ReadOnly);QDataStream ds(&file);QByteArray ba;ds>>ba;QString code = ba.toHex();QString shortcode = code.mid(0,12);QString mc = getMachineCode();QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);if(shortcode!=copycode){//激活碼錯誤qDebug()<<"校驗不通過";return;}QDate lastDate;QString dts = code.mid(12,4);int idt = dts.toInt(nullptr,16);int y = idt>>9;int m = (idt>>5) & ((1<<4)-1);int d = idt & ((1<<5)-1);lastDate.setDate(y+2000,m,d);if(lastDate.daysTo(QDate::currentDate())<0){//用戶修改了系統時間qDebug()<<"時間非法";return;}QDate today = QDate::currentDate();y=today.year()-2000;m=today.month();d=today.day();QString s_today = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = s_today.toInt(nullptr,2);QString s_yxq = code.mid(16,4);if(s_yxq.toInt(nullptr,16)<dt){//許可證已過期qDebug()<<"已過期";return;}
}

六、更新許可證

為防止用戶篡改系統時間以達到延長使用期限的目的,許可證中加入了最后使用日期進行校驗。在每次軟件啟動校驗成功后、軟件關閉時,更新許可證中的最后使用日期。

void updateLicense()
{QFile file("license.dat");file.open(QIODevice::ReadWrite);QDataStream ds(&file);QByteArray ba;ds>>ba;QDate today = QDate::currentDate();int y=today.year()-2000;int m=today.month();int d=today.day();QString s_today = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = s_today.toInt(nullptr,2);QString hex = QString::number(dt,16);ba[6]=uchar(hex.mid(0,2).toUInt(nullptr,16));ba[7]=uchar(hex.mid(2,2).toUInt(nullptr,16));file.resize(0);file.seek(0);ds<<ba;file.flush();file.close();
}

以上內容為本地生成許可證的方式,也可以用寫注冊表的方式來代替,主體思想不變。

想要完成代碼的朋友可以私信作者獲取。

請大家多多關注與支持!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93698.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93698.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93698.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【JavaEE】多線程(線程安全問題)

有些代碼在單個線程環境下執行正確&#xff0c;如果同樣的代碼在多個線程下同時執行可能就會出現問題&#xff0c;這個就是線程安全問題&#xff08;或者稱線程不安全問題&#xff09;&#xff0c;簡而言之就是&#xff1a;線程安全問題是由于多線程出現的問題&#xff0c;原因…

NodeJs 桌面開發學習 electron.js (一)

今天開始學習NodeJs 關于 桌面應用的內容&#xff0c;長期目標是 React electron 實現一個桌面應用。今天先實現一個簡單的目標&#xff0c;搭建一個Electron ts 項目架構&#xff0c;并實現主業務線程 和前端渲染線程的交互一、代碼結構和配置例子項目結構大致如下&#xff…

diffusion model(1.4) 相關論文閱讀清單

以下是閱讀清單&#xff1a; 《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》擴散模型&#xff0c;arxiv鏈接《Denoising Diffusion Probabilistic Models》DDPM論文 arxiv鏈接

ESP32-C3_SMARTCAR

前言: 前面用stm32f103c8t6 rt-thread 寫了個智能小車程序 這章用esp32-c3 重新來遍 1&#xff1a;環境 vscodeidf5.4 esp32-3c 找到一塊MIN的底板 湊合用&#xff08;138 cm左右&#xff09; 一個L298N 一個船型開關&#xff0c; 一個665mm 2腳按鈕 鋰電池 186502 及電池盒&a…

消費者API

目錄獨立消費者案例&#xff08;訂閱主題&#xff09;獨立消費者案例&#xff08;訂閱分區&#xff09;消費者組案例獨立消費者案例&#xff08;訂閱主題&#xff09; package com.tsg.kafka.consumer;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.ap…

C# NX二次開發:操作按鈕控件Button和標簽控件Label詳解

大家好&#xff0c;今天介紹ug二次開發過程中的一個叫操作按鈕的控件&#xff0c;這個控件在塊UI編輯器中可以使用。 ? Button這個控件的屬性和方法如下所示&#xff1a; namespace NXOpen.BlockStyler { public class Label : UIBlock { protected intern…

Vue.prototype 的作用

在 Vue.js 中&#xff0c;Vue.prototype 是用來向所有 Vue 實例添加屬性或方法的機制。通過它添加的屬性或方法可以在所有 Vue 組件實例中通過 this 訪問。主要作用添加全局方法或屬性&#xff1a;可以在所有組件中使用的工具方法或常量擴展 Vue 功能&#xff1a;添加 Vue 本身…

Javaee 多線程 --進程和線程之間的區別和聯系

文章目錄進程和線程進程線程進程和線程的區別創建線程的五種寫法繼承Thread,重寫run實現Runnable(接口)&#xff0c;重寫run繼承Thread,重寫run,但是使用匿名內部類實現Runnable(接口)&#xff0c;重寫run&#xff0c;但是使用匿名內部類使用lambda表達式請說明Thread類中run和…

企業如何讓內部視頻僅限指定域名播放,確保視頻不被泄露?

在數字化辦公時代&#xff0c;企業內部的培訓視頻、產品演示或機密會議錄像等敏感內容&#xff0c;一旦被非法傳播或泄露&#xff0c;可能帶來嚴重的商業風險。如何確保這些視頻只能在公司官網或指定域名播放&#xff0c;防止被惡意下載、盜鏈或二次傳播&#xff1f;今天介紹一…

端口映射原理操作詳解教程:實現外網訪問內網服務,本地路由器端口映射公網ip和軟件端口映射域名2種方法

端口映射作為一種不同網絡間通信的關鍵網絡技術&#xff0c;在遠程訪問和內外網連接服務需求日益增長的如今&#xff0c;理解端口映射的原理和設置方法是確保網絡服務可用性的必要技能。本文將深入探討端口映射的基本概念、路由器端口映射設置步驟以及無公網IP用端口映射軟件映…

【PyTorch】多對象分割項目

對象分割任務的目標是找到圖像中目標對象的邊界。實際應用例如自動駕駛汽車和醫學成像分析。這里將使用PyTorch開發一個深度學習模型來完成多對象分割任務。多對象分割的主要目標是自動勾勒出圖像中多個目標對象的邊界。 對象的邊界通常由與圖像大小相同的分割掩碼定義&#xf…

SSH 使用密鑰登錄服務器

用這種方法遠程登陸服務器的時候無需手動輸入密碼 具體步驟 客戶端通過 ssh-keygen 生成公鑰和私鑰 ssh-keygen -t rsa 生成的時候會有一系列問題&#xff0c;根據自己的需要選擇就行。生成的結果為兩個文件&#xff1a; 上傳公鑰至服務器&#xff0c;上述兩個文件一般在客戶…

MySQL 8.4 企業版啟用TDE功能和表加密

一、系統環境操作系統&#xff1a;Ubuntu 24.04 數據庫:8.4.4-commercial for Linux on x86_64 (MySQL Enterprise Server - Commercial)二、安裝TDE組件前提&#xff1a;檢查組件文件是否存在ls /usr/lib/mysql/plugin/component_keyring_encrypted_file.so1.配置全局清單文件…

【Altium designer】導出的原理圖PDF亂碼異常的解決方法

一、有些電源名字無法顯示或器件丟失 解決辦法 (1)首先AD18以及以上的新版本AD不存在該問題。 (2)其次AD17以及更舊版本的AD很可能遇到該問題,參考如下博客筆記進行操作即可: 大致的操作如下:DXP → Preferences → Schematic → Options里面“Render Text with GDI+”…

4.Ansible自動化之-部署文件到主機

4 - 部署文件到受管主機 實驗環境 先通過以下命令搭建基礎環境&#xff08;創建工作目錄、配置 Ansible 環境和主機清單&#xff09;&#xff1a; # 在控制節點&#xff08;controller&#xff09;上創建web目錄并進入&#xff0c;作為工作目錄 [bqcontroller ~]$ mkdir web &a…

Vuex的使用

Vuex 超詳細使用教程&#xff08;從入門到精通&#xff09;一、Vuex 是什么&#xff1f;Vuex 是專門為 Vue.js 設計的狀態管理庫&#xff0c;它采用集中式存儲管理應用的所有組件的狀態。簡單來說&#xff0c;Vuex 就是一個"全局變量倉庫"&#xff0c;所有組件都可以…

pytorch 數據預處理,加載,訓練,可視化流程

流程定義自定義數據集類定義訓練和驗證的數據增強定義模型、損失函數和優化器訓練循環&#xff0c;包括驗證訓練可視化整個流程模型評估高級功能擴展混合精度訓練?分布式訓練?{:width“50%” height“50%”} 定義自定義數據集類 # #1. 自定義數據集類 # class CustomImageD…

Prompt工程:OCR+LLM文檔處理的精準制導系統

在PDF OCR與大模型結合的實際應用中&#xff0c;很多團隊會發現一個現象&#xff1a;同樣的OCR文本&#xff0c;不同的Prompt設計會產生截然不同的提取效果。有時候準確率能達到95%&#xff0c;有時候卻只有60%。這背后的關鍵就在于Prompt工程的精細化程度。 &#x1f3af; 為什…

RecSys:粗排模型和精排特征體系

粗排 在推薦系統鏈路中&#xff0c;排序階段至關重要&#xff0c;通常分為召回、粗排和精排三個環節。粗排作為精排前的預處理階段&#xff0c;需要在效果和性能之間取得平衡。 雙塔模型 后期融合&#xff1a;把用戶、物品特征分別輸入不同的神經網絡&#xff0c;不對用戶、…

spring聲明式事務,finally 中return對事務回滾的影響

finally 塊中使用 return 是一個常見的編程錯誤&#xff0c;它會&#xff1a; 跳過正常的事務提交流程。吞掉異常&#xff0c;使錯誤處理失效 導致不可預測的事務行為Java 中 finally 和 return 的執行機制&#xff1a;1. finally 塊的基本特性 在 Java 中&#xff0c;finally …