Qt--探讨.exe程序加密

一、前言

程序员随着代码写的多,难免会接到一些私活。但是又怕对方白嫖,困难总比办法多,哦不,错了,办法总比困难多。为了避免被别人白嫖,我们可以给自己的程序留后手,网上查阅资料,大概有以下两种:

1、采用远程控制:UDP指令远程锁死程序;

2、采用本地加密:提取CPU和硬盘序列号,加密生成注册码;

以上两种方法各有利弊,方法1可以本人自由控制,但是一旦设备没网,就GG了;方法2则不依赖网络,且每台设备的注册码唯一,但是本人无法直接控制。个人认为还是方法2简单有效,所以下面就方法2进行具体分析。


二、分析

采用注册码机制,我们首先要生成注册码,Qt下获取CPU和硬盘等系统信息(针对windows系统)的方法如下:

windows下执行命令除了用cmd之外,还有个东西叫WMIC,非常强大,可以通过他获取很多信息,包括硬件信息。

QString Widget::getWMIC(const QString &cmd)
{
    //获取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
    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::getCpuName()
{
    return getWMIC("wmic cpu get name");
}
 
QString Widget::getCpuId()
{
    return getWMIC("wmic cpu get processorid");
}
 
QString Widget::getDiskNum()
{
    return getWMIC("wmic diskdrive where index=0 get serialnumber");
}

获取注册码之后,就可以着手程序的加密了,我的策略是这样的:

  • 如果程序没有注册,默认可以使用3次;
  • 如果程序注册了,使用次数无限制;

那怎么限制程序的使用次数呢?我的策略是这样的:

  • 生成一个System.ini配置文件,里面存放程序的剩余运行次数RemainTime:3
  • 但是RemainTime:3当然不能直接存在System.ini中,不然一眼看出来就可以自己修改次数了;
  • 所以在对System.ini写之前,进行加密;对System.ini读之后,进行解密;
  • 加/解密算法可以自行选取,但是要采用可逆算法;
  • 然后判断剩余运行次数,如果小于等于0,则程序提示需注册后使用,并退出;
  • 否则,剩余运行次数减1,程序正常运行;

三、实现(核心代码)

QString Widget::getWMIC(const QString &cmd)
{
    //获取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
    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;
}

void Widget::Judge_Valid() //判断程序合法性
{
    QString filePath = "System.ini";
    QFile file(filePath);

    if(!file.exists()) { //如果文件不存在
        file.open(QIODevice::ReadWrite | QIODevice::Text); //新建文件
        QString info = "RemainTime:"+time; //time是全局变量,QString time = "3";
        file.write(Encode(info).toUtf8()); //写入信息
        file.close();
         goto Here;
    }else {	//如果文件存在
        Here:if(file.open(QFile::ReadWrite | QFile::Text)) { //打开文件
            QString info = file.readAll(); //读取信息
            if(info.isEmpty()) { //如果文件为空
                QString time_temp = "1";
                QString info = "RemainTime:"+time_temp;
                file.write(Encode(info).toUtf8()); //写入信息
                info = file.readAll();
            }
            info = Decode(info); //解码
            if(info.contains(':')) {	//信息正确
                QStringList list = info.split(':');
                if(list.length()>=1) {
                    if(list[1].toInt() <= 0) {	//程序剩余使用次数不足
                        QMessageBox::about(this,"提示","请注册后再使用!");
                        exit(0); //程序退出
                    }else {	//程序还有剩余使用次数
                        file.close();
                        file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); //清空文件内容
                        QString time_remain = QString::number(list[1].toInt()-1); //程序剩余使用次数减1
                        QString info = "RemainTime:"+time_remain;
                        file.write(Encode(info).toUtf8()); //更新程序剩余使用次数
                        QMessageBox::about(this,"提示","程序剩余使用次数:"+time_remain+"次");
                    }
                }
            }
      }//Here
      file.close();

   }//如果文件存在
}

四、效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


附:MD5加密注册码

