基于Qt的机器绑定与有效期设置

来源:互联网 发布:mac自动整理文件夹 编辑:程序博客网 时间:2024/05/16 22:23

http://1.johnhome.sinaapp.com/?p=310


以下函数可分别 获取主机硬件信息:
CPU, cpuid
硬盘,hardDisk
主板,motherBoared
网卡信息,netInterfaceCard.
 
 
通过WMI接口获取硬件信息,但这些信息有些未必可靠

QString logInDialog::getWMIHWInfo(int type){
/*
//0.当前原生网卡地址:
SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))
// 1.硬盘序列号
SELECT PNPDeviceID FROM Win32_DiskDrive WHERE(SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed hard disk%')
//2.获取主板序列号
SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)
// 3.处理器ID
SELECT ProcessorId FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)
// 4.BIOS序列号
SELECT SerialNumber FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)
// 5.主板型号
SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)*/

QString hwInfo=tr("");
QStringList sqlCmd;
sqlCmd.clear();
sqlCmd<<tr("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))");
//注意qt调用 wmi时,对查询语句要求很严格,所以 like之类的句子务必精确才能有结果出来
sqlCmd<<tr("SELECT PNPDeviceID FROM Win32_DiskDrive WHERE( PNPDeviceID IS NOT NULL) AND (MediaType LIKE 'Fixed%')");
sqlCmd<<tr("SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)");
sqlCmd<<tr("SELECT ProcessorId FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)");
sqlCmd<<tr("SELECT SerialNumber FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)");
sqlCmd<<tr("SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)");
QStringList columnName;
columnName.clear();
columnName<<tr("MACAddress");
columnName<<tr("PNPDeviceID");
columnName<<tr("SerialNumber");
columnName<<tr("ProcessorId");
columnName<<tr("SerialNumber");
columnName<<tr("Product");
QAxObject *objIWbemLocator = new QAxObject("WbemScripting.SWbemLocator");
QAxObject *objWMIService =objIWbemLocator->querySubObject("ConnectServer(QString&,QString&)",QString("."),QString("root\\cimv2"));
QString query=tr("");
if(type<sqlCmd.size())
query=sqlCmd.at(type);
QAxObject *objInterList = objWMIService->querySubObject("ExecQuery(QString&))", query);
QAxObject *enum1 = objInterList->querySubObject("_NewEnum");
//需要 include windows.h
IEnumVARIANT* enumInterface = 0;
enum1->queryInterface(IID_IEnumVARIANT, (void**)&enumInterface);
enumInterface->Reset();
for (int i = 0; i < objInterList->dynamicCall("Count").toInt(); i++) {
VARIANT *theItem = (VARIANT*)malloc(sizeof(VARIANT));
if (enumInterface->Next(1,theItem,NULL) != S_FALSE){
QAxObject *item = new QAxObject((IUnknown *)theItem->punkVal);
if(item){
if(type<columnName.size()){
QByteArray datagram(columnName.at(type).toAscii()); //Or
const char* tempConstChar = datagram.data();
qDebug()<<"the query is "<<query<<" and cn is "<<QString::fromAscii(tempConstChar);
hwInfo=item->dynamicCall(tempConstChar).toString();
}
qDebug() <<" string is "<<hwInfo;
}else{
qDebug() <<" item is null";
}
}else{
qDebug() <<" item is false";
}
}
return hwInfo;
}

 
//读取硬盘的逻辑序列号,注意这不是硬盘的硬序列号,并不具有唯一性。
QString logInDialog::getHDLogicalID(){
/*char cVolume[256]; //
char cFileSysName[256];
DWORD dwSerialNum; //硬盘序列号
DWORD dwFileNameLength;
DWORD dwFileSysFlag;
::GetVolumeInformation(L"C://", cVolume, 256, &dwSerialNum, &dwFileNameLength, &dwFileSysFlag, cFileSysName, 256);
*/

DWORD VolumeSerialNumber;
GetVolumeInformation(L"C:\\",NULL,0,&VolumeSerialNumber,NULL,NULL,NULL,0);
return QString::number(VolumeSerialNumber,16).toUpper();
}

 
//通过调用汇编语言获取CPU制造商信息
QString logInDialog::getCPUManID(){
//用来存储信息
DWORD deax;
DWORD debx;
DWORD decx;
DWORD dedx;
char ID[25];//存储制造商信息
memset(ID,0,sizeof(ID));//先清空数组 ID
//gcc中应该是 __asm__
__asm
{
mov eax,0
cpuid
mov deax,eax
mov debx,ebx
mov decx,ecx
mov dedx,edx
}
memcpy(ID+0,&debx,4);//制造商信息前四个字符复制到数组
memcpy(ID+4,&dedx,4);//中间四个
memcpy(ID+8,&decx,4);//最后四个
//如果返回 char * ,会出现乱码;故返回 string 值
qDebug()<<"manufacture id is "<<QString::fromLocal8Bit(ID);
return QString::fromLocal8Bit(ID);
}

 
//使用qt 原生库获取网卡地址

