找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 354|回复: 5

[原创] win11激活时ptc_hostid.exe不可用的解决方法

[复制链接]

1

主题

6

回帖

2

威望

实习生

积分
12
发表于 2025-3-5 21:21 | 显示全部楼层 |阅读模式
用rust重写了一个,替换掉原来的ptc_hostid.exe即可。

原代码如下:
  1. // ptc_hostid.exe为2016年的,在windows11上无法获取到mac地址。故使用rust重写一个,程序体积也小了很多从2mb 变成了 200kb。
  2. // 在 Windows 平台,使用系统api获取mac地址,按照优先级(有线网卡 > 无线网卡)返回物理网卡的 MAC 地址。
  3. // 在其他平台(Linux/macOS)上使用 pnet 库获取 MAC 地址
  4. // 真实物理网卡(即使驱动未正确报告类型)能通过描述正确分类,排除了虚拟设备的mac地址,排除了蓝牙mac地址,避免重复的 MAC 地址等。
  5. // 输出格式为:PTC HOSTID = XX-XX-XX-XX-XX-XX,如果没有找到合适的 MAC 地址则输出 PTC HOSTID = Not Found。


  6. #[cfg(target_os = "windows")]
  7. use windows::Win32::NetworkManagement::IpHelper::{GetAdaptersInfo, IP_ADAPTER_INFO};
  8. #[cfg(target_os = "windows")]
  9. use windows::Win32::Foundation::ERROR_BUFFER_OVERFLOW;
  10. #[cfg(not(target_os = "windows"))]
  11. use pnet::datalink;
  12. use std::collections::HashSet;

  13. #[cfg(target_os = "windows")]
  14. fn is_virtual_interface(name: &str) -> bool {
  15.     let virtual_keywords = [
  16.         "virtual", "hyper-v", "vmware", "vpn", "miniport", "pseudo",
  17.         "tap", "tunnel", "vethernet", "virtualbox"
  18.     ];
  19.     virtual_keywords.iter().any(|k| name.to_lowercase().contains(k))
  20. }

  21. #[cfg(target_os = "linux")]
  22. fn is_virtual_interface(name: &str) -> bool {
  23.     let virtual_keywords = [
  24.         "docker", "virbr", "veth", "br-", "vmnet", "virtual", "lo"
  25.     ];
  26.     virtual_keywords.iter().any(|k| name.contains(k))
  27. }

  28. #[cfg(target_os = "macos")]
  29. fn is_virtual_interface(name: &str) -> bool {
  30.     let virtual_keywords = ["bridge", "virtual", "vmnet"];
  31.     virtual_keywords.iter().any(|k| name.contains(k))
  32. }

  33. #[cfg(target_os = "windows")]
  34. fn get_adapter_priority(adapter_type: u32, description: &str) -> Option<i32> {
  35.     let desc_lower = description.to_lowercase();
  36.    
  37.     // 明确排除蓝牙设备
  38.     if desc_lower.contains("bluetooth") {
  39.         return None;
  40.     }

  41.     // 优先级判断逻辑:类型 + 关键词组合
  42.     if adapter_type == 6 || desc_lower.contains("ethernet") {
  43.         Some(0)  // 有线网卡最高优先级
  44.     } else if adapter_type == 71 || desc_lower.contains("wireless") || desc_lower.contains("wi-fi") {
  45.         Some(1)  // 无线网卡
  46.     } else {
  47.         Some(2)  // 其他类型最后
  48.     }
  49. }

  50. #[cfg(target_os = "windows")]
  51. fn get_physical_mac() -> Option<String> {
  52.     unsafe {
  53.         let mut buffer_size = 0u32;
  54.         let mut result = GetAdaptersInfo(None, &mut buffer_size);
  55.         
  56.         if result != ERROR_BUFFER_OVERFLOW.0 {
  57.             return None;
  58.         }

  59.         let mut buffer = vec![0u8; buffer_size as usize];
  60.         let adapter_info = buffer.as_mut_ptr() as *mut IP_ADAPTER_INFO;
  61.         
  62.         result = GetAdaptersInfo(Some(adapter_info), &mut buffer_size);
  63.         if result != 0 {
  64.             return None;
  65.         }

  66.         let mut current = adapter_info;
  67.         let mut seen_macs = HashSet::new();
  68.         let mut adapters: Vec<(String, i32)> = Vec::new();  // (mac_str, priority)

  69.         while !current.is_null() {
  70.             let adapter = &*current;
  71.             let description = String::from_utf8_lossy(&adapter.Description);
  72.             
  73.             // 检查是否为物理接口
  74.             if !is_virtual_interface(&description) {
  75.                 // 获取MAC地址
  76.                 let mac_bytes = &adapter.Address[..adapter.AddressLength as usize];
  77.                
  78.                 // 检查是否为有效的物理MAC
  79.                 if !mac_bytes.iter().all(|&b| b == 0) && (mac_bytes[0] & 0x02) == 0 {
  80.                     let mac_str = mac_bytes
  81.                         .iter()
  82.                         .map(|b| format!("{:02X}", b))
  83.                         .collect::<Vec<_>>()
  84.                         .join("-");
  85.                     
  86.                     if seen_macs.insert(mac_str.clone()) {
  87.                         if let Some(priority) = get_adapter_priority(adapter.Type, &description) {
  88.                             adapters.push((mac_str, priority));
  89.                         }
  90.                     }
  91.                 }
  92.             }
  93.             
  94.             current = adapter.Next;
  95.         }

  96.         // 按优先级排序(优先级数字越小越优先)
  97.         adapters.sort_by_key(|&(_, priority)| priority);
  98.         adapters.first().map(|(mac_str, _)| mac_str.clone())
  99.     }
  100. }

  101. #[cfg(not(target_os = "windows"))]
  102. fn format_mac(mac: &datalink::MacAddr) -> String {
  103.     let bytes = [mac.0, mac.1, mac.2, mac.3, mac.4, mac.5];
  104.     bytes.iter()
  105.         .map(|b| format!("{:02X}", b))
  106.         .collect::<Vec<_>>()
  107.         .join("-")
  108. }

  109. #[cfg(not(target_os = "windows"))]
  110. fn get_physical_mac() -> Option<String> {
  111.     let interfaces = datalink::interfaces();
  112.     let mut seen_macs = HashSet::new();

  113.     for interface in interfaces {
  114.         // 过滤无 MAC 地址 或 虚拟接口 或 本地回环
  115.         if interface.mac.is_none()
  116.             || is_virtual_interface(&interface.name)
  117.             || interface.is_loopback() {
  118.             continue;
  119.         }

  120.         let mac = interface.mac.unwrap();
  121.         
  122.         // 排除全零MAC和私有MAC地址
  123.         if [mac.0, mac.1, mac.2, mac.3, mac.4, mac.5].iter().all(|&b| b == 0)
  124.             || (mac.0 & 0x02) != 0  // 检查是否为本地管理的(私有)MAC地址
  125.         {
  126.             continue;
  127.         }
  128.         
  129.         // 排除重复 MAC 地址(某些虚拟化环境会出现)
  130.         let mac_str = format_mac(&mac);
  131.         if !seen_macs.insert(mac_str.clone()) {
  132.             continue;
  133.         }

  134.         return Some(mac_str);
  135.     }

  136.     None
  137. }

  138. fn main() {
  139.     match get_physical_mac() {
  140.         Some(mac) => println!("PTC HOSTID = {}", mac),
  141.         None => println!("PTC HOSTID = Not Found"),
  142.     }
  143. }
