一、GDID 是什么:从一份联邦起诉书说起
在美国联邦刑事起诉书 United States v. Peter Stokes 中,出现了如下标识符:
Global Device Identifier g:6755467234350028
这个以 g: 为前缀、后接十进制整数的字符串,就是 GDID(Global Device Identifier)。微软代表在相关法律程序中将其描述为:
一种持久性的、设备级标识符,设计用于唯一标识设备上的 Windows 安装,跨微软服务和场景使用。
两个关键特征值得注意:
- 持久性:GDID 在 Windows 更新(包括大版本功能更新)中保持一致;
- 设备级:它标识的是"一次 Windows 安装"而非"一台物理机器"——这一点在后面的重装行为分析中至关重要。
起诉书涉及的 Scattered Spider 攻击团伙案件中,FBI 正是通过 GDID 关联了 IP 历史与浏览记录,完成了跨服务的身份归因。这说明 GDID 绝非一个普通的本地标识符,而是一个贯穿微软云端身份图谱的全局追踪锚点。
二、破除社交媒体谣言:GDID 的逆向真相
在逆向工程成果公开之前,社交媒体上流传着若干关于 GDID 的"阴谋论"式解读。逆向工程(smtimesiwndr/gdid-reversal)逐一证伪了这些说法。
谣言一:GDID 是 128 位的,从硬件序列号生成
实际:GDID 是 64 位整数。逆向中捕获到的真实样本为 0x0018000FC8CB93CC,对应的十进制即 6755467234350028(与起诉书中的 g:6755467234350028 完全吻合)。
更重要的是,这个值并非由客户端根据硬件序列号计算得出,而是由服务器分配的。
谣言二:GDID 从 GPU/CPU 序列号派生(硬件哈希)
实际:这是最容易被事实击破的谣言。逆向工程与实测一致表明:Windows 重装后会产生一个全新的 GDID。
如果 GDID 是硬件序列号的哈希,那么只要硬件不变,重装后的 GDID 就应当保持不变。但事实恰恰相反——重装即刷新。这从逻辑上排除了"硬件哈希"假说,把 GDID 的来源指向了"安装实例级的服务器分配标识符"。
谣言与真相对比
| 谣言 | 实际(逆向验证) |
|---|---|
| 128 位 | 64 位(0x0018000FC8CB93CC) |
| 从硬件序列号本地生成 | 服务器分配,客户端存储 |
| GPU/CPU 序列号哈希 | 重装产生新值,非硬件派生 |
| 客户端计算 | 客户端只 provision + 消费 |
三、GDID 的真实身份:Microsoft Account Device PUID
逆向工程给出的最终结论是:
GDID = Microsoft Account 的 "Device PUID"(Passport Unique ID)。
Device PUID 详解
PUID(Passport Unique ID)是微软身份体系(Passport / Windows Live ID / Microsoft Account)中的 64 位标识符。当一台 Windows 安装注册到某个 Microsoft Account 时,服务器会为"这台安装"分配一个 Device PUID。
在设备图谱(Device Graph)中,它的呈现格式正是:
g:<十进制整数>
例如 g:6755467234350028。
命名空间前缀:0018 vs 0003
Device PUID 的高位字节带有命名空间语义。在注册表中存储时,PUID 以十六进制字符串形式出现,前缀决定了 PUID 的类型:
0018前缀:Device PUID(设备 PUID,即 GDID 的本质)0003前缀:User PUID(用户 PUID)
逆向样本 0x0018000FC8CB93CC 的前两个字节正是 0018,这与其"设备级标识符"的身份完全一致。这个前缀不仅是一个命名约定,它在 DDS 设备图谱的节点类型路由中起到关键作用——图谱通过前缀区分用户节点与设备节点。
四、完整技术栈架构:自底向上
GDID 并非孤立存在,而是嵌入在一套完整的微软身份与设备图谱技术栈中。下面自底向上拆解整个调用链。
4.1 技术栈架构图
4.2 各层职责
身份提供层 —— wlidsvc.dll
wlidsvc.dll(Microsoft Account Sign-in Assistant 服务,服务名 wlidsvc)是整个 PUID 体系的源头。它通过 login.live.com 的 Passport PPCRL(Passport Client Runtime Credential Library)SOAP 协议完成设备 provisioning。
密钥层 —— 设备认证密钥
注意一个关键区分:BCryptGenRandom 生成的是设备认证密钥(Device Authentication Key),用于证明"这台设备"的持有者身份,它不是 PUID 本身。PUID 是服务器分配的标识符,而认证密钥是客户端持有的密码学凭证。BindDeviceToHardware 将认证密钥与硬件绑定,提供设备完整性证明,但这仍然是认证机制,不是标识符生成机制。
存储层 —— 注册表明文存储
Device PUID 被存储在用户注册表配置单元中(详见第五节)。
消费层 —— cdp.dll / CDPSvc
Connected Devices Platform 服务(CDPSvc)及其核心 DLL cdp.dll 是 GDID 的主要消费者。CDP 不计算 GDID,只消费它——这是逆向工程最重要的结论之一。
云端层 —— DDS 与 Delivery Optimization
CDP 通过 RegisterUserDeviceAsync 将设备注册到 DDS(Device Directory Service)。同时,Delivery Optimization 也会上报 GDID,字段名为 UCDOStatus.GlobalDeviceId。
五、注册表存储分析
5.1 存储路径与值
Device PUID 存储在当前用户的注册表配置单元(HKCU)中,路径为:
HKCU\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties
键值名称:LID
值类型:字符串(REG_SZ)
值内容:十六进制形式的 PUID,例如:
0018000FC8CB93CC
5.2 明文存储的含义
这里有几个值得强调的技术事实:
-
明文存储:PUID 以纯文本十六进制字符串形式存放,未加密、未混淆。任何具有该用户 hive 读取权限的进程(包括低权限进程)都可以直接读取。
-
用户级而非机器级:存储在
HKCU而非HKLM,意味着它是"每用户"的。如果同一台机器上有多个 MSA 账户登录,每个用户的 hive 中会有各自 provisioning 产生的 LID。 -
前缀可读:
0018前缀直接暴露在值中,无需解码即可判断这是设备 PUID。 -
无访问保护:该注册表项没有设置特殊的 ACL,标准的
RegOpenKeyEx+RegQueryValueEx即可读取。
这种"明文 + 用户级 + 无保护"的存储设计,使得 GDID 的本地暴露面非常大——任何已在本机执行的代码(无论恶意软件还是普通应用)都能获取它,并随后用作跨服务追踪的关联键。
六、MSA Device PUID Provisioning 流程时序图
下面是设备首次注册到 MSA 时,Device PUID 从分配到落地存储、再到 DDS 注册的完整时序。
6.1 关键 SOAP 响应解析
服务器返回的 SOAP 响应中,Device PUID 通过以下 XPath 路径定位:
/S:Envelope/S:Body/ps:DeviceUpdatePropertiesResponse/HWPUIDFlipped
其中 ps: 命名空间对应 Passport 的 schema,HWPUIDFlipped 节点指示硬件绑定 PUID 是否发生了翻转(重新绑定)。Device PUID 本身出现在 <ps:DevicePUID> 元素中。
6.2 为什么重装会产生新 GDID
这个时序图完美解释了第二节中的现象。Device PUID 的分配发生在 provisioning 阶段——即客户端向服务器请求注册一个新设备实例时。Windows 重装等同于一次全新的 provisioning:
- 旧安装的认证密钥随系统清除而丢失;
- 新安装向
login.live.com发起新的 provision 请求; - 服务器为新安装分配一个全新的 64 位 PUID。
由于 PUID 是服务器侧分配的状态,而非本地硬件派生的值,因此"重装即刷新"是设计使然,而非异常。这也进一步证伪了"硬件哈希"假说。
七、CDP 获取 GDID 的调用链分析
逆向工程的核心贡献之一,是完整还原了 CDP(Connected Devices Platform)获取 GDID 的内部调用链。结论是:CDP 不计算 GDID,只消费它。
7.1 调用链
GetStableDeviceIdFromProvider() // cdp.dll 入口
└─> provider.GetStableDeviceIdAsync() // 异步获取
└─> OneCoreAccountProvider // OneCore 账户提供者实现
└─> IWebAccountBackedAccountProvider // MSA/AAD 身份 COM 接口
└─> [读取注册表 LID / MSA 缓存]
└─> OnGetStableDeviceIdCompleted(deviceId: string) // 回调
└─> assign() // 存储到 CDP 内部结构
7.2 关键 COM 接口
IWebAccountBackedAccountProvider 是一个基于 Web 账户(MSA 或 AAD)的身份提供者 COM 接口。它抽象了"从一个已登录的微软账户获取稳定设备标识"的能力。OneCoreAccountProvider 是该接口在 OneCore(跨设备 Windows 内核)上的具体实现。
这意味着 CDP 获取 GDID 的路径是:
- 找到当前登录的 Web 账户(MSA/AAD);
- 通过账户提供者 COM 接口查询该账户关联的稳定设备标识;
- 提供者内部读取注册表中的
LID(或等价的 MSA 缓存); - 通过回调
OnGetStableDeviceIdCompleted把字符串形式的 deviceId 交还给 CDP; - CDP 调用
assign()将其存入内部数据结构,供后续 DDS 注册使用。
7.3 "只消费不计算"的工程含义
这个设计有几个重要的工程与隐私含义:
- GDID 的真值源唯一:永远是
wlidsvcprovisioning 写入注册表的值,CDP 只是搬运工。 - CDP 无法独立伪造 GDID:如果注册表中的 LID 被清除,CDP 调用链将无法返回有效 deviceId。
- 多服务复用同一标识:CDP、Delivery Optimization 等多个子系统都从同一注册表值读取,导致 GDID 成为跨服务关联的天然主键。
7.4 函数偏移地址
逆向工程标注了 cdp.dll 中相关函数的偏移地址(随版本变化,以下为代表性定位):
GetStableDeviceIdFromProvider:CDP 导出表中的稳定设备 ID 入口;OnGetStableDeviceIdCompleted:异步完成回调,在.text段内;assign:内部存储函数,负责把 deviceId 写入 CDP 设备对象。
(具体 RVA 因 cdp.dll 版本而异,逆向时需结合符号或模式匹配定位。)
八、DDS 设备目录服务架构
8.1 DDS 是什么
DDS(Device Directory Service)是微软的跨设备身份图谱后端,域名 dds.microsoft.com。它维护"用户 → 设备 → 设备能力"的映射关系,是以下功能的后端基础设施:
| 功能 | 对 DDS 的使用 |
|---|---|
| Phone Link(手机连接) | 发现并配对手机与 PC |
| 云剪贴板(Cloud Clipboard) | 跨设备同步剪贴板内容 |
| "继续在 PC 上"(Continue on PC) | 将手机上的网页/任务转移到 PC |
| Nearby Share(附近分享) | 发现附近设备并分享文件 |
这些功能看似独立,但它们背后共享同一套 DDS 设备图谱——而图谱中每个设备节点的核心标识,正是 GDID。
8.2 设备令牌认证
CDP 注册设备到 DDS 时,使用基于设备令牌的认证。涉及的 OAuth scope 包括:
scope=service::dds.microsoft.com::MBI_SSL_TOKEN_BROKER
scope=service::activity.windows.com::MBI_SSL_SA_TOKEN_BROKER
MBI_SSL_TOKEN_BROKER 是微软身份平台的令牌代理 scope,表示请求方是一个已 provisioning 的设备(而非单纯用户)。这确保了只有合法注册的设备才能向 DDS 写入图谱数据。
8.3 注册流程
CDP.RegisterUserDeviceAsync
├─ 获取设备令牌 (scope: service::dds.microsoft.com::MBI_SSL_TOKEN_BROKER)
├─ 构造设备注册请求 (含 GDID 作为设备主键)
├─ POST 到 dds.microsoft.com
└─ 接收 HTTP 200 确认 → 设备节点进入图谱
注册成功后,该设备就在 DDS 图谱中成为一个以 GDID 为标识的节点,并与登录用户关联。此后,任何依赖 DDS 的功能都能通过 GDID 定位这台设备。
8.4 设备图谱的关联性
DDS 图谱的强大之处在于其关联性:
- 用户关联:同一 MSA 登录的多台设备,在图谱中以用户 PUID(
0003前缀)为枢纽相互关联; - 设备关联:每台设备以 GDID(
0018前缀)为节点; - 跨服务复用:Phone Link 的配对记录、云剪贴板的同步目标、Nearby Share 的发现列表,都引用同一套设备节点。
这意味着,只要拿到一个 GDID,理论上就可以在图谱中查询到该设备参与过的所有跨设备交互。
九、Delivery Optimization 中的 GDID
Delivery Optimization(传递优化,服务 DoSvc)是 Windows 的 P2P 内容分发机制。它同样会消费 GDID,在遥测与状态数据中以 UCDOStatus.GlobalDeviceId 字段上报。
这形成了一个额外的暴露面:即便用户从不使用 Phone Link 或云剪贴板,只要系统开启了 Delivery Optimization(默认开启),GDID 就会随着内容下载的统计与对等连接信息一同上报。
UCDOStatus.GlobalDeviceId 的存在表明,GDID 的消费方不止 CDP 一家,而是被多个独立子系统各自读取并上报,进一步扩大了跨服务追踪的可能。
十、隐私影响分析
10.1 VPN 无法隐藏 GDID
这是 GDID 最具隐私敏感性的特征。GDID 不是网络层标识符(如 IP 地址),而是应用层标识符:
- 它随 HTTPS 请求体(SOAP、DDS API)传输,VPN 只能隐藏网络层的源 IP,无法触及 TLS 隧道内的载荷;
- 它存储在本地注册表,任何本地进程都能读取;
- 它由服务器分配并持久化,即使更换 IP、更换网络,GDID 依然不变。
因此,一个用户即便全程使用 VPN,微软云端仍能通过 GDID 把该设备的所有活动关联到同一身份。
10.2 跨服务追踪
由于 GDID 被多个子系统消费(CDP/DDS、Delivery Optimization、以及潜在的遥测管道),它成为天然的跨服务关联主键:
[MSA 登录] ──┐
[DDS 注册] ──┼──> 同一 GDID <── [Delivery Optimization 上报]
[云剪贴板] ──┤ [活动历史 activity.windows.com]
[Phone Link]──┘
微软可以在服务端把不同来源的日志按 GDID join 起来,重建完整的设备行为画像。
10.3 IP 关联与执法归因
在 Scattered Spider 案件中,FBI 正是利用 GDID 关联了 IP 历史与浏览记录。其逻辑链条是:
- 攻击者使用的某台 Windows 设备拥有一个固定 GDID;
- 该 GDID 在多个微软服务中留下活动记录(含源 IP、时间戳);
- 即使攻击者使用了代理或 VPN 切换 IP,GDID 始终不变;
- 服务端按 GDID 聚合后,可还原设备在不同时间、不同 IP 下的完整活动轨迹。
这正是 GDID 在联邦起诉书中被作为"Global Device Identifier"引用的原因——它具备执法层面可用的稳定归因能力。
10.4 持久性与重装的权衡
GDID 的持久性是双刃剑:
- 对功能:持久性保证了跨设备体验的连续性;
- 对隐私:持久性意味着标识符长期可关联,用户几乎无法在不重装系统的情况下刷新它。
唯一的"刷新"手段是 Windows 重装(触发新的 provisioning),但这显然不是日常可用的隐私保护手段。
十一、与传统硬件指纹技术的对比
GDID 与传统的硬件指纹技术有本质区别。下表进行系统对比:
| 维度 | 传统硬件指纹(MAC 地址 / 硬件序列号) | GDID(MSA Device PUID) |
|---|---|---|
| 生成位置 | 客户端本地(硬件固化或本地计算) | 服务器分配(login.live.com) |
| 位数 | MAC 48 位;序列号变长 | 64 位 |
| 派生来源 | 网卡 / CPU / 主板 / 磁盘序列号 | 与硬件无关,安装实例级 |
| 重装行为 | 不变(硬件未变则指纹不变) | 刷新(产生全新 GDID) |
| 硬件依赖 | 强依赖 | 弱依赖(仅认证密钥绑定硬件,PUID 本身不依赖) |
| 存储方式 | 硬件固化 / 驱动可读 | 注册表明文(HKCU) |
| 跨服务性 | 通常单服务/单应用使用 | 跨微软全域服务复用 |
| VPN 是否可隐藏 | 视情况(MAC 不出本地网络,序列号不出本机) | 不可隐藏(应用层载荷) |
| 可伪造性 | 部分可改(MAC 可软改) | 客户端不可伪造(服务器分配) |
| 隐私刷新难度 | 可改 MAC、更换硬件 | 需重装系统或重置 MSA 设备注册 |
| 法律证据效力 | 较弱(易伪造、易变更) | 较强(服务器分配、持久、可追溯) |
核心差异在于:传统硬件指纹是本地派生、可篡改的;GDID 是服务器分配、客户端不可伪造、跨服务复用的。后者在追踪能力上远超前者。
十二、减少暴露的方法分析
鉴于 GDID 的服务器分配特性,完全"清除"它而不损失功能是困难的,但可以通过组合策略减少暴露面。
12.1 本地账户 vs MSA 账户
GDID 的产生前提是 Windows 安装注册到 MSA。如果使用本地账户登录 Windows(不绑定 Microsoft Account),则不会触发 MSA 设备 provisioning,也就不会产生 Device PUID / GDID。
代价:失去 OneDrive 同步、Microsoft Store 个性化、跨设备体验等功能。
12.2 断开 MSA 设备注册
在已绑定 MSA 的系统上,可以在微软账户的设备管理页面移除该设备,并清理本地注册表中的 LID。但这只是"注销"当前 PUID,下次 MSA 重新登录会触发新的 provisioning,分配新 GDID。
12.3 禁用相关服务
禁用以下服务可以阻止 GDID 的部分上报渠道:
CDPSvc(Connected Devices Platform Service)—— 阻止 DDS 注册;DoSvc(Delivery Optimization)—— 阻止GlobalDeviceId上报。
代价:失去 Phone Link、云剪贴板、Nearby Share,以及 P2P 下载加速。
12.4 重装刷新
重装 Windows 会触发新的 provisioning,获得全新 GDID,从而切断与旧 GDID 的关联。这是最彻底但成本最高的方法。
12.5 注册表清理(临时性)
删除 HKCU\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties 下的 LID 值,可以临时使本地消费方无法读取 GDID。但下一次 MSA 服务活动可能重新 provisioning 并写回。因此这只能作为临时手段。
12.6 暴露面收敛建议
| 目标 | 措施 | 代价 |
|---|---|---|
| 不产生 GDID | 使用本地账户 | 失去 MSA 同步功能 |
| 阻止 DDS 上报 | 禁用 CDPSvc | 失去跨设备功能 |
| 阻止 DO 上报 | 禁用 DoSvc | 失去 P2P 加速 |
| 切断旧关联 | 重装系统 + 新 MSA | 高 |
| 临时清除本地 | 删除 LID 注册表值 | 临时,会被写回 |
十三、PowerShell 查看与脱敏指南
13.1 查看自己的 GDID
方法一:直接读取注册表原始十六进制值
(Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties').LID
输出示例:
0018000FC8CB93CC
方法二:转换为 g: 十进制格式(与起诉书一致的呈现)
$hex = (Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties').LID
"g:$([Convert]::ToUInt64($hex, 16))"
输出示例:
g:6755467234350028
这正是法庭文件中出现的格式。
13.2 验证前缀
$hex = (Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties').LID
if ($hex -like '0018*') { 'Device PUID (设备级 / GDID)' }
elseif ($hex -like '0003*') { 'User PUID (用户级)' }
else { '未知命名空间前缀: ' + $hex.Substring(0,4) }
13.3 脱敏指南
在分享截图、日志或诊断信息时,务必对 GDID 进行脱敏,因为它是一个全局唯一、跨服务可关联的设备标识符。
脱敏原则:
- 截断:只保留前缀与少量字符,如
0018:****:93CC; - 哈希化:用单向哈希替换原始值(注意:脱敏后无法还原);
- 整体替换:用占位符
<GDID>替换。
PowerShell 脱敏脚本:
function Mask-Gdid {
param([string]$HexLid)
if ([string]::IsNullOrEmpty($HexLid)) { return '<空>' }
$prefix = $HexLid.Substring(0, 4)
$tail = $HexLid.Substring($HexLid.Length - 4)
$masked = '****'
"$prefix`:$masked`:$tail"
}
$raw = (Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties').LID
Mask-Gdid -HexLid $raw
# 输出: 0018:****:93CC
脱敏检查清单:
注意:GDID 一旦泄露,等同于暴露了设备在微软全域服务中的身份锚点。在公开渠道(论坛、issue、博客)分享任何包含 GDID 的内容前,必须完成脱敏。
十四、总结
通过对 GDID 的深度逆向,我们可以得出以下技术结论:
-
GDID 的本质是 MSA Device PUID,一个 64 位、由
login.live.com服务器在设备 provisioning 阶段分配的标识符,而非硬件哈希。 -
技术栈是分层的:
wlidsvc.dll负责 provisioning 与存储,注册表(HKCU\...\IdentityCRL\ExtendedProperties\LID)明文持久化,cdp.dll/CDPSvc只消费不计算,DDS 作为云端图谱汇聚,Delivery Optimization 作为额外上报通道。 -
重装即刷新是服务器分配机制的必然结果,证伪了所有"硬件派生"假说。
-
GDID 的隐私威胁在于跨服务可关联性与 VPN 不可见性。它不是网络层标识,而是应用层标识,VPN、代理均无法隐藏。
-
在执法层面,GDID 具备稳定归因能力,Scattered Spider 案件中 FBI 正是利用其关联 IP 历史与浏览记录完成归因。
-
减少暴露需要组合策略:本地账户、禁用 CDP/DO 服务、重装刷新,但每种策略都有功能代价。
GDID 揭示了现代操作系统"设备身份"设计的演进方向:从本地派生、可篡改的硬件指纹,走向服务器分配、跨服务复用、客户端不可伪造的云端身份锚点。这种设计在功能连贯性上更强大,但在隐私与可追踪性上也更具穿透力。理解其技术机理,是进行有效隐私评估与暴露面管理的必要前提。
附录:关键标识符速查
| 标识 | 含义 | 示例 |
|---|---|---|
0018XXXXXXXXXXXX |
注册表中的 Device PUID(十六进制) | 0018000FC8CB93CC |
g:<decimal> |
设备图谱中的 GDID | g:6755467234350028 |
0003XXXXXXXXXXXX |
User PUID(用户级) | 0003xxxxxxxxxxxx |
UCDOStatus.GlobalDeviceId |
Delivery Optimization 中的 GDID 字段 | 6755467234350028 |
<ps:DevicePUID> |
SOAP 响应中的 Device PUID 元素 | — |
附录:关键注册表与服务速查
| 项 | 路径 / 名称 |
|---|---|
| PUID 存储键 | HKCU\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties |
| PUID 值名 | LID |
| MSA 服务 | wlidsvc(wlidsvc.dll) |
| CDP 服务 | CDPSvc(cdp.dll) |
| Delivery Optimization 服务 | DoSvc |
| DDS 端点 | dds.microsoft.com |
| Provisioning 端点 | login.live.com(Passport PPCRL SOAP) |
| DDS OAuth scope | service::dds.microsoft.com::MBI_SSL_TOKEN_BROKER |
| Activity OAuth scope | service::activity.windows.com::MBI_SSL_SA_TOKEN_BROKER |
本文基于公开的逆向工程成果(smtimesiwndr/gdid-reversal)与美国联邦刑事起诉书 United States v. Peter Stokes 的公开技术证据撰写,仅供技术研究与隐私评估参考。
浙公网安备 33010602011771号