QString logInDialog::getMac(){
QString macAddress=tr("");
QList<QNetworkAddressEntry> lclInfAE;
QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
foreach (QNetworkInterface iface, list)
{
//保证获取的是本地IP地址,不是虚拟机,隧道 之类的网络地址
//以下这句可优化
if(!(iface.humanReadableName().contains("VMware",Qt::CaseInsensitive))&&!(iface.humanReadableName().contains("Tunnel",Qt::CaseInsensitive))&&!(iface.humanReadableName().contains("Tunneling",Qt::CaseInsensitive))&&!(iface.humanReadableName().contains("Loopback",Qt::CaseInsensitive))&&!(iface.humanReadableName().contains("Pseudo",Qt::CaseInsensitive))){
qDebug()<<"caught iface name is "<<iface.humanReadableName();
if(iface.hardwareAddress()!=tr("")){
macAddress=iface.hardwareAddress().toUpper();
qDebug()<<"hdmac is "<<macAddress;
}
}
}
// ui->textBrowser_5->append(tr("\r\n MAC is %1").arg(macAddress));
return macAddress;
}

 
//另一种获取CPU OEM的方法

 
QString logInDialog::getCPUID1(){
char OEMString[13];
QString result=tr("");
int iEAXValue,iEBXValue,iECXValue,iEDXValue;
_asm
{
mov eax,0
cpuid
mov DWORD PTR OEMString,ebx
mov DWORD PTR OEMString+4,edx
mov DWORD PTR OEMString+8,ecx
mov BYTE PTR OEMString+12,0
}
// SetDlgItemText(IDC_STATIC1,OEMString); //CPU 供应商 名称
qDebug()<<"manufacture id is "<<QString(OEMString);
_asm
{
mov eax,1
cpuid
mov iEAXValue,eax
mov iEBXValue,ebx
mov iECXValue,ecx
mov iEDXValue,edx
}
int iCPUFamily=(0xf00 & iEAXValue)>>8;
char Family[10]={0};
_itoa_s(iCPUFamily,Family,10);
// SetDlgItemText(IDC_STATIC2,Family); //CPU系列
qDebug()<<"cpu family is "<<QString(Family);
_asm
{
mov eax,2
CPUID
}
char szCPUID[129]={NULL};
char szTmp[33]={NULL};
unsigned long s1 = 0,s2=0;
_asm
{
mov eax,01h
xor edx,edx
cpuid
mov s1,edx
mov s2,eax
}
//大写16 进制,宽度占8 个位置,右对齐
sprintf_s(szTmp, "%08X%08X", s1, s2);
strcpy_s(szCPUID, szTmp);
_asm
{
mov eax,03h
xor ecx,ecx
xor edx,edx
cpuid
mov s1,edx
mov s2,ecx
}
sprintf_s(szTmp, "%08X%08X", s1, s2);
strcat_s(szCPUID, szTmp);
// SetDlgItemText(IDC_STATIC3,szCPUID); //CPUID号
qDebug()<<"cpuid2 is "<<QString(szCPUID);
// ui->textBrowser_5->append(tr("\r\n cpuid1 is %1").arg(QString(szCPUID)));
result=QString(szCPUID).toUpper();
return result;
}

 
 