复制代码


编译好的见附件:
ptc_hostid.zip (88.35 KB, 下载次数: 15)


评分

参与人数 1威望 +2 金钱 +10 收起 理由
野火 + 2 + 10 原创内容

查看全部评分

本帖被以下淘专辑推荐:

10

主题

857

回帖

27

威望

讲师

积分
1070
QQ
发表于 2025-3-6 08:40 | 显示全部楼层
厉害,学习一下
回复

使用道具 举报

4

主题

193

回帖

0

威望

工程师

积分
209
QQ
发表于 2025-3-6 09:25 | 显示全部楼层
学习一下
回复

使用道具 举报

12

主题

401

回帖

0

威望

工程师

积分
437
发表于 2025-3-6 11:59 | 显示全部楼层
牛掰了,自己写代码,学习学习
回复

使用道具 举报

1275

主题

4万

回帖

900

威望

管理员

积分
47455

社区建设勋章优秀斑竹勋章原创先锋勋章热心助人勋章宣传大使勋章斑竹勋章

发表于 2025-3-9 13:51 | 显示全部楼层
谢谢朋友分享!
回复

使用道具 举报

110

主题

948

回帖

4

威望

讲师

积分
1351
发表于 2025-3-9 14:46 | 显示全部楼层
厉害,分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

本站为非营利性站点,部分资源为网友搜集或发布,仅供学习和研究使用,如用于商业用途,请购买正版。站内所发布的资源,如有侵犯你的权益,请发邮件联系我们,本站将立即改正或删除。

手机版|小黑屋|野火论坛(©2007~2025) ( 苏ICP备11036728号-2 )苏公网安备 32039102000103号|站长QQ28016688

GMT+8, 2025-4-4 19:14 , Processed in 0.156481 second(s), 31 queries .

快速回复 返回顶部 返回列表