1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using LibXboxOne ;
5+ using LibXboxOne . Keystore ;
6+
7+ namespace DurangoKeyExtractor
8+ {
9+ public class KeyExtractor
10+ {
11+ public readonly Dictionary < string , byte [ ] > FoundCikKeys ;
12+ public readonly Dictionary < string , byte [ ] > FoundOdkKeys ;
13+ public readonly Dictionary < string , byte [ ] > FoundXvdSignKeys ;
14+ public string FilePath { get ; private set ; }
15+
16+ public KeyExtractor ( string filePath )
17+ {
18+ if ( ! File . Exists ( filePath ) )
19+ throw new InvalidOperationException ( $ "File { filePath } does not exist") ;
20+
21+ FilePath = filePath ;
22+ FoundCikKeys = new Dictionary < string , byte [ ] > ( ) ;
23+ FoundOdkKeys = new Dictionary < string , byte [ ] > ( ) ;
24+ FoundXvdSignKeys = new Dictionary < string , byte [ ] > ( ) ;
25+ }
26+
27+ void StoreKey ( string keyName , IKeyEntry keyEntry , byte [ ] keyData )
28+ {
29+
30+ switch ( keyEntry . KeyType )
31+ {
32+ case KeyType . CikKey :
33+ // Assemble GUID + keyData blob
34+ var assembledKey = new byte [ 0x30 ] ;
35+ Array . Copy ( ( ( CikKeyEntry ) keyEntry ) . KeyId . ToByteArray ( ) , 0 , assembledKey , 0 , 16 ) ;
36+ Array . Copy ( keyData , 0 , assembledKey , 16 , 32 ) ;
37+
38+ FoundCikKeys [ keyName ] = assembledKey ;
39+ break ;
40+ case KeyType . OdkKey :
41+ FoundOdkKeys [ keyName ] = keyData ;
42+ break ;
43+ case KeyType . XvdSigningKey :
44+ FoundXvdSignKeys [ keyName ] = keyData ;
45+ break ;
46+ default :
47+ throw new InvalidDataException ( "Invalid KeyType provided" ) ;
48+ }
49+ }
50+
51+ public int PullKeysFromFile ( )
52+ {
53+ var exeData = File . ReadAllBytes ( FilePath ) ;
54+
55+ int foundCount = 0 ;
56+ for ( int i = 0 ; i < exeData . Length - 32 ; i += 8 )
57+ {
58+ byte [ ] hash32 = HashUtils . ComputeSha256 ( exeData , i , 32 ) ;
59+ foreach ( var kvp in DurangoKeys . KnownKeys )
60+ {
61+ string keyName = kvp . Key ;
62+ IKeyEntry keyEntry = kvp . Value ;
63+
64+ if ( ( keyEntry . DataSize == 32 && hash32 . IsEqualTo ( keyEntry . SHA256Hash ) ) ||
65+ ( keyEntry . DataSize != 32 && keyEntry . DataSize <= ( exeData . Length - i ) &&
66+ keyEntry . SHA256Hash . IsEqualTo ( HashUtils . ComputeSha256 ( exeData , i , keyEntry . DataSize ) ) ) )
67+ {
68+ Console . WriteLine ( $ "Found { keyEntry . KeyType } \" { keyName } \" at offset 0x{ i : X} ") ;
69+
70+ byte [ ] keyData = new byte [ keyEntry . DataSize ] ;
71+ Array . Copy ( exeData , i , keyData , 0 , keyData . Length ) ;
72+ StoreKey ( keyName , keyEntry , keyData ) ;
73+ foundCount ++ ;
74+ }
75+ }
76+ }
77+
78+ return foundCount ;
79+ }
80+
81+ public bool SaveFoundKeys ( string destinationDirectory )
82+ {
83+ if ( ! Directory . Exists ( destinationDirectory ) )
84+ {
85+ Directory . CreateDirectory ( destinationDirectory ) ;
86+ }
87+
88+ foreach ( var entry in FoundCikKeys )
89+ {
90+ var path = Path . Combine ( destinationDirectory , $ "CIK_{ entry . Key } .bin") ;
91+ File . WriteAllBytes ( path , entry . Value ) ;
92+ }
93+
94+ foreach ( var entry in FoundOdkKeys )
95+ {
96+ var path = Path . Combine ( destinationDirectory , $ "ODK_{ entry . Key } .bin") ;
97+ File . WriteAllBytes ( path , entry . Value ) ;
98+ }
99+
100+ foreach ( var entry in FoundXvdSignKeys )
101+ {
102+ var path = Path . Combine ( destinationDirectory , $ "XVDSIGN_{ entry . Key } .bin") ;
103+ File . WriteAllBytes ( path , entry . Value ) ;
104+ }
105+
106+ return true ;
107+ }
108+ }
109+ }
0 commit comments