
Microsoft의 GDID(Global Device Identifier)에 대한 리버스 엔지니어링 분석을 통해 서버 할당 MSA Device PUID로 생성되고, 레지스트리에 저장되며, Connected Devices Platform을 통해 전송되는 과정을 밝혀내며, 재현 가능한 법의학 방법론을 제공합니다.
2026년 7월 Scattered Spider 고소장에서 언급된 영구적인 Windows 식별자인 Microsoft의 "Global Device Identifier"가 실제로 생성, 저장 및 전송되는 방식
[!NOTE] 아래 나열된 내용은 사실이지만 일부 정보가 누락되어 있습니다. MSA에 로그인했는지 여부와 관계없이 GDID가 있다는 점을 깨달았습니다. 게시 당시에는 인지하지 못했지만 조사해 보았습니다. CDP에는 MSA가 연결되지 않은 경우 사용되는 익명 장치 경로가 있습니다. 기본 시스템은 여전히 사실적으로 정확하며 몇 가지 사항만 누락되었습니다.
Global Device Identifier g:6755467234350028로 나타납니다.g:<decimal> 형식으로 기록됩니다.wlidsvc(Microsoft 계정 서비스)가 login.live.com으로 장치를 프로비저닝하고 장치 PUID를 받아 레지스트리에 저장 -> Connected Devices Platform(cdp.dll / CDPSvc)이 이를 읽고 Device Directory Service (DDS) 그래프에 등록 -> Delivery Optimization이 이를 문서화된 UCDOStatus.GlobalDeviceId로 보고합니다.[!NOTE] 신뢰도 레이블. 모든 주장에는 태그가 붙어 있어 직접 평가할 수 있습니다:
[COURT]1차 출처 사실,[OBSERVED]테스트 머신에서 실제 재현,[STATIC]바이너리 및 공개 Windows PDB에서 입증,[ASSESSED]증거로부터의 강력한 추론.
wlidsvc)2026년 7월 1일, DOJ는 Scattered Spider(일명 Octo Tempest / UNC3944 / 0ktapus)의 일원으로 추정되는 Peter Stokes에 대한 형사 고소장을 공개했습니다. 진술서는 Microsoft가 FBI가 장치에 활동을 귀속시키는 데 어떻게 도움을 주었는지 설명합니다.
[!IMPORTANT]
[COURT]대체 고소장(¶25, p.34)에서 인용:"ngrok 계정은 Global Device Identifier g:6755467234350028('GDID')을 통해 설정되었습니다. Microsoft 담당자에 따르면, Windows 생태계의 Global Device Identifier는 장치에서 Windows 운영 체제 설치를 고유하게 식별하도록 설계된 영구적인 장치 수준 식별자입니다... GDID는 장치의 Windows 설치에 연결된 전역 고유 식별자입니다. GDID는 장치의 Windows 운영 체제 업데이트에서 일관되게 유지되지만, Windows 재설치는... 새로운 고유 GDID와 연결됩니다."
각주에는 한 Microsoft 사용자가 여러 GDID를 가질 수 있다고 추가합니다. 진술서는 GDID의 IP 기록 및 검색(예: empirehotelnyc.com, Growtopia/Ubisoft 로그인 URL)을 용의자가 로그인한 계정과 연관시킵니다.
여기서 두 가지 사항이 이 분석의 나머지 부분을 이끕니다:
g: 뒤에 10진수 정수입니다(g:6755467234350028). 16진수로는 0x0018000FC8CB93CC이므로 64비트 숫자입니다.소셜 미디어 요약은 GDID가 *"설치 시 일련 번호에서 생성된 128비트 식별자"*라고 주장했습니다. 두 부분 모두 거짓입니다:
| 주장 (소셜 미디어) | 현실 (1차 출처) |
|---|---|
| "128비트" | 고소장의 값은 g:6755467234350028이며, 64비트에 맞는 10진수입니다(0x0018000FC8CB93CC). |
| "설치 시 일련 번호에서 생성" | 고소장은 재설치가 새로운 GDID를 생성한다고 말합니다. 고정된 일련 번호에서 파생된 값은 재설치 후 동일하게 돌아와야 하며, 변경되지 않습니다. |
[!NOTE] CDP를 좀 더 리버싱한 후 약간의 잘못된 정보를 제공했습니다. 로컬 계정을 사용한다고 GDID가 방지되지는 않습니다. CDP에는 Microsoft 계정이 없는 경우 사용되는 익명 장치 경로가 있습니다. 읽을 때 이 점을 명심하십시오.
[STATIC] Microsoft의 공개 Azure Monitor 문서는 UCDOStatus (Update Compliance / Delivery Optimization) 테이블의 GlobalDeviceId 열을 정의합니다:
GlobalDeviceId(문자열): "Microsoft 전역 장치 식별자. Microsoft에서 내부적으로 사용하는 식별자입니다."
LastCensusSeenTime, ISP, City, Country 바로 옆에 위치하여 지리 및 IP와 연결된 장치 ID가 생성됩니다. Microsoft가 공개 문서에서 값을 명명한 유일한 곳입니다. 그러나 Delivery Optimization은 이를 보고만 합니다. 중요하게도 이를 소유하지는 않습니다. 업스트림을 따라가면 Connected Devices Platform에 도달합니다.
[STATIC] C:\Windows\System32\cdp.dll (Connected Devices Platform, 서비스 CDPSvc + CDPUserSvc)에는 GlobalDeviceId 기호와 전체 Device Directory Service 등록 하위 시스템이 포함되어 있습니다:
ddsregistrationclient.cpp ddsregistrationmanager.cpp ddsregistrationinfo.cpp
DdsRegistrationClient RegisterUserDevicesObserver DdsRegistrationInfoProviderForCDP
endpoints: dds.microsoft.com fd.dds.microsoft.com aad.cs.dds.microsoft.com cdpcs.access.microsoft.com
device-id format string: "g:%s"
DDS = Device Directory Service는 Microsoft의 교차 장치 ID 그래프(Phone Link, 클라우드 클립보드, "PC에서 계속", Nearby Share 뒤의 백엔드)입니다. CDP는 이 그래프에 설치를 등록하는 Windows 클라이언트로, g:<decimal>로 키가 지정됩니다.
[OBSERVED] 새 등록을 강제하고(로컬 상태를 지운 후 CDPSvc 다시 시작) CDP 자체 ETW 공급자를 캡처하여 전체 핸드셰이크를 생성했습니다:
DdsClient::RegisterUserDeviceAsync() RegistrationReason: Startup Account Type: MSA
DDSClient: Registration response received. HTTP status code: 200
OnRegisterUserDeviceComplete
GetDeviceIdAndTicketActivity -> deviceid: 0018XXXXXXXXXXXX
g:<decimal>로 기록된 그 deviceid는 구조적으로 고소장의 값과 일치합니다:
| 값 | 16진수 (64비트) | 클래스 접두사 | |
|---|---|---|---|
| 내 머신 (수정됨) | g:XXXXXXXXXXXXXXXX | 0x0018XXXXXXXXXXXX | 0018 |
| 법원 증거 | g:6755467234350028 | 0x0018000FC8CB93CC | 0018 |
둘 다 동일한 0x0018 상위 워드 클래스(장치 PUID 네임스페이스, §6 참조)에 있는 64비트 값입니다. g: 접두사는 해당 정수를 10진수로 나타낸 것입니다.
[STATIC] 공개 PDB(cdp.pdb)를 사용하면 cdp.dll의 장치 ID 경로는 ID 스택에 대한 요청 및 대기일 뿐입니다. CDP는 ID를 자체적으로 계산하지 않습니다:
flowchart TD
A["GetStableDeviceIdFromProvider<br/>0x0A3140"] --> B["provider.GetStableDeviceIdAsync<br/>(vtable +0x48)"]
B --> C["OneCoreAccountProvider::<br/>GetStableDeviceIdAsync 0x0C8370"]
C --> D["IWebAccountBackedAccountProvider<br/>(MSA / AAD identity COM)"]
D --> E["OnGetStableDeviceIdCompleted<br/>(const char* deviceId) 0x06CEA0"]
E -->|"assign() string, signal flag"| A
이를 수신하는 콜백은 명확합니다. ID는 문자열로 나타나며 그냥 저장됩니다:
; OnGetStableDeviceIdCompleted
mov rbp, r9 ; r9 = ID 공급자가 전달한 device-id 문자열
lea rcx, [rsi+0xD8] ; CDP 멤버 필드
mov rdx, rbp
call assign@basic_string ; 저장, 계산 없음, 일련 번호 없음
call Set@CdpWaitableFlag ; 대기자 차단 해제
결론: GDID는 CDP 아래의 Windows ID 스택에서 생성되어 불투명한 문자열로 CDP에 전달됩니다. 이는 Microsoft 계정 서비스를 가리킵니다.
wlidsvc)[STATIC] C:\Windows\System32\wlidsvc.dll은 Microsoft 계정 / Passport (Windows Live ID) 서비스로, 리터럴 GlobalDeviceId를 포함하는 유일한 ID 바이너리이며 전체 장치 프로비저닝 메커니즘을 보유합니다:
CDeviceIdentityBase::CreateNewDeviceIdentity / Provision / BindDeviceToHardware / GetDeviceCert
DeviceAssociateRequest (Passport PPCRL SOAP -> login.live.com)
<ps:DevicePUID> ... </ps:DevicePUID>
DeviceIdStore::LogToRegistry
BCryptGenRandom / CCryptRandom::GenRandom (장치 KEY, ID 아님)
식별자는 Device PUID (Passport Unique ID)이며, 64비트 MSA 식별자입니다. 그 안의 BCryptGenRandom은 BindDeviceToHardware가 머신에 고정하는 장치 인증 키를 만들며, PUID가 아닙니다.
[STATIC] 클라이언트는 서버의 SOAP 응답에서 PUID를 추출하며, 응답 본문에 대한 XPath를 사용합니다:
/S:Envelope/S:Body/ps:DeviceUpdatePropertiesResponse/HWPUIDFlipped