CPU序列号

19

我如何获取PC中CPU的序列号?


2
你们的CPU是奔腾III吗?如果不是,您实际上是想问另一个问题吗? - Joe Hildebrand
这个页面有一个很好的答案。https://dev59.com/P3A75IYBdhLWcg3wGVCI#3474966 - Oli B
这个页面有答案。 :) - Oli B
14个回答

17

我可以在不使用任何外部库的情况下,提供与此问题有关的最终答案。只需输入以下命令:

wmic bios get serialnumber

这将为您提供PC机箱上的序列号;) (来自Microsoft知识库)

敬礼!


6
在我的i7上,它为我返回了“系统序列号”文本。你有提到的知识库文章链接吗? - 0xC0DEFACE
2
“System Serial Number”这个文本在白盒系统中很常见。它应该在PC制造商出售之前被替换掉。 - codekaizen
7
使用我的主板会返回“由O.E.M.填写”,不可靠,最好使用其他东西,如MAC地址(如果可用)。 - Paul Groke
返回戴尔电脑的标签号码。 - Pierre

6

5
在英特尔CPU中,自Pentium III之后就没有CPU序列号(PSN; CPUID edx bit 18“psn”处理器序列号),而AMD芯片中从来没有psn。 https://software.intel.com/en-us/forums/watercooler-catchall/topic/308483(2005年)指出:“但是请记住,只有Pentium III Xeon、移动版Pentium III和Pentium III处理器支持由Pentium III处理器引入的处理器序列号功能。没有其他英特尔处理器支持处理器序列号功能。”

https://en.wikipedia.org/wiki/Pentium_III#Controversy_about_privacy_issues

https://en.wikipedia.org/wiki/CPUID#EAX=3:_Processor_Serial_Number

EAX=3: 处理器序列号 参见:奔腾III § 隐私问题争议

此命令返回处理器的序列号。处理器序列号最初在英特尔奔腾III上引入,但由于隐私问题,该功能不再实现于后续型号(PSN功能标志位始终被清除)。Transmeta的Efficeon和Crusoe处理器也提供此功能。然而,AMD CPU不在任何CPU型号中实现此功能。


2
使用正确的寄存器设置执行CPUID指令将在EAX、EBX、ECX和EDX中检索处理器序列号。然而,此功能仅适用于Pentium 3及更高版本的处理器。在Pentium 4和更新版本的处理器上,该指令始终在所有4个寄存器中返回0x00000000。较新型号的Pentium 3也可能返回0x00000000。该功能主要针对副本保护,允许软件与特定处理器链接。但它并没有得到社区的认可,导致了诉讼的发生。该功能已从较新型号的P3和所有更新的处理器中删除。出于兼容性原因,该功能存在于较新的处理器中。据传可以通过特殊订单来获取具有序列号的处理器,但最小购买量约为100万个处理器。有关在执行CPUID指令之前的特定寄存器设置,请查阅英特尔系统程序员PDF,该文件可通过其网站获得。
另外 -

#include <Windows.h>
#include <stdio.h>
#include <xmmintrin.h>
#include <iphlpapi.h>
#include <Rpc.h>

static void GetMACaddress(void);
static void uuidGetMACaddress(void);

