Multipurpose utility for managing Games for Windows - LIVE installs and content. (Mirrored from https://github.com/InvoxiPlayGames/GfWLUtility)
at master 387 lines 18 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Drawing; 4using System.IO; 5using System.Linq; 6using System.Reflection; 7using System.Security.Cryptography; 8using System.Text; 9 10namespace GfWLUtility 11{ 12 internal class KnownTitle 13 { 14 public uint TitleID; 15 public string Name; 16 public string ProductKey; 17 public byte[] ConfigData; 18 public Bitmap Icon; 19 20 public KnownTitle(uint titleID) 21 { 22 TitleID = titleID; 23 } 24 25 public override string ToString() 26 { 27 if (Name != null) 28 return Name; 29 return $"{TitleID:X8} (Unknown)"; 30 } 31 } 32 33 internal class TitleManager 34 { 35 // list from XLiveLessNess 36 // https://gitlab.com/GlitchyScripts/xlln-data/-/blob/main/XLiveLessNess/hub/titles.json?ref_type=heads 37 public static Dictionary<uint, string> TitleNameDatabase = new Dictionary<uint, string>() 38 { 39 { 0x33390FA0, "7 Wonders 3" }, 40 { 0x33390FA1, "Chainz 2: Relinked" }, 41 { 0x35530FA0, "Cubis Gold" }, 42 { 0x35530FA1, "Cubis Gold 2" }, 43 { 0x35530FA2, "Ranch Rush 2" }, 44 { 0x355A0FA0, "Mahjongg Dimensions" }, 45 { 0x36590FA0, "TextTwist 2" }, 46 { 0x36590FA1, "Super TextTwist" }, 47 { 0x41560829, "007: Quantum of Solace" }, 48 { 0x41560FA0, "Call of Duty 4" }, 49 { 0x41560FA1, "Call of Duty: WaW" }, 50 { 0x41560FA2, "Singularity" }, 51 { 0x41560FA3, "Transformers: WFC" }, 52 { 0x41560FA4, "Blur" }, 53 { 0x41560FA5, "[PROTOTYPE]" }, 54 { 0x41560FA6, "007: Blood Stone" }, 55 { 0x415807D5, "BlazBlue: Calamity Trigger" }, 56 { 0x425307D6, "Fallout 3" }, 57 { 0x42530FA0, "Hunted Demon's Forge" }, 58 { 0x425607F3, "TRON: Evolution" }, 59 { 0x42560FA0, "LEGO Pirates of the Caribbean: The Video Game" }, 60 { 0x434307DE, "Lost Planet: Extreme Condition: Colonies Edition" }, 61 { 0x434307F4, "Street Fighter IV" }, 62 { 0x434307F7, "Resident Evil 5" }, 63 { 0x43430803, "Dark Void" }, 64 { 0x43430808, "Lost Planet 2" }, 65 { 0x4343080E, "Dead Rising 2" }, 66 { 0x43430FA0, "Super Street Fighter IV: Arcade Edition" }, 67 { 0x43430FA1, "Resident Evil: Operation Raccoon City" }, 68 { 0x43430FA2, "Dead Rising 2: Off the Record" }, 69 { 0x43430FA5, "Street Fighter X Tekken" }, 70 { 0x434D0820, "DiRT 2" }, 71 { 0x434D082F, "FUEL" }, 72 { 0x434D0831, "F1 2010" }, 73 { 0x434D083E, "Operation Flashpoint: Red River" }, 74 { 0x434D0FA0, "DiRT 3" }, 75 { 0x434D0FA1, "F1 2011" }, 76 { 0x44540FA0, "Crash Time 4: The Syndicate" }, 77 { 0x44540FA1, "Crash Time 4 Demo" }, 78 { 0x4541091C, "Dragon Age: Awakening" }, 79 { 0x4541091F, "Battlefield: Bad Co. 2" }, 80 { 0x45410920, "Mass Effect 2" }, 81 { 0x45410921, "Dragon Age: Origins" }, 82 { 0x45410935, "Bulletstorm" }, 83 { 0x45410FA1, "Medal of Honor" }, 84 { 0x45410FA2, "Need for Speed SHIFT" }, 85 { 0x45410FA3, "Dead Space 2" }, 86 { 0x45410FA4, "Bulletstrom DEMO" }, 87 { 0x45410FA5, "Dragon Age 2" }, 88 { 0x45410FA8, "Crysis 2" }, 89 { 0x45410FAB, "The Sims 3" }, 90 { 0x45410FAC, "The Sims 3 Late Night" }, 91 { 0x45410FAD, "The Sims 3 Ambitions" }, 92 { 0x45410FAE, "World Adventures" }, 93 { 0x45410FAF, "The Sims Medieval" }, 94 { 0x45410FB1, "Darkspore" }, 95 { 0x45410FB2, "NFS SHIFT 2 Unleashed" }, 96 { 0x45410FB3, "Spore" }, 97 { 0x45410FB4, "The Sims 3 Generations" }, 98 { 0x45410FB5, "Alice: Madness Returns" }, 99 { 0x45410FB6, "Harry Potter (DH2)" }, 100 { 0x45410FB7, "The Sims Medieval Pirates & Nobles" }, 101 { 0x45410FB8, "Tiger Woods PGA TOUR 12: The Masters" }, 102 { 0x454D07D4, "Flatout Ultimate Carnage" }, 103 { 0x46450FA0, "Divinity II - DKS" }, 104 { 0x46450FA1, "Cities XL 2011" }, 105 { 0x46450FA2, "The Next Big Thing" }, 106 { 0x46450FA3, "Faery" }, 107 { 0x46450FA4, "Pro Cycling Manager" }, 108 { 0x46550FA0, "Jewel Quest 5" }, 109 { 0x46550FA1, "Family Feud Dream Home" }, 110 { 0x48450FA0, "AFL Live" }, 111 { 0x48450FA1, "Rugby League Live 2" }, 112 { 0x49470FA1, "Test Drive Ferrari Racing Legend" }, 113 { 0x4B590FA0, "Tropico 3 Gold Edition" }, 114 { 0x4B590FA1, "Patrician IV" }, 115 { 0x4B590FA3, "Commandos Complete" }, 116 { 0x4B590FA5, "Dungeons" }, 117 { 0x4B590FA8, "Patrician: RoaD" }, 118 { 0x4B590FA9, "Elements of War" }, 119 { 0x4B590FAA, "The First Templar" }, 120 { 0x4C4107EB, "Star Wars: The Clone Wars - Republic Heroes" }, 121 { 0x4D5307D6, "Shadowrun" }, 122 { 0x4D53080F, "Halo 2 Vista" }, 123 { 0x4D530841, "Viva Piñata" }, 124 { 0x4D530842, "Gears of War" }, 125 { 0x4D5308D2, "Microsoft Flight" }, 126 { 0x4D5308D3, "Firebird Project" }, 127 { 0x4D530901, "Game Room" }, 128 { 0x4D53090A, "Fable 3" }, 129 { 0x4D530935, "Flight Simulator X" }, 130 { 0x4D530936, "Age of Empires III" }, 131 { 0x4D530937, "Fable: TLC" }, 132 { 0x4D530942, "AoE Online - Beta" }, 133 { 0x4D530FA0, "Zoo Tycoon 2" }, 134 { 0x4D530FA2, "Toy Soldiers" }, 135 { 0x4D530FA3, "Age of Empires Online" }, 136 { 0x4D530FA4, "Toy Soldiers: Cold War" }, 137 { 0x4D530FA5, "Ms. Splosion Man" }, 138 { 0x4D530FA6, "Skulls of the Shogun" }, 139 { 0x4D530FA7, "Insanely Twisted Shadow Planet" }, 140 { 0x4D530FA8, "Iron Brigade" }, 141 { 0x4D530FA9, "MGS Pinball FX2 GFWL Games For Windows Live" }, 142 { 0x4D530FAA, "MGS Vodka PC" }, 143 { 0x4D5388B0, "BugBash 2" }, 144 { 0x4E4D0FA1, "Dark Souls: Prepare to Die Edition" }, 145 { 0x4E4D0FA2, "ACE COMBAT ASSAULT HORIZON: Enhanced Edition" }, 146 { 0x4E4E0FA0, "Trainz Simulator 2010" }, 147 { 0x4E4E0FA1, "Settle and Carlisle" }, 148 { 0x4E4E0FA2, "Classic Cabon City" }, 149 { 0x4E4E0FA3, "TS 2010: Blue Comet" }, 150 { 0x4E4E0FA4, "Trainz Simulator 12" }, 151 { 0x4F420FA0, "BubbleTown" }, 152 { 0x4F430FA0, "King's Bounty Platinum" }, 153 { 0x50470FA1, "Bejeweled 2" }, 154 { 0x50470FA3, "Bookworm" }, 155 { 0x50470FA4, "Plants vs. Zombies" }, 156 { 0x50470FA5, "Zuma's Revenge" }, 157 { 0x50470FA6, "Bejeweled 3" }, 158 { 0x50580FA0, "Europa Universalis III" }, 159 { 0x50580FA1, "Hearts of Iron III" }, 160 { 0x50580FA2, "King Arthur" }, 161 { 0x50580FA3, "Mount & Blade Warband" }, 162 { 0x50580FA4, "Victoria 2" }, 163 { 0x50580FA6, "EU 3: Divine Wind" }, 164 { 0x50580FA7, "EU3:Heir to the Throne" }, 165 { 0x50580FA8, "King Arthur The Druids" }, 166 { 0x50580FA9, "King Arthur The Saxons" }, 167 { 0x50580FAB, "Cities in Motion" }, 168 { 0x50580FAC, "Cities in Motion" }, 169 { 0x50580FAD, "EU 3: Chronicles" }, 170 { 0x50580FAE, "Darkest Hour" }, 171 { 0x50580FAF, "MnB: With Fire & Sword" }, 172 { 0x50580FB0, "King Arthur Collection" }, 173 { 0x50580FB1, "Supreme Ruler Cold War" }, 174 { 0x50580FB2, "Pirates of Black Cove" }, 175 { 0x51320FA0, "Poker Superstars III" }, 176 { 0x51320FA1, "Slingo Deluxe" }, 177 { 0x534307EB, "Kane & Lynch: Dead Men" }, 178 { 0x534307FA, "Battlestations: Pacific" }, 179 { 0x534307FF, "Batman: Arkham Asylum" }, 180 { 0x53430800, "Battlestations: Pacific" }, 181 { 0x5343080C, "Batman: AA GOTY" }, 182 { 0x53430813, "ChampionshipManager 10" }, 183 { 0x53430814, "Tomb Raider Underworld" }, 184 { 0x534507F0, "Universe at War: Earth Assault" }, 185 { 0x534507F6, "The Club" }, 186 { 0x53450826, "Stormrise" }, 187 { 0x5345082C, "Vancouver 2010" }, 188 { 0x53450849, "Alpha Protocol" }, 189 { 0x5345084E, "Football Manager 2010" }, 190 { 0x53450854, "Rome: Total War" }, 191 { 0x53450FA0, "Football Manager 2011" }, 192 { 0x53450FA1, "Dreamcast Collection" }, 193 { 0x53450FA2, "Virtua Tennis 4" }, 194 { 0x53460FA0, "A Vampyre Story" }, 195 { 0x53460FA1, "Ankh 2" }, 196 { 0x53460FA2, "Ankh 3" }, 197 { 0x53460FA3, "Rise of Flight: ICE" }, 198 { 0x535007E3, "Section 8" }, 199 { 0x53510FA0, "Deus Ex: GotY" }, 200 { 0x53510FA1, "Deus Ex: Invisible War" }, 201 { 0x53510FA2, "Hitman: Blood Money" }, 202 { 0x53510FA3, "Thief: Deadly Shadows" }, 203 { 0x53510FA4, "Hitman 2: SA" }, 204 { 0x53510FA5, "MINI NINJAS" }, 205 { 0x53510FA6, "Tomb Raider:Legend" }, 206 { 0x53510FA7, "Tomb Raider: Anniv." }, 207 { 0x53510FA8, "Battlestations: Midway" }, 208 { 0x53510FA9, "Conflict: Denied Ops" }, 209 { 0x53510FAA, "Project: Snowblind" }, 210 { 0x544707D4, "Section 8: Prejudice" }, 211 { 0x5451081F, "Juiced 2: Hot Import Nights" }, 212 { 0x5451082D, "Warhammer 40,000: Dawn of War 2: Chaos Rising" }, 213 { 0x54510837, "Red Faction: Guerrilla" }, 214 { 0x54510868, "DoW II: Chaos Rising" }, 215 { 0x54510871, "Saints Row 2" }, 216 { 0x54510872, "S.T.A.L.K.E.R." }, 217 { 0x5451087F, "Dawn of War" }, 218 { 0x54510880, "DoW - Dark Crusade" }, 219 { 0x54510881, "Supreme Commander" }, 220 { 0x54510882, "Supreme Commander: Forged Alliance" }, 221 { 0x5454083B, "Grand Theft Auto IV" }, 222 { 0x5454085C, "BioShock 2" }, 223 { 0x5454086E, "GTA IV: EFLC" }, 224 { 0x54540873, "Borderlands" }, 225 { 0x54540874, "Civ IV: Complete" }, 226 { 0x54540876, "GTA San Andreas" }, 227 { 0x54540877, "GTA: Vice City" }, 228 { 0x54540878, "Max Payne 2" }, 229 { 0x54540879, "Max Payne" }, 230 { 0x5454087B, "BioShock" }, 231 { 0x54540880, "Bully Scholarship Ed." }, 232 { 0x54540881, "Grand Theft Auto III" }, 233 { 0x54590FA0, "RIFT" }, 234 { 0x54590FA1, "RIFT CE" }, 235 { 0x54590FA2, "RIFT AoH CE" }, 236 { 0x554C0FA0, "4 Elements" }, 237 { 0x554C0FA1, "Gardenscapes" }, 238 { 0x554C0FA2, "Call of Atlantis" }, 239 { 0x554C0FA3, "Around the World in 80" }, 240 { 0x554C0FA4, "Fishdom: Spooky Splash" }, 241 { 0x55530855, "Prince of Persia: TFS" }, 242 { 0x55530856, "Assassin's Creed II" }, 243 { 0x55530857, "SplinterCellConviction" }, 244 { 0x55530859, "Prince of Persia: WW" }, 245 { 0x5553085A, "Prince of Persia: SoT" }, 246 { 0x5553085B, "The Settlers 7" }, 247 { 0x5553085E, "Assassin's Creed" }, 248 { 0x5553085F, "World In Conflict" }, 249 { 0x55530860, "Dawn of Discovery Gold" }, 250 { 0x55530861, "Prince of Persia" }, 251 { 0x55530862, "TC's RainbowSix Vegas2" }, 252 { 0x55530864, "GRAW 2" }, 253 { 0x55530865, "Far Cry 2" }, 254 { 0x55530866, "Silent Hunter 5" }, 255 { 0x55530FA0, "Prince of Persia: TT" }, 256 { 0x55530FA1, "Tom Clancy's H.A.W.X.2" }, 257 { 0x55530FA2, "Shaun White Skate" }, 258 { 0x55530FA3, "AC Brotherhood" }, 259 { 0x55530FA4, "AC Brotherhood Deluxe" }, 260 { 0x55530FA6, "From Dust" }, 261 { 0x57520806, "F.E.A.R. 2" }, 262 { 0x57520808, "LEGO Batman" }, 263 { 0x57520809, "LEGO Harry Potter: Years 1-4" }, 264 { 0x57520FA0, "Batman: Arkham City" }, 265 { 0x57520FA1, "LEGO Universe" }, 266 { 0x57520FA2, "Mortal Kombat Arcade Kollection" }, 267 { 0x57520FA3, "Gotham City Impostors" }, 268 { 0x584109EB, "Tinker" }, 269 { 0x584109F0, "World of Goo" }, 270 { 0x584109F1, "Mahjong Wisdom" }, 271 { 0x58410A01, "Where's Waldo" }, 272 { 0x58410A10, "Osmos" }, 273 { 0x58410A1C, "Carneyvale Showtime" }, 274 { 0x58410A6D, "Blacklight: Tango Down" }, 275 { 0x585207D1, "XLive" }, 276 { 0x5A450FA0, "Battle vs. Chess" }, 277 { 0x5A450FA1, "Two Worlds II" }, 278 { 0x5A500FA1, "Kona's Crate" } 279 }; 280 281 public static Dictionary<uint, KnownTitle> KnownTitles = new Dictionary<uint, KnownTitle>(); 282 283 public static void FoundTitleExists(uint titleID) 284 { 285 if (!KnownTitles.ContainsKey(titleID)) 286 KnownTitles[titleID] = new KnownTitle(titleID); 287 if (TitleNameDatabase.ContainsKey(titleID)) 288 KnownTitles[titleID].Name = TitleNameDatabase[titleID]; 289 } 290 291 public static void FoundTitleName(uint titleID, string name) 292 { 293 FoundTitleExists(titleID); 294 KnownTitles[titleID].Name = name; 295 } 296 297 public static string GetTitleProductKey(uint titleID) 298 { 299 if (KnownTitles.ContainsKey(titleID)) 300 { 301 // if we already fetched the product key, don't try to fetch it again 302 if (KnownTitles[titleID].ProductKey != null) 303 return KnownTitles[titleID].ProductKey; 304 305 string rawTokenPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 306 $"Microsoft\\Xlive\\Titles\\{titleID:X8}\\Token.bin"); 307 if (File.Exists(rawTokenPath)) { 308 byte[] tokenBytes = File.ReadAllBytes(rawTokenPath); 309 // first 32-bits are a size, we can ignore that 310 byte[] rawTokenBytes = tokenBytes.Skip(4).ToArray(); 311 // try to decrypt it, if we fail just assume the key is a dud 312 try 313 { 314 byte[] unprotectedBytes = ProtectedData.Unprotect(rawTokenBytes, null, DataProtectionScope.CurrentUser); 315 string productKey = Encoding.UTF8.GetString(unprotectedBytes); 316 KnownTitles[titleID].ProductKey = productKey; 317 return productKey; 318 } catch (Exception) 319 { 320 return null; 321 } 322 } 323 } 324 return null; 325 } 326 327 public static byte[] GetConfigSector(uint titleID, int sectorID) 328 { 329 if (KnownTitles.ContainsKey(titleID)) 330 { 331 string configPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 332 $"Microsoft\\Xlive\\Titles\\{titleID:X8}\\config.bin"); 333 byte[] configData = null; 334 if (KnownTitles[titleID].ConfigData == null) 335 { 336 if (File.Exists(configPath)) 337 KnownTitles[titleID].ConfigData = File.ReadAllBytes(configPath); 338 else 339 return null; 340 } 341 configData = KnownTitles[titleID].ConfigData; 342 343 int sectorStart = sectorID * 0x400; 344 // make sure the sector isn't empty 345 if (configData[sectorStart] != 0x00) 346 { 347 // copy it into a buffer and unprotect it 348 byte[] sector = new byte[0x400]; 349 Buffer.BlockCopy(configData, sectorStart, sector, 0, 0x400); 350 // try to decrypt it, if we fail just assume the sector doesn't exist 351 try 352 { 353 byte[] unprotectedSector = ProtectedData.Unprotect(sector, null, DataProtectionScope.CurrentUser); 354 return unprotectedSector; 355 } catch (Exception) 356 { 357 return null; 358 } 359 } else 360 { 361 return null; 362 } 363 } 364 return null; 365 } 366 367 public static void WriteConfigSector(uint titleID, int sectorID, byte[] data) 368 { 369 byte[] sector = new byte[0x1EC]; 370 Buffer.BlockCopy(data, 0, sector, 0, data.Length); 371 372 byte[] protectedSector = new byte[0x400]; 373 byte[] protectedSectorBytes = ProtectedData.Protect(sector, null, DataProtectionScope.CurrentUser); 374 Buffer.BlockCopy(protectedSectorBytes, 0, protectedSector, 0, protectedSectorBytes.Length); 375 376 string configPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 377 $"Microsoft\\Xlive\\Titles\\{titleID:X8}\\config.bin"); 378 byte[] configData = null; 379 if (File.Exists(configPath)) 380 configData = File.ReadAllBytes(configPath); 381 else 382 configData = new byte[0x5000]; 383 Buffer.BlockCopy(protectedSector, 0, configData, sectorID * 0x400, protectedSector.Length); 384 File.WriteAllBytes(configPath, configData); 385 } 386 } 387}