QString logInDialog::getCPUID2(){
DWORD dwId1, dwId2, dwId3, dwId4;
char szCompany[13];
PCHAR pCompany = szCompany;
szCompany[12]=0;
_asm
{
pushfd
pushad
//取得CPU的ID号
mov eax,1 //功能号
_emit 0x0f
_emit 0xa2
mov dwId1,eax
mov dwId2,ebx
mov dwId3,ecx
mov dwId4,edx
//取得CPU的制造公司名称
mov edi,pCompany //功能号
mov eax,0
_emit 0x0f
_emit 0xa2
mov eax,ebx
stosd
mov eax,edx
stosd
mov eax,ecx
stosd
popad
popfd
}
DWORD dwResult = 0;
DWORD dwTemp1 = dwId1 << 12;
DWORD dwTemp2 = dwId2 << 8 ;
DWORD dwTemp3 = dwId3 << 4;
QString res=tr("splitted string is %1_%2_%3_%4").arg(QString::number(dwTemp1,16)).arg(QString::number(dwTemp2,16)).arg(QString::number(dwTemp3,16)).arg(QString::number(dwId4,16));
dwResult = dwTemp1 + dwTemp2 + dwTemp3 + dwId4;
QString result=QString::number(dwResult,16).toUpper();
qDebug()<<"the result is "<<result;
QString cpy=QString::fromLocal8Bit(szCompany);
// ui->textBrowser_5->append(res+tr("\r\n cpuid2 is :")+result.toUpper()+tr("\r\n company is :")+cpy);
return result;
}
 
 
//综合以后上几个功能,获取机器码的函数:
QString logInDialog::getMachineCode(int type){
QString machineInfo=tr("");
machineInfo.append(this->getCPUID1());
machineInfo.append(tr("@"));
machineInfo.append(this->getCPUID2());
machineInfo.append(tr("@"));
for(int i=0;i<6;i++){
machineInfo.append(this->getWMIHWInfo(i));
machineInfo.append(tr("@"));
}
machineInfo.append(this->getHDLogicalID());
machineInfo.append(tr("@"));
machineInfo.append(this->getMac());
QCryptographicHash sha1(QCryptographicHash::Sha1);
QByteArray datagram(machineInfo.toAscii());
const char* tempConstChar = datagram.data();
sha1.addData(tempConstChar);
QString machineCode=sha1.result().toHex();
if(type==1){
QClipboard *board = QApplication::clipboard();
board->setText(machineCode);
QMessageBox::information (NULL,QObject::tr("系统未激活"),QObject::tr("机器码已经复制到粘贴板上,\r\n请发给软件供应商以获取激活码"));
}
return machineCode;
}
QString logInDialog::calActiveCode(QString machineCode,int validays){
QString originalStr120=tr("@@@")+machineCode+tr("ihepJiangzhengwei@@@%1").arg(QString::number(validays));
QCryptographicHash sha1(QCryptographicHash::Sha1);
QByteArray datagram(originalStr120.toAscii());
const char* tempConstChar = datagram.data();
sha1.addData(tempConstChar);
QString activeCode=sha1.result().toHex();
QClipboard *board = QApplication::clipboard();
board->setText(activeCode);
return activeCode;
}

 
 
QString calMachineCode();
QString machineInfo=cpu+hardDisk+motherBoared+netInterfaceCard;
QCryptographicHash md5(QCryptographicHash::Md5);
md5.addData(originalStr.toLocal8Bit());
QString machineCode= md5.result().toHex();