int main(){
    SYSTEM_INFO SysInfo;
    GetSystemInfo(&SysInfo);
    printf("Processors - %d\n" , SysInfo.dwNumberOfProcessors);
    DWORD a , b , c , d , e;
    DWORD BasicLeaves;
    char* VendorID = (char*)malloc(20);
    char* message = (char*)malloc(20);
    _asm {
        pusha
        pushfd
        pop eax
        push eax
        xor eax , 0x00200000
        push eax
        popfd
        pushfd
        pop ecx
        pop eax
        xor eax , ecx
        mov [a] , eax
        }
    if(a & 0x00200000){
        printf("CPUID opcode supported.\n");
        } else {
        printf("CPUID opcode not supported, exiting...\n");
        return 0;
        }

    //DWORD* pa = &a[0];
    //DWORD* pb = &a[1];
    //DWORD* pc = &a[2];
    //DWORD* pd = &a[3];
    //a[4] = 0;
    e = 0;
    __asm {
        mov eax , 0
        cpuid
        mov [BasicLeaves] , eax;
        mov [b] , ebx;
        mov [c] , ecx;
        mov [d] , edx;
        }
    memcpy(&VendorID[0] , &b , 4);
    memcpy(&VendorID[4] , &d , 4);
    memcpy(&VendorID[8] , &c , 4);
    VendorID[12] = 0;

    printf("%d Basic Leaves\nVendorID - %s\n" , BasicLeaves , VendorID);

    __asm {
        mov eax , 1
        cpuid
        mov [a] , eax;
        mov [b] , ebx;
        mov [c] , ecx;
        mov [d] , edx;
        }
    if(d & 0x00000001) printf("FPU\n");
    if(d & 0x00000200) printf("APIC On-Chip\n");
    if(d & 0x00040000) printf("Processor Serial Number Present\n");
    if(d & 0x00800000) printf("MMX\n");
    if(d & 0x01000000) printf("SSE\n");
    if(d & 0x02000000) printf("SSE2\n");
    if(d & 0x08000000) printf("Hyperthreading (HTT)\n");

    if(c & 0x00000001) printf("SSE3\n");
    if(c & 0x00000200) printf("SSSE3\n");
    if(c & 0x00080000) printf("SSE4.1\n");
    if(c & 0x00100000) printf("SSE4.2\n");
    if(c & 0x02000000) printf("AES\n");


    __asm {
        mov eax , 0x80000000
        cpuid
        and eax , 0x7fffffff;
        mov [a] , eax;
        mov [b] , ebx;
        mov [c] , ecx;
        mov [d] , edx;
        }

    printf("%d Extended Leaves\n" , a);

    printf("Processor Brand String - ");
    __asm {
        mov eax , 0x80000002
        cpuid
        mov [a] , eax;
        mov [b] , ebx;
        mov [c] , ecx;
        mov [d] , edx;
        }
    memcpy(&message[0] , &a , 4);
    memcpy(&message[4] , &b , 4);
    memcpy(&message[8] , &c , 4);
    memcpy(&message[12] , &d , 4);
    message[16] = 0;
    printf("%s" , message);

    __asm {
        mov eax , 0x80000003
        cpuid
        mov [a] , eax;
        mov [b] , ebx;
        mov [c] , ecx;
        mov [d] , edx;
        }

    memcpy(&message[0] , &a , 4);
    memcpy(&message[4] , &b , 4);
    memcpy(&message[8] , &c , 4);
    memcpy(&message[12] , &d , 4);
    message[16] = 0;
    printf("%s" , message);

    __asm {
        mov eax , 0x80000004
        cpuid
        mov [a] , eax;
        mov [b] , ebx;
        mov [c] , ecx;
        mov [d] , edx;
        popa
        }
    memcpy(&message[0] , &a , 4);
    memcpy(&message[4] , &b , 4);
    memcpy(&message[8] , &c , 4);
    memcpy(&message[12] , &d , 4);
    message[16] = 0;
    printf("%s\n" , message);

    char VolumeName[256]; DWORD VolumeSerialNumber; DWORD MaxComponentLength; DWORD FileSystemFlags; char FileSystemNameBuffer[256]; 
    GetVolumeInformationA("c:\\" , VolumeName , 256 , &VolumeSerialNumber , &MaxComponentLength , &FileSystemFlags , (LPSTR)&FileSystemNameBuffer , 256);
    printf("Serialnumber - %X\n" , VolumeSerialNumber);

    GetMACaddress();
    uuidGetMACaddress();

    return 0;
    }

// Fetches the MAC address and prints it
static void GetMACaddress(void){
    IP_ADAPTER_INFO AdapterInfo[16];        // Allocate information 
                                            // for up to 16 NICs
    DWORD dwBufLen = sizeof(AdapterInfo);   // Save memory size of buffer

    DWORD dwStatus = GetAdaptersInfo(       // Call GetAdapterInfo
    AdapterInfo,                            // [out] buffer to receive data
    &dwBufLen);                             // [in] size of receive data buffer
    //assert(dwStatus == ERROR_SUCCESS);    // Verify return value is 
                                            // valid, no buffer overflow

    PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo; // Contains pointer to
                                            // current adapter info
    do {
        printf("Adapter MAC Address - %X-%X-%X-%X-%X-%X\n" , pAdapterInfo->Address[0] , pAdapterInfo->Address[1] , pAdapterInfo->Address[2] , pAdapterInfo->Address[3] , pAdapterInfo->Address[4] , pAdapterInfo->Address[5]);
        printf("Adapter IP Address  - %s\n" , pAdapterInfo->CurrentIpAddress);
        printf("Adapter Type        - %d\n" , pAdapterInfo->Type);
        printf("Adapter Name        - %s\n" , pAdapterInfo->AdapterName);
        printf("Adapter Description - %s\n" , pAdapterInfo->Description);
        uuidGetMACaddress();

        printf("\n");
        //PrintMACaddress(pAdapterInfo->Address); // Print MAC address
        pAdapterInfo = pAdapterInfo->Next;      // Progress through 
                                                // linked list
        } while(pAdapterInfo);                  // Terminate if last adapter
    }

