Windows 8 系列(八):Win8无法获取机器唯一标识的替代方案
当初为了使用户安全性问题得到保障,服务器端曾要求各客户端程序根据机器的唯一标识,经过MD5等算法得出一个值并传递给服务器。但是找遍了API文档和MSDN的官方论坛,也没有找到可以像Windows phone中通过DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out DeviceUniqueID) 可以直接获得到的机器唯一标识,得到的结果只有一句话:You cannot do that from a Metro app. That is by design.
可能是我们做win8开发的时间比较早吧,后来不知道什么时候,最近得知有种方法可以得到类似的这个标识:App Specific Hardware ID(ASHWID),就赶快打开博客园给大家分享出来。
App Specific Hardware ID(ASHWID),翻译成中文是: 应用特定硬件ID,对每个应用/程序包来说,得出的 ASHWID 都不同。 除非基本硬件已更改,否则相同应用的两次调用会导致 ASHWID 相同。 但是,如果设备的硬件配置文件更改(如,当用户拔出 USB Bluetooth 适配器时),则 ASHWID 会更改。 后端云服务可以验证 ASHWID 并将其与之前报告的值相比较。 虽然 ASHWID 改变,但可以分析它来检测变化是否仅由于较小更改(如,系统中内存增加)而导致。 变化容差级别由后端云服务实现来决定。随后的部分中提供了组成 ASHWID 的特定元素和如何分析这些元素的指南。
也就是说,在同一台机器上(硬件设备都没有变化),不同应用的ASHWID不同,同一应用不同版本的ASHWID相同。在不同机器上同一应用的ASHWID也不同
ASHWID 结构
ASHWID 是根据组成设备的多个硬件组件而得出的结果。ASHWID 旨在针对每个应用/程序包都刻意不同,以防止出现针对系统范围的行为并保护用户隐私。每个组件(如果出现)都对应所返回 ASHIWD 字节流的一部分。 以下列出了 9 个组件:
- 处理器的 CPU ID
- 内存大小
- 磁盘设备的序列号
- 网络适配器(NIC MAC 地址 - 第一个实例)
- 音频适配器
- 扩展坞
- Bluetooth 地址
- 移动宽带设备 ID
- BIOS
ASHWIDS 示例
不同组件 ID 的枚举顺序没有必要连续。以下流显示少量 ASHWID 示例。注意,在流中,组件 ID 的数字及其顺序会不同。
- 7,0,124,215,3,0,206,143,8,0,128,55,5,0,12,222,5,0,128,255,6,0,1,0,4,0,20,22,4,0,48,155,1,0,250,155,2,0,162,217,9,0,92,101
Samsung Intel Core i5 平板电脑上发现的移动宽带。
- 7,0,124,215,3,0,206,143,8,0,128,55,5,0,126,129,5,0,12,222,5,0,128,255,6,0,1,0,4,0,20,22,4,0,48,155,4,0,178,193,1,0,250,155,2,0,162,217,9,0,92,101
当靠接时同一设备上有三个不同音频适配器和当靠接时同一设备上有三个不同网络适配器。
- 3,0,188,97,3,0,76,128,3,0,250,138,5,0,220,130,6,0,1,0,4,0,20,164,1,0,204,49,2,0,226,37,9,0,22,72
桌面上发现三个不同磁盘。
- 3,0,24,211 ,5,0,182,46,5,0,54,49,6,0,1,0,4,0,203,9,1,0,148,99,2,0,162,255,9,0,140,234
Nvidia Tegra 3 设备。你可能会注意到流“6,0,1,0”与扩展坞对应,不论设备或外形规格如何。
HardwareIdentification.GetPackageSpecificToken 方法可为 Metro 风格应用提供一种方式来生成运行应用的设备的 ASHWID。在同一设备上调用此 API 的两个应用会返回不同的 ASHWID。 对于给定的应用/程序包,ASHWID 不受以下操作的影响:
- OS 重新安装
- 推送按钮重置
- OS SKU 升级
- 应用的版本更新
- 在同一设备上更改用户
也就是说,一般情况下,只要硬件没有变过,ASHWID是不会变的,在一定程度上可以解决无法获取到唯一标识的问题。
代码如下:
private string GetUniqueId() { var token = Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null); IBuffer buffer = token.Id; using (var dataReader = DataReader.FromBuffer(buffer)) { var bytes = new byte[buffer.Length]; dataReader.ReadBytes(bytes); return BitConverter.ToString(bytes); } }