飞道的博客

Windows/Linux获取Mac地址和CPU序列号实现

481人阅读  评论(0)

UUID(Universally Unique Identifier)即通用唯一标识符,是指在一台机器上生成的数字,保证在全球范围的唯一性。可用的开源库如libuuid,可参考https://blog.csdn.net/fengbingchun/article/details/94590406

UDID(Unique Device Identifier)即设备唯一标识符。一般可通过获取设备的MAC地址+设备的CPU序列号作为设备的唯一标识符。

MAC地址(Media Access Control Address),直译为媒体访问控制地址,也称为局域网地址(LAN Address),以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网络设备位置的地址。在OSI模型中,第三层网络层负责IP地址,第二层数据链路层则负责MAC地址。MAC地址用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的MAC地址。

MAC地址共48位(6个字节),以十六进制表示。第1Bit为广播地址(0)/群播地址(1),第2Bit为广域地址(0)/区域地址(1)。前3~24位由IEEE决定如何分配给每一家制造商,且不重复,后24位由实际生产该网络设备的厂商自行指定且不重复。

通过命令查看MAC地址

(1). Windows:打开命令提示符(cmd.exe),运行ipconfig/all命令,执行结果如下所示:如果计算机上有多个网络设备(无论物理或虚拟),则会有多组信息及MAC地址,需辨识相应的设备。

(2). Linux:第一种方法运行ifconfig命令;第二种方法运行ip link show命令,执行结果如下所示:eth0为第一块物理网卡,HWaddr 2c:fd:a1:bc:1f:44就是MAC地址,lo为本地回环地址。

修改MAC地址:网卡MAC地址可以通过Windows设备管理员或其他工具修改。对于某些手机、平板电脑设备来说,其MAC地址/产品序号均由厂方连同销售或保修时的客户资料一并记录在案,而有关的MAC地址也不可通过常规手段来修改。

注:以上MAC地址内容主要来自 维基百科

CPU都有一个唯一的ID号,称CPUID,即CPU序列号,是在制造CPU的时候,由厂家置入到CPU内部的。但是近年的Intel CPU不再区分同一批次中各个CPU的序列号,这样就有可能两台电脑获得的CPU序列号是一样的。

通过命令查看CPU序列号

(1). Windows:打开命令提示符,运行wmic cpu get processorid命令,执行结果如下图所示:

(2). Linux:第一种方法运行dmidecode -t 4 | grep ID命令;第二种方法运行cpuid -r命令,执行结果如下图所示:

