最近項目要用到加密授權,考慮了一下打算採用CPUID加密,上網找了資料整合如下,代碼適合windows環境下32位和64位的 均可。
首先說下 cmd 下查看 CPUID 命令:
wmic cpu get ProcessorId
在32位模式下,我們可以使用內嵌彙編來調用cpuid指令。但在64位模式下,VC編譯器不支持內嵌彙編。
於是微軟提供了Intrinsics函數——編譯器會將Intrinsics函數編譯爲對應的機器指令,而且同時支持32位和64位。
例如CPUID指令的對應Intrinsics函數是——
void __cpuid(
int CPUInfo[4],
int InfoType
);
void __cpuidex(
int CPUInfo[4],
int InfoType,
int ECXValue
);
__cpuidex函數的InfoType參數是CPUID指令的eax參數,即功能ID。ECXValue參數是CPUID指令的ecx參數,即子功能ID。CPUInfo參數用於接收輸出的eax, ebx, ecx, edx這四個寄存器。
早期的CPUID功能只需要一個功能ID參數(eax),這時可以使用__cpuid函數。
後來CPUID的功能越來越強大,一個功能ID參數(eax)參數不夠用,於是加了一個子功能ID(ecx)參數,這時應該採用__cpuidex。
在__cpuid、__cpuidex等Intrinsics函數時,會遇到以下問題——
1.低版本的VC編譯器沒有intrin.h頭文件。【注】:只有VC2005(或更高)才擁有intrin.h,支持__cpuid。
2.低版本的VC編譯器不支持__cpuidex。【注】:只有VC2008的部分版本及VS2010(或更高)的intrin.h中才有__cpuidex
上代碼: vs x86 x64 下均可運行
#include "pch.h"
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <iostream>
#include <intrin.h> // 所有Intrinsics函數
using namespace std;
char szBuf[64];
// 取得CPU廠商(Vendor)
//
// result: 成功時返回字符串的長度(一般爲12)。失敗時返回0。
// pvendor: 接收廠商信息的字符串緩衝區。至少爲13字節。
int cpu_getvendor(char* pvendor)
{
INT32 dwBuf[4];
if (NULL == pvendor) return 0;
// Function 0: Vendor-ID and Largest Standard Function
__cpuid(dwBuf, 0);
// save. 保存到pvendor
*(INT32*)&pvendor[0] = dwBuf[1]; // ebx: 前四個字符
*(INT32*)&pvendor[4] = dwBuf[3]; // edx: 中間四個字符
*(INT32*)&pvendor[8] = dwBuf[2]; // ecx: 最後四個字符
pvendor[12] = '\0';
return 12;
}
// 取得CPU商標(Brand)
//
// result: 成功時返回字符串的長度(一般爲48)。失敗時返回0。
// pbrand: 接收商標信息的字符串緩衝區。至少爲49字節。
int cpu_getbrand(char* pbrand)
{
INT32 dwBuf[4];
if (NULL == pbrand) return 0;
// Function 0x80000000: Largest Extended Function Number
__cpuid(dwBuf, 0x80000000);
if (dwBuf[0] < 0x80000004) return 0;
// Function 80000002h,80000003h,80000004h: Processor Brand String
__cpuid((INT32*)&pbrand[0], 0x80000002); // 前16個字符
__cpuid((INT32*)&pbrand[16], 0x80000003); // 中間16個字符
__cpuid((INT32*)&pbrand[32], 0x80000004); // 最後16個字符
pbrand[48] = '\0';
return 48;
}
string GetCPUID() {
INT32 dwBuf[4];
std::string strCPUId;
char buf[32] = { 0 };
__cpuidex(dwBuf, 1, 1);
//printf("%08X%08X\n", dwBuf[3], dwBuf[0]);
memset(buf, 0, 32);
sprintf_s(buf, 32, "%08X", dwBuf[3]);
strCPUId += buf;
memset(buf, 0, 32);
sprintf_s(buf, 32, "%08X", dwBuf[0]);
strCPUId += buf;
return strCPUId;
}
int main(int argc, _TCHAR* argv[])
{
cpu_getvendor(szBuf);
printf("CPU Vendor:\t%s\n", szBuf);
cpu_getbrand(szBuf);
printf("CPU Name:\t%s\n", szBuf);
cout << "CPU ID: " << GetCPUID() <<endl;
return 0;
}
X86下不適用Intrinsics函數 獲得CPUID
#include "pch.h"
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
string GetCPUIDwin32()
{
std::string strCPUId;
unsigned long s1, s2;
char buf[32] = { 0 };
__asm {
mov eax, 01h //eax=1:取CPU序列號
xor edx, edx
cpuid
mov s1, edx
mov s2, eax
}
if (s1) {
memset(buf, 0, 32);
sprintf_s(buf, 32, "%08X", s1);
strCPUId += buf;
}
if (s2) {
memset(buf, 0, 32);
sprintf_s(buf, 32, "%08X", s2);
strCPUId += buf;
}
__asm {
mov eax, 03h
xor ecx, ecx
xor edx, edx
cpuid
mov s1, edx
mov s2, ecx
}
if (s1) {
memset(buf, 0, 32);
sprintf_s(buf, 32, "%08X", s1);
strCPUId += buf;
}
if (s2) {
memset(buf, 0, 32);
sprintf_s(buf, 32, "%08X", s2);
strCPUId += buf;
}
return strCPUId;
}
int main()
{
cout << "CPUID:" << GetCPUIDwin32() << endl;
getchar();
return 0;
}