QString calActiveCode();
QString originalStr120=  @@@machineCode+ihepJiangzhengwei@@@120
QString originalStr180=  @@@machineCode+ihepJiangzhengwei@@@180
QString originalStr360=  @@@machineCode+ihepJiangzhengwei@@@360
QString originalStr730=  @@@machineCode+ihepJiangzhengwei@@@730
        QCryptographicHash sha1(QCryptographicHash::Sha1);
        sha1.addData(originalStr.toLocal8Bit());
        QString  activeCode=sha1.result().toHex();

 
bool logInDialog::activationJudge(){

    QSettings *reg = newQSettings("HKEY_CURRENT_USER\\Software\\qCloudSecChk",QSettings::NativeFormat);
    QString activeCode=reg->value("activeCode").toString();
    QString machineCode=this->getMachineCode(0);
    QString activeCodeCal=this->calActiveCode(machineCode,120);
    qDebug()<<"activeCode is "<<activeCode;
    // QDateTime curDateTime=QDateTime::currentDateTime();
    // QString curDateTimeStr=curDateTime.toString("yyyy-MM-dd");
    //qDebug()<<"current time  is "<<curDateTimeStr;
    if(activeCode.trimmed()!=activeCodeCal){
        this->getMachineCode(1);
        QString itemText2=QInputDialog::getText(0,tr("激活系统"),tr("输入激活码:"));

        if(itemText2==activeCodeCal){
            reg->setValue("activeCode",itemText2);
            return true;
        }else{
            QMessageBox::warning(NULL,QObject::tr("错误"),QObject::tr("激活码错误!"));
            return false;
        }

    }
}

   

//读写注册表函数

 
bool logInDialog::activationJudge(){

    QSettings *reg = newQSettings("HKEY_CURRENT_USER\\Software\\qCloudSecChk",QSettings::NativeFormat);
    QString activeCode=reg->value("activeCode").toString();
    QString machineCode=this->getMachineCode(0);
    QString activeCodeCal=this->calActiveCode(machineCode,120);
    qDebug()<<"activeCode is "<<activeCode;
    // QDateTime curDateTime=QDateTime::currentDateTime();
    // QString curDateTimeStr=curDateTime.toString("yyyy-MM-dd");
    //qDebug()<<"current time  is "<<curDateTimeStr;
    if(activeCode.trimmed()!=activeCodeCal){
        this->getMachineCode(1);
        QString itemText2=QInputDialog::getText(0,tr("激活系统"),tr("输入激活码:"));

        if(itemText2==activeCodeCal){
            reg->setValue("activeCode",itemText2);
            return true;
        }else{
            QMessageBox::warning(NULL,QObject::tr("错误"),QObject::tr("激活码错误!"));
            return false;
        }

    }
}

 
 
思路:
 保存activeCode到
HKEY_CURRENT_USER\\Software\\qCloudSecChk\\activeCode中

   程序每次打开时,先读取 注册表
HKEY_CURRENT_USER\\Software\\qCloudSecChk\\activeCode

 ,如果为空,则提示需要激活,如果存在,进行下一步:

获取机器信息getMachineInfo(),计算calMachineCode,计算激活码calActiveCode与activeCode进行对比,一致说明已激活,否则提示激活。
 
有效期限制:首次激活时,validRecord到
HKEY_CURRENT_USER\\Software\\qCloudSecChk\\validRecordTime
 
    程序每次打开,确认已激活后,打开上述位置,读取第一次激活时间,与当前时间对比,根据激活码匹配情况(120,180,360,730),选择对应时间阈,提示软件是否过期,是否需要重新注册。另外,不能仅依赖于注册表,应该建立一些特殊位置的隐藏文件辅助上述的激活、有限期设置工作。
 
 
完整工程代码:
https://github.com/jiangzhw/MachineCodeCal

原创粉丝点击