以下是代码段通过C++获取Mac地址和CPU序列号的实现:


  
  1. namespace {
  2. #ifdef __linux__
  3. // reference: https://stackoverflow.com/questions/6491566/getting-the-machine-serial-number-and-cpu-id-using-c-c-in-linux
  4. inline void native_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
  5. {
  6. // ecx is often an input as well as an output
  7. asm volatile("cpuid"
  8. : "=a" (*eax),
  9. "=b" (*ebx),
  10. "=c" (*ecx),
  11. "=d" (*edx)
  12. : "0" (*eax), "2" (*ecx));
  13. }
  14. #endif
  15. } // namespace
  16. int get_mac_and_cpuid()
  17. {
  18. // get mac
  19. #ifdef _MSC_VER
  20. // reference: https://stackoverflow.com/questions/13646621/how-to-get-mac-address-in-windows-with-c
  21. PIP_ADAPTER_INFO AdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO));
  22. if (AdapterInfo == nullptr) {
  23. fprintf( stderr, "fail to malloc\n");
  24. return -1;
  25. }
  26. DWORD dwBufLen = sizeof(IP_ADAPTER_INFO);
  27. std::unique_ptr<char[]> mac_addr(new char[18]);
  28. // Make an initial call to GetAdaptersInfo to get the necessary size into the dwBufLen variable
  29. if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_BUFFER_OVERFLOW) {
  30. free(AdapterInfo);
  31. AdapterInfo = (IP_ADAPTER_INFO *) malloc(dwBufLen);
  32. if (AdapterInfo == nullptr) {
  33. fprintf( stderr, "fail to malloc\n");
  34. return -1;
  35. }
  36. }
  37. if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == NO_ERROR) {
  38. for (PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo; pAdapterInfo != nullptr; pAdapterInfo = pAdapterInfo->Next) {
  39. // technically should look at pAdapterInfo->AddressLength and not assume it is 6.
  40. if (pAdapterInfo->AddressLength != 6) continue;
  41. if (pAdapterInfo->Type != MIB_IF_TYPE_ETHERNET) continue;
  42. sprintf(mac_addr.get(), "%02X:%02X:%02X:%02X:%02X:%02X",
  43. pAdapterInfo->Address[ 0], pAdapterInfo->Address[ 1],
  44. pAdapterInfo->Address[ 2], pAdapterInfo->Address[ 3],
  45. pAdapterInfo->Address[ 4], pAdapterInfo->Address[ 5]);
  46. fprintf( stdout, "mac address: %s\n", mac_addr.get());
  47. break;
  48. }
  49. }
  50. free(AdapterInfo);
  51. #else
  52. // reference: https://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program/35242525
  53. int sock = socket(AF_INET, SOCK_DGRAM, 0);
  54. if (sock < 0) {
  55. fprintf( stderr, "fail to socket: %d\n", sock);
  56. return -1;
  57. };
  58. struct ifconf ifc;
  59. char buf[ 1024];
  60. int success = 0;
  61. ifc.ifc_len = sizeof(buf);
  62. ifc.ifc_buf = buf;
  63. if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
  64. fprintf( stderr, "fail to ioctl: SIOCGIFCONF\n");
  65. return -1;
  66. }
  67. struct ifreq* it = ifc.ifc_req;
  68. const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
  69. struct ifreq ifr;
  70. for (; it != end; ++it) {
  71. strcpy(ifr.ifr_name, it->ifr_name);
  72. if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
  73. if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
  74. if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
  75. success = 1;
  76. break;
  77. }
  78. }
  79. } else {
  80. fprintf( stderr, "fail to ioctl: SIOCGIFFLAGS\n");
  81. return -1;
  82. }
  83. }
  84. unsigned char mac_address[ 6];
  85. if (success) memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
  86. fprintf( stdout, "mac address: %02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[ 0], mac_address[ 1], mac_address[ 2], mac_address[ 3], mac_address[ 4], mac_address[ 5]);
  87. #endif
  88. // Capture vendor string
  89. char vendor[ 0x20];
  90. memset(vendor, 0, sizeof(vendor));
  91. // get cpid
  92. #ifdef _MSC_VER
  93. // reference: https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=vs-2019
  94. std:: array< int, 4> cpui;
  95. // Calling __cpuid with 0x0 as the function_id argument gets the number of the highest valid function ID
  96. __cpuid(cpui.data(), 0);
  97. int nIds_ = cpui[ 0];
  98. std:: vector< std:: array< int, 4>> data_;
  99. for ( int i = 0; i <= nIds_; ++i) {
  100. __cpuidex(cpui.data(), i, 0);
  101. data_.push_back(cpui);
  102. fprintf( stdout, "%08X-%08X-%08X-%08X\n", cpui[ 0], cpui[ 1], cpui[ 2], cpui[ 3]);
  103. }
  104. * reinterpret_cast< int*>(vendor) = data_[ 0][ 1];
  105. * reinterpret_cast< int*>(vendor + 4) = data_[ 0][ 3];
  106. * reinterpret_cast< int*>(vendor + 8) = data_[ 0][ 2];
  107. fprintf( stdout, "vendor: %s\n", vendor); // GenuineIntel or AuthenticAMD or other
  108. fprintf( stdout, "vendor serialnumber: %08X%08X\n", data_[ 1][ 3], data_[ 1][ 0]);
  109. #else
  110. unsigned eax, ebx, ecx, edx;
  111. eax = 0; // processor info and feature bits
  112. native_cpuid(&eax, &ebx, &ecx, &edx);
  113. fprintf( stdout, "%d, %d, %d, %d\n", eax, ebx, ecx, edx);
  114. * reinterpret_cast< int*>(vendor) = ebx;
  115. * reinterpret_cast< int*>(vendor + 4) = edx;
  116. * reinterpret_cast< int*>(vendor + 8) = ecx;
  117. fprintf( stdout, "vendor: %s\n", vendor); // GenuineIntel or AuthenticAMD or other
  118. eax = 1; // processor serial number
  119. native_cpuid(&eax, &ebx, &ecx, &edx);
  120. // see the CPUID Wikipedia article on which models return the serial number in which registers
  121. printf( "vendor serialnumber: %08X%08X\n", edx, eax);
  122. #endif
  123. return 0;
  124. }

Windows下执行结果如下所示:与命令行执行结果相同

Linux上执行结果如下图所示:与命令行执行结果相同

GitHubhttps://github.com//fengbingchun/Messy_Test


转载:https://blog.csdn.net/fengbingchun/article/details/108874436
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场