當初為了使用戶安全性問題得到保障,服務器端曾要求各客戶端程序根據機器的唯一標識,經過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); } }
