Multipurpose utility for managing Games for Windows - LIVE installs and content. (Mirrored from https://github.com/InvoxiPlayGames/GfWLUtility)
at master 4.2 kB view raw
1using System.Collections.Generic; 2using System.Drawing; 3using System.IO; 4using System.Runtime.InteropServices; 5 6namespace GfWLUtility 7{ 8 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 9 internal struct GamertagString 10 { 11 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x10)] 12 public string Value; 13 14 public static implicit operator string(GamertagString value) 15 { 16 return value.Value; 17 } 18 } 19 20 [StructLayout(LayoutKind.Sequential, Pack = 1)] 21 internal struct XamAccount 22 { 23 public uint Flags1; 24 25 public uint Flags2; 26 27 [MarshalAs(UnmanagedType.Struct)] 28 public GamertagString Gamertag; 29 30 public ulong OnlineXUID; 31 32 public uint Flags3; 33 34 public uint OnlineServiceID; 35 36 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)] 37 public byte[] Passcode; // unused in GfWL..? 38 39 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x14)] 40 public string Domain; // unused in GfWL 41 42 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x18)] 43 public string Realm; // unused in GfWL 44 45 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] 46 public byte[] OnlineKey; // unused in GfWL 47 48 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x72)] 49 public string PassportEmail; 50 51 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] 52 public string PassportPassword; // unused in GfWL 53 54 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x72)] 55 public string OwnerPassportEmail; // unused in GfWL 56 } 57 58 internal class KnownUser 59 { 60 public ulong XUID; 61 public Bitmap ProfilePicture; 62 public bool HasFullInformation; 63 64 public string Gamertag; 65 public bool LiveEnabled; 66 public bool Pnet; 67 public ulong OnlineXUID; 68 public string MsaEmail; 69 70 public KnownUser(ulong xuid) 71 { 72 XUID = xuid; 73 } 74 75 public override string ToString() 76 { 77 if (Gamertag != null) 78 return Gamertag; 79 return $"{XUID:X} (Unknown)"; 80 } 81 } 82 83 internal class UserManager 84 { 85 public static Dictionary<ulong, KnownUser> KnownUsers = new Dictionary<ulong, KnownUser>(); 86 87 public static void FoundUserExists(ulong xuid) 88 { 89 if (!KnownUsers.ContainsKey(xuid)) 90 KnownUsers[xuid] = new KnownUser(xuid); 91 } 92 93 public static void FoundUserGamertag(ulong xuid, string name) 94 { 95 FoundUserExists(xuid); 96 KnownUsers[xuid].Gamertag = name; 97 } 98 99 public static void PopulateUserInformation(ulong xuid, string accountFile = null) 100 { 101 FoundUserExists(xuid); 102 byte[] accBytes = null; 103 // if we're given one, attempt to decrypt profile information directly 104 if (accountFile != null) 105 { 106 byte[] encBytes = File.ReadAllBytes(accountFile); 107 accBytes = XeKeys.UnObfuscate(encBytes); 108 } 109 // otherwise check if we have decrypted profile information in the account cache 110 if (accBytes == null) 111 { 112 string accCacheFilename = UtilityFuncs.GetLocalDirectory("ProfileCache") + xuid.ToString("x16") + ".bin"; 113 if (File.Exists(accCacheFilename)) 114 accBytes = File.ReadAllBytes(accCacheFilename); 115 } 116 // if we have a byte stream of the right length of a decrypted account file, hooray 117 if (accBytes != null && accBytes.Length == 0x17C) 118 { 119 XamAccount account = UtilityFuncs.BytesToStructure<XamAccount>(accBytes); 120 KnownUsers[xuid].Gamertag = account.Gamertag; 121 if ((account.Flags1 & 0x20000000) == 0x20000000) 122 KnownUsers[xuid].LiveEnabled = true; 123 KnownUsers[xuid].OnlineXUID = account.OnlineXUID; 124 KnownUsers[xuid].Pnet = account.OnlineServiceID == 0x54524150; 125 KnownUsers[xuid].MsaEmail = account.PassportEmail; 126 KnownUsers[xuid].HasFullInformation = true; 127 } 128 } 129 } 130}