// Fetches the MAC address and prints it

static void uuidGetMACaddress(void)
{
  unsigned char MACData[6];

  UUID uuid;
  UuidCreateSequential( &uuid );    // Ask OS to create UUID

  for (int i=2; i<8; i++)  // Bytes 2 through 7 inclusive 
                           // are MAC address
    MACData[i - 2] = uuid.Data4[i];

  printf("UUID MAC Address - %X-%X-%X-%X-%X-%X\n" , MACData[0] , MACData[1] , MACData[2] , MACData[3] , MACData[4] , MACData[5]);
}//*/

你不需要使用 pusha。支持内联汇编语法的编译器知道你触及了哪些寄存器。而且你直到稍后的汇编块才使用 popa,所以如果你担心会影响编译器的寄存器,那么你大多数情况下只会让情况变得更糟,而不是更好。(除非 MSVC 不知道 CPUID 写入 EBX?)无论如何,在检查是否支持 CPUID 后,通常应该使用 __cpuid() 内部函数而不是内联汇编。 - Peter Cordes

2

2
即使启用了CPUID,现代处理器中是否实际上有可用的序列号?我记得在Pentium 3时代提出整个序列号问题时曾经引起了巨大的抗议。

1
英特尔 CPU 在 Pentium III 之后没有 CPU 序列号 (PSN):https://software.intel.com/en-us/forums/watercooler-catchall/topic/308483 "但请记住,只有 Pentium III Xeon、Mobile Pentium III 和 Pentium III 处理器支持由 Pentium III 处理器引入的处理器序列号功能。没有其他英特尔处理器支持处理器序列号功能:"(2005 年);https://en.wikipedia.org/wiki/Pentium_III#Controversy_about_privacy_issues - osgx

2

这是一个旧帖子。但我遇到了同样的问题,不过我使用以下逻辑成功解决了问题,而且没有太多的条件限制。

CPU序列号的问题在于它在虚拟化环境下并不总是有效。

我在一组基于Windows的服务器上实现了以下逻辑:

Win32_BIOS可以提供BIOS的序列号。需要记住的是,如果系统被虚拟化,你可能会得到所有服务器相同的BIOS序列号。

Win32_NetworkAdapter可以提供MAC地址,可以同时使用。在有多个网络适配器的情况下,你将得到多个MAC地址。

结合这两个ID,在跨越物理和虚拟的6000台服务器集合中,我得到了所有独特的集合。这很容易通过使用ManagementClassManagementObject来实现。

但是需要注意的是:当你远程获取MO实例时,对于一个延迟小于5毫秒、速率为10Gbps的光纤网络,这将需要几秒钟以上的时间。因此,如果进行多线程调用收集WMI数据,需要考虑到这是更像是低优先级的流量,我不希望疯狂地使用网络。


1

__get_cpuid (unsigned int __level, unsigned int *__eax, unsigned int *__ebx, unsigned int *__ecx, unsigned int *__edx);

  • 头文件:#include <cpuid.h>

注意:处理器序列号是在英特尔奔腾III上引入的,但由于隐私问题,此功能不再实现于后续型号。

来源:wikipedia


0

2
由于这是一个编程网站,我猜他是在询问如何以编程方式获取序列号。他使用了许可标签,这表明他将使用它来创建应用程序的序列号。 - Espo
@Bruce 即使如此,这个工具也不会返回序列号... - user2284570

0
请提供更多细节:操作系统、编程语言。
例如,在Windows上,您可以使用WMI并读取Win32_Processor.ProcessorId来获取它。

是的,ProcessorId是处理器的某种(半)唯一标识符。 - Biri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接