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

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 "<
    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 "<
    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

你可能感兴趣的:(Qt技术)