C++根据CPU ID硬盘序列号主板ID生成一个设备GUID

1 使用C++实现,根据硬件信息,生成一个标识该设备的唯一ID

思路:

先获取cpuid,硬盘id,主板id

拼接成字符串,做hash得到一个唯一的设备id(unsigned int)

根据业务需求,改造成 guid 格式的字符串。

2 代码实现

#include <windows.h>
#include <string>
#include <iostream>
#include <list>
#include <functional>
#include <sstream>
#include <iomanip>
#include <map>
#include "getDeviceFinger.h"

#define BUFFER_SIZE (128)
using namespace std;

#pragma comment(lib, "msvcprt.lib")

typedef unsigned int size_t_32;
typedef unsigned long long size_t_64;

// BKDR Hash Function
static unsigned int BKDRHash(char* str)
{
    unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
    unsigned int hash = 0;

    while (*str)
    {
        hash = hash * seed + (*str++);
    }

    return (hash & 0x7FFFFFFF);
}

static std::string hash32_to_guid(size_t_32 hash_value) {
    char chHex_str[BUFFER_SIZE] = { 0 };

    std::stringstream ss;
    ss << std::setfill('0') << std::setw(8) << std::hex << hash_value;
    std::string hex_str = ss.str();
    strcpy_s(chHex_str, hex_str.c_str());

    std::hash <std::string> hash_hex_str1;
    size_t_32 num1 = BKDRHash(chHex_str);
    std::stringstream ss1;
    ss1 << std::setfill('0') << std::setw(8) << std::hex << num1;
    std::string hex_str1 = ss1.str();
    memset(chHex_str, 0, sizeof(chHex_str));
    strcpy_s(chHex_str, hex_str1.c_str());

    std::hash <std::string> hash_hex_str2;
    size_t_32 num2 = BKDRHash(chHex_str);
    std::stringstream ss2;
    ss2 << std::setfill('0') << std::setw(8) << std::hex << num2;
    std::string hex_str2 = ss2.str();
    memset(chHex_str, 0, sizeof(chHex_str));
    strcpy_s(chHex_str, hex_str2.c_str());

    std::hash <std::string> hash_hex_str3;
    size_t_32 num3 = BKDRHash(chHex_str);
    std::stringstream ss3;
    ss3 << std::setfill('0') << std::setw(8) << std::hex << num3;
    std::string hex_str3 = ss3.str();
    memset(chHex_str, 0, sizeof(chHex_str));
    strcpy_s(chHex_str, hex_str3.c_str());

    // 构造GUID的格式
    std::string guid_str = "{" + hex_str.substr(0, 8) + "-" + hex_str1.substr(0, 4) + "-" +
        hex_str1.substr(4, 4) + "-" +
        hex_str2.substr(0, 4) + "-" +
        hex_str2.substr(4, 4) + hex_str3.substr(0, 8) + "}";

    return guid_str;
}

static bool getDeviceInfo(const char* cmd, std::list<std::string>& resultList)
{
    char buffer[BUFFER_SIZE] = { 0 };
    bool bRet = false;

    FILE* pipe = _popen(cmd, "r");
    if (pipe == nullptr) return bRet;

    const char* name[20] = { "UUID", "ProcessorId", "SerialNumber" };
    int len0 = strlen(name[0]), len1 = strlen(name[1]), len2 = strlen(name[2]);
    bool isOk = false;

    while (!feof(pipe))
    {
        if (fgets(buffer, BUFFER_SIZE, pipe))
        {
            if (strncmp(name[0], buffer, len0) == 0
                || strncmp(name[1], buffer, len1) == 0
                || strncmp(name[2], buffer, len2) == 0)
            {
                isOk = true;
                continue;
            }

            if (!isOk || strcmp("\r\n", buffer) == 0)
            {
                continue;
            }

            bRet = true;
            resultList.push_back(string(buffer));
        }
    }
    _pclose(pipe);
    return bRet;
}

static size_t_32 getBiosCpuDiskHashID()
{
    //AllocConsole();
    //ShowWindow(GetConsoleWindow(), SW_HIDE);

    std::list <std::string> strList;
    std::list <std::string>::iterator it;

    // std::hash 会在32和64位模式得到不同结果,显式指定使用仅32位hash值
    size_t_32 num;
    char chHex_str[BUFFER_SIZE] = { 0 };

    //主板UUID存在,使用主板UUID生成机器指纹
    if (getDeviceInfo("wmic csproduct get UUID", strList)
        && (*strList.begin()).compare("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF\r\n") != 0)
    {
        strcpy_s(chHex_str, (*strList.begin()).c_str());
        num = BKDRHash(chHex_str);
        return num;
    }

    // 主板UUID不存在,使用CPUID,BIOS序列号,硬盘序列号生成机器指纹
    std::string otherStr("");
    strList.clear();
    if (getDeviceInfo("wmic cpu get ProcessorId", strList))
    {
        otherStr.append(*strList.begin());
    }
    strList.clear();
    if (getDeviceInfo("wmic bios get SerialNumber", strList))
    {
        otherStr.append(*strList.begin());
    }
    /*strList.clear();
    if (getDeviceInfo("wmic diskdrive get SerialNumber", strList))
    {
        std::string allDiskNum("");
        for (it = strList.begin(); it != strList.end(); it++)
        {
            allDiskNum.append(*it);
        }
        otherStr.append(*strList.begin());
    }*/

    memset(chHex_str, 0, sizeof(chHex_str));
    strcpy_s(chHex_str, otherStr.c_str());
    num = BKDRHash(chHex_str);
    return num;
}

std::string getDeviceGUID()
{
    test01();
    size_t_32 num = getBiosCpuDiskHashID();
    return hash32_to_guid(num);
}

3 由于系统的 std::hash 返回值是 size_t,在 x86 和 x64 模式下得到的结果不相同。

这里使用了 BKDRHash 来 hash。

验证 BKDRHash 的碰撞概率


void test01()
{
    char chTmep[64] = "123456789abcdefghijklmnopqrstuvwxyz";
    char chTemp1[128] = { 0 };
    map<size_t_32, char*> mapNum;

    int count = 0;
    int maxNum = 1000 * 10000;

    size_t_32 num;

    for (int i = 0; i < maxNum; i++)
    {
        sprintf_s(chTemp1, "%s-%d", chTmep, i);
        num = BKDRHash(chTemp1);

        map<size_t_32, char*>::iterator it;
        it = mapNum.find(num);
        if (it != mapNum.end())
        {
            count++;
            std::cout << "生成了重复的hash值:" << it->first << ", " << it->second << std::endl;
        }
        else {
            mapNum.insert(std::make_pair(num, chTemp1));
        }
    }

    std::cout << "生成了" << count << "/" << maxNum << "个重复的hash值" << std::endl;
}

分别使用 x86 和 x64 运行,一千万个得到 0 个重复。

4 参考链接:

字符串哈希函数 - 知乎

C/C++:Windows获取电脑机器指纹_c/c++ 调用指纹仪-CSDN博客

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值