//获取设备信息字符串
const QString get_SerialNumber()
{
    QString cpu_id = "";
    QProcess p(0);
    p.start("wmic CPU get ProcessorID");  //其它信息也类似
    p.waitForStarted();
    p.waitForFinished();
    cpu_id = QString::fromLocal8Bit(p.readAllStandardOutput());
    cpu_id = cpu_id.remove("ProcessorId").trimmed();

    QString lpRootPathName = "C:\\";
    LPTSTR lpVolumeNameBuffer=new TCHAR[12];//磁盘卷标
    DWORD nVolumeNameSize=12;// 卷标的字符串长度
    DWORD VolumeSerialNumber;//硬盘序列号
    DWORD MaximumComponentLength;// 最大的文件长度
    LPTSTR lpFileSystemNameBuffer=new TCHAR[10];// 存储所在盘符的分区类型的长指针变量
    DWORD nFileSystemNameSize=10;// 分区类型的长指针变量所指向的字符串长度
    DWORD FileSystemFlags;// 文件系统的一此标志
    GetVolumeInformation((LPTSTR)lpRootPathName.utf16(),
                         lpVolumeNameBuffer, nVolumeNameSize,
                         &VolumeSerialNumber, &MaximumComponentLength,
                         &FileSystemFlags,
                         lpFileSystemNameBuffer, nFileSystemNameSize);
    return (cpu_id.mid(0,4) + "D-"+ cpu_id.mid(4,4) + "R-" +
            cpu_id.mid(8,4) + "E-" + cpu_id.mid(12,4) + "A-" +
            QString::number(VolumeSerialNumber,10).mid(0,4)+"M");
}

//使用MD5对设备信息字符串进行加密
const QString hash_Encryption(const QString temp)
{
    QByteArray byte_array;
    byte_array.append(temp);
    QByteArray hash_byte_array = QCryptographicHash::hash(byte_array,QCryptographicHash::Md5);
    return hash_byte_array.toHex().toUpper();
}

//将加密后的字符串序列化为注册码形式
const QString format_HASHString(const QString hashtemp)
{
    QString retemp = "";
    for(int i = 0; i < 7; i++)
    {
        retemp += hashtemp.mid(4*i,4) + "-";
    }
    retemp += hashtemp.mid(28,4);
    return retemp;
}

//去除注册码格式,转化为MD5加密后的字符串
const QString remove_Format(const QString formathash)
{
    QString temp = "";
    for(int i = 0; i < 8; i++)
    {
        temp += formathash.mid(5*i,4);
    }
    return temp;
}
  • 7
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
Zprotect是新一代的软件加密保护系统,拥有多项革命性的创新技术,设计用来保护您的软件产品不被破解,减少由于盗版给您带来的经济损失!此外,Zprotect 拥有简单易用的许可控制系统,您无需更改任何代码,即可为您的软件添加注册机制。与传统软件保护系统相比,Zprotect更加注重对代码的处理,并且拥有良好的稳定性和兼容性,是您配置软件保护系统的最佳选择! Zprotect拥有简单易用、高效灵活的注册和授权管理系统: 一键试用技术. Zprotect 为您提供一键试用技术,您不必修改任何源代码,在短短几分钟之内就可以将您的完整版软件转换为“先试用后购买”的试用版软件,甚至还可以支持带硬件锁定的序列号注册。 内建注册和许可管理系统. Zprotect 内建灵活易用的注册和许可管理系统,您可以轻松创建具有时间限制、硬件锁定、水印信息的注册码。 动态算法生成引擎. 外壳所使用算法均动态生成,随机且唯一,让逆向算法变得困难和高成本。 时间限制注册密钥. 如果您需要限制注册版本的有效期,可以通过创建具有时间限制的注册密钥来实现。 硬件锁定(一机一码). 激活硬件锁定功能的注册密钥,只能在某一特定计算机上使用;您可以通过锁定用户计算机的硬件信息来控制注册码的传播,例如 CPU、硬盘序列号、网卡 MAC 地址等。 密钥黑名单. 如果您的用户泄漏了注册密钥,那么您就可以将该密钥添加进密钥黑名单,这样下一版本更新的时候您就可以锁定该密钥。 启动密码保护. 这种附加的保护可以有效防止软件未经授权的使用,必须输入正确的密码才可以运行程序。 试用次数、天数、日期和运行时间限制. 使用 Zprotect ,您可以轻松为您的应用程序添加试用次数、试用天数、试用日期和试运行时间等限制;这样您的客户就可以全功能评估您的软件产品,增大购买意向

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝勒里恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值