Honey Cake Asked:2020-08-19 05:09:14 +0000 UTC2020-08-19 05:09:14 +0000 UTC 2020-08-19 05:09:14 +0000 UTC 如何使用 C++ 获取处理器(CPU)的唯一标识符? 772 对使用 c ++ 获取处理器 ID 的方法感兴趣。 c++ 2 个回答 Voted Best Answer MSDN.WhiteKnight 2020-08-21T01:57:01Z2020-08-21T01:57:01Z 并非每个处理器都在 CPUID 中返回唯一的序列号。为了唯一标识一台计算机,使用由多个值组成的复合硬件标识符是有意义的,例如: CPUID SMBIOS 系统 UUID 系统单元的序列号 主板序列号 所有这些值都可以通过编程方式从SMBIOS 表中检索。当然,也可以添加网络接口的 MAC 地址,但请记住,一台计算机可以有多个网络接口,不能只取第一个,它可以是虚拟的。 Windows 示例(读取 SMBIOS 表的代码取自sysinv项目): #include <stdio.h> #include <Windows.h> #include <tchar.h> // SMBIOS Table Type numbers #define SMB_TABLE_BIOS 0 #define SMB_TABLE_SYSTEM 1 #define SMB_TABLE_BASEBOARD 2 #define SMB_TABLE_CHASSIS 3 #define SMB_TABLE_PROCESSOR 4 #define SMB_TABLE_MEMCTRL 5 #define SMB_TABLE_MEMMODULES 6 #define SMB_TABLE_PORTS 8 #define SMB_TABLE_SLOTS 9 #define SMB_TABLE_OEM_STRINGS 11 #define SMB_TABLE_SYS_CFG_OPTIONS 12 #define SMB_TABLE_MEM_ARRAY 16 #define SMB_TABLE_MEM_DEVICE 17 #define SMB_TABLE_END_OF_TABLE 127 // 64bit Word type typedef unsigned long long QWORD; /* * Structures */ typedef struct _RawSmbiosData { BYTE Used20CallingMethod; BYTE SMBIOSMajorVersion; BYTE SMBIOSMinorVersion; BYTE DmiRevision; DWORD Length; BYTE SMBIOSTableData[1]; } RAW_SMBIOS_DATA, * PRAW_SMBIOS_DATA; typedef struct _SmbiosStructHeader { BYTE Type; BYTE Length; WORD Handle; } SMBIOS_STRUCT_HEADER, *PSMBIOS_STRUCT_HEADER; // Structures typedef struct _NODE { wchar_t *Name; // Name of the node struct _NODE_ATT_LINK *Attributes; // Array of attributes linked to the node struct _NODE *Parent; // Parent node struct _NODE_LINK *Children; // Array of linked child nodes int Flags; // Node configuration flags } NODE, * PNODE; typedef struct _NODE_LINK { struct _NODE *LinkedNode; // Node attached to this node } NODE_LINK, * PNODE_LINK; typedef struct _NODE_ATT { wchar_t *Key; // Attribute name wchar_t *Value; // Attribute value string (may be null separated multistring if NAFLG_ARRAY is set) int Flags; // Attribute configuration flags } NODE_ATT, *PNODE_ATT; typedef struct _NODE_ATT_LINK { struct _NODE_ATT *LinkedAttribute; // Attribute linked to this node } NODE_ATT_LINK, *PNODE_ATT_LINK; /********************************************************************/ PRAW_SMBIOS_DATA GetSmbiosData() { DWORD bufferSize = 0; PRAW_SMBIOS_DATA smbios = NULL; // Get required buffer size bufferSize = GetSystemFirmwareTable('RSMB', 0, NULL, 0); if (bufferSize) { smbios = (PRAW_SMBIOS_DATA)LocalAlloc(LPTR, bufferSize); bufferSize = GetSystemFirmwareTable('RSMB', 0, (PVOID)smbios, bufferSize); } return smbios; } PSMBIOS_STRUCT_HEADER GetNextStructure(PRAW_SMBIOS_DATA smbios,PSMBIOS_STRUCT_HEADER previous) { PSMBIOS_STRUCT_HEADER next = NULL; PBYTE c = NULL; // Return NULL is no data found if (NULL == smbios) return NULL; // Return first table if previous was NULL if (NULL == previous) return (PSMBIOS_STRUCT_HEADER)(&smbios->SMBIOSTableData[0]); // Move to the end of the formatted structure c = ((PBYTE)previous) + previous->Length; // Search for the end of the unformatted structure (\0\0) while (true) { if ('\0' == *c && '\0' == *(c + 1)) { /* Make sure next table is not beyond end of SMBIOS data * (Thankyou Microsoft for ommitting the structure count * in GetSystemFirmwareTable */ if ((c + 2) < ((PBYTE)smbios->SMBIOSTableData + smbios->Length)) return (PSMBIOS_STRUCT_HEADER)(c + 2); else return NULL; // We reached the end } c++; } return NULL; } PSMBIOS_STRUCT_HEADER GetNextStructureOfType(PRAW_SMBIOS_DATA smbios,PSMBIOS_STRUCT_HEADER previous, DWORD type) { PSMBIOS_STRUCT_HEADER next = previous; while (NULL != (next = GetNextStructure(smbios,next))) { if (type == next->Type) return next; } return NULL; } PSMBIOS_STRUCT_HEADER GetStructureByHandle(PRAW_SMBIOS_DATA smbios,WORD handle) { PSMBIOS_STRUCT_HEADER header = NULL; while (NULL != (header = GetNextStructure(smbios,header))) if (handle == header->Handle) return header; return NULL; } void GetSmbiosString(PSMBIOS_STRUCT_HEADER table, BYTE index, LPWSTR output, int cchOutput) { DWORD i = 0; DWORD len = 0; wcscpy(output,L""); if (0 == index) return; char *c = NULL; for (i = 1, c = (char *)table + table->Length; '\0' != *c; c += strlen(c) + 1, i++) { if (i == index) { len = MultiByteToWideChar(CP_UTF8, 0, c, -1, output,cchOutput); break; } } } //вывод значения числового параметра таблицы SMBIOS по указанному смещению void PrintBiosValue(PRAW_SMBIOS_DATA smbios,DWORD type,DWORD offset, DWORD size) { PSMBIOS_STRUCT_HEADER head=NULL; PBYTE cursor = NULL; head = GetNextStructureOfType(smbios,head, type); if (NULL == head){ printf("PrintBiosValue Error!\n");return;} cursor=((PBYTE)head+offset); //value for(int i=0;i<size;i++) { printf("%02x",(unsigned int) *cursor); cursor++; } printf("\n"); } //вывод значения строкового параметра таблицы SMBIOS по указанному смещению void PrintBiosString(PRAW_SMBIOS_DATA smbios,DWORD type,DWORD offset) { PSMBIOS_STRUCT_HEADER head; head=NULL; PBYTE cursor = NULL; WCHAR buf[1024]; head = GetNextStructureOfType(smbios,head, type); if (NULL == head){printf("PrintString Error!\n");return;} cursor=((PBYTE)head+offset); BYTE val=*cursor; GetSmbiosString((head), *cursor,buf,1024); // value wprintf(L"%s\n",buf); } int main(){ PRAW_SMBIOS_DATA data = GetSmbiosData(); if(data==NULL){ printf("Can't get SMBIOS data!"); return 1; } printf("System UUID: "); PrintBiosValue(data,SMB_TABLE_SYSTEM,8, 16); printf("Chassis serial: "); PrintBiosString(data,SMB_TABLE_CHASSIS,7); printf("Motherboard serial: "); PrintBiosString(data,SMB_TABLE_BASEBOARD,7); printf("CPUID: "); PrintBiosValue(data,SMB_TABLE_PROCESSOR,8, 8); //Таблица SMBIOS содержит только 2 DWORD-значения CPUID из 4, но этого обычно достаточно getchar(); } AlexGlebe 2020-08-19T16:32:56Z2020-08-19T16:32:56Z 尝试使用cpuid命令。完整说明: https://c9x.me/x86/html/file_module_x86_id_45.html 也许有你正在寻找的东西。例子 : # include <cstdint> # include <cstdio> struct CPUIDinfo { uint32_t EAX; uint32_t EBX; uint32_t ECX; uint32_t EDX; }; static inline void CpuId(unsigned int func, unsigned int subfunc, CPUIDinfo& info) { __asm__ __volatile__ ( "cpuid" : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) : "a"(func), "c"(subfunc) ); } int main(){ for(int i=0;i<6;++i){ CPUIDinfo info; CpuId(i,0,info); printf("%d,0:%d,%d,%d,%d\n",i,info.EAX,info.EBX,info.ECX,info.EDX);} } 4.2. 形成 96 位处理器序列号 96 位处理器序列号是三个 32 位实体的串联。要访问处理器序列号的最高 32 位,程序应将 EAX 寄存器参数值设置为“1”,然后执行 CPUID 指令,如下所示: MOV EAX, 01H CPUID 执行 CPUID 指令后,EAX 寄存器包含处理器签名。处理器签名包括处理器序列号的最高有效 32 位。在收集处理器序列号的剩余 64 位之前,应保存 EAX 中的值。要访问处理器序列号的剩余 64 位,程序应将 EAX 寄存器参数值设置为“3”,然后执行 CPUID 指令,如下所示:MOV EAX, 03H CPUID CPUID 指令执行后,EDX 寄存器包含处理器序列号的中间 32 位,ECX 寄存器包含处理器序列号的低 32 位。然后,软件可以在返回完整的 96 位处理器序列号之前连接保存的处理器签名、EDX 和 ECX。处理器序列号应显示为 6 组 4 个十六进制半字节(例如 XXXX-XXXX-XXXX-XXXXXXXX-XXXX,其中 X 代表十六进制数字)。字母十六进制字符应显示为大写字母。处理器序列号应显示为 6 组 4 个十六进制半字节(例如 XXXX-XXXX-XXXX-XXXXXXXX-XXXX,其中 X 代表十六进制数字)。字母十六进制字符应显示为大写字母。处理器序列号应显示为 6 组 4 个十六进制半字节(例如 XXXX-XXXX-XXXX-XXXXXXXX-XXXX,其中 X 代表十六进制数字)。字母十六进制字符应显示为大写字母。 从隐私来看,请求EAX=0x03总是返回零。使用所有其他可用信息。有时人们使用虚拟计算机。因此,身份请求对您来说效果不佳。
并非每个处理器都在 CPUID 中返回唯一的序列号。为了唯一标识一台计算机,使用由多个值组成的复合硬件标识符是有意义的,例如:
所有这些值都可以通过编程方式从SMBIOS 表中检索。当然,也可以添加网络接口的 MAC 地址,但请记住,一台计算机可以有多个网络接口,不能只取第一个,它可以是虚拟的。
Windows 示例(读取 SMBIOS 表的代码取自sysinv项目):
尝试使用cpuid命令。完整说明:
https://c9x.me/x86/html/file_module_x86_id_45.html
也许有你正在寻找的东西。例子 :
从隐私来看,请求
EAX=0x03总是返回零。使用所有其他可用信息。有时人们使用虚拟计算机。因此,身份请求对您来说效果不佳。