最可靠方式是通过wmi查询win32_bios类serialnumber字段,但该值常为空、为"to be filled by o.e.m."或乱码;若失效,可退而求其次使用win32_baseboard的serialnumber或系统uuid作为更稳定的硬件标识。

Windows平台下用WMI查询BIOS序列号最可靠
直接读取硬件寄存器或访问SMBIOS表在用户态不可行,Windows上唯一稳定可用的方式是通过WMI(Windows Management Instrumentation)。Win32_BIOS类提供SerialNumber字段,但要注意:该值可能为空、被厂商设为"None"、"To Be Filled By O.E.M.",或返回乱码(尤其在虚拟机中)。
实操建议:
- 必须链接
comctl32.lib和wbemuuid.lib,初始化COM和WMI服务(调用CoInitializeEx、CoInitializeSecurity、CoCreateInstance) - 查询语句用
"SELECT SerialNumber FROM Win32_BIOS",结果需检查vtValue.vt == VT_BSTR且vtValue.bstrVal != nullptr - 返回的BSTR需用
SysFreeString释放,否则内存泄漏 - 在沙箱、WSL或某些精简版系统中,WMI服务可能被禁用,此时
CoCreateInstance会失败,需做错误分支处理
Linux下读取/sys/class/dmi/id/serial不总是有效
Linux内核自2.6起导出DMI信息到/sys/class/dmi/id/目录,serial文件理论上对应BIOS序列号。但实际行为高度依赖内核配置、固件实现和权限:
- 需要root权限才能读取该文件(普通用户通常返回
Permission denied) - 若内核未启用
CONFIG_DMIID,整个dmi/id目录不存在 - 部分OEM设备(如戴尔商用机)会填充此字段,但苹果Mac或多数ARM板卡返回空或"0"
- 读取时应检查
errno是否为EACCES或ENOENT,而非仅判断文件内容为空字符串
跨平台尝试SMBIOS解析风险极高
有人试图用libsmbios或自己解析/dev/mem(Linux)或物理内存地址(Windows),这条路基本走不通:
-
/dev/mem在现代Linux默认关闭(CONFIG_STRICT_DEVMEM=y),即使开启也需root且极易触发内核panic - Windows驱动需通过
\.PhysicalMemory访问,但自Win10 RS5起该设备被彻底移除,调用CreateFile直接返回ERROR_ACCESS_DENIED - SMBIOS结构版本(v2.4/v3.0)差异大,校验和验证逻辑复杂,一个字节错就导致解析崩溃
- UEFI固件可能隐藏或加密敏感字段,读出来也是占位符
替代方案:用主板序列号或UUID兜底
当BIOS序列号不可用时,可退而求其次获取更稳定的硬件标识:
- Windows下查
Win32_BaseBoard的SerialNumber(主板序列号),比BIOS字段更常被厂商填写 - Linux下读
/sys/class/dmi/id/product_uuid(注意全大写、带短横线),该值由固件生成,重启不变,但虚拟机中可能重复 - 避免用MAC地址——网卡可更换,且多网卡时不确定选哪个
- 任何硬件ID都需加哈希(如SHA-256)再使用,防止暴露原始信息
BIOS序列号不是可靠标识符,它既不保证唯一性,也不保证可读性。真正要绑定设备时,得组合多个字段并做好降级处理。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











