Created
April 10, 2017 11:31
-
-
Save nta/ad7ad4b3399e781200817d231788df4d to your computer and use it in GitHub Desktop.
Mass Effect: Andromeda - DLC 'unlock'
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// to use: start Origin with -lsxport:3236 | |
// this'll fix save games that were made with pirate copies that have all DLC | |
// by unlocking the DLC the CPY crack used | |
using System; | |
using System.Globalization; | |
using System.IO; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Sockets; | |
using System.Security.Cryptography; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Xml; | |
using System.Xml.Linq; | |
namespace LSXProxy | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
try | |
{ | |
Task.Run(RunProgram).Wait(); | |
} | |
catch (AggregateException ex) | |
{ | |
Console.WriteLine(ex.InnerException); | |
} | |
} | |
static async Task RunProgram() | |
{ | |
var listener = new TcpListener(new IPEndPoint(IPAddress.Loopback, 3216)); | |
listener.Start(); | |
while (true) | |
{ | |
var client = await listener.AcceptTcpClientAsync(); | |
RunClient(client); | |
} | |
} | |
static async Task RunClient(TcpClient client) | |
{ | |
var remoteClient = new TcpClient(); | |
await remoteClient.ConnectAsync(IPAddress.Loopback, 3236); | |
async Task InterceptionStream(TcpClient from, TcpClient to, Func<byte[], Task<byte[]>> readFunction) | |
{ | |
var fromStream = from.GetStream(); | |
var toStream = to.GetStream(); | |
var buffer = new byte[131072]; | |
try | |
{ | |
int len; | |
do | |
{ | |
len = await fromStream.ReadAsync(buffer, 0, buffer.Length); | |
if (len > 0) | |
{ | |
var newBytes = new byte[len]; | |
Buffer.BlockCopy(buffer, 0, newBytes, 0, len); | |
newBytes = await readFunction(newBytes); | |
await toStream.WriteAsync(newBytes, 0, newBytes.Length); | |
} | |
} while (len > 0); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine(e.ToString()); | |
} | |
try | |
{ | |
to.Dispose(); | |
} catch { } | |
} | |
var aes = Aes.Create(); | |
byte[] ParseHexString(string s) | |
{ | |
var str = s.Trim(); | |
var rv = new byte[str.Length / 2]; | |
for (int i = 0; i < str.Length; i += 2) | |
{ | |
rv[i / 2] = byte.Parse(str.Substring(i, 2), NumberStyles.HexNumber); | |
} | |
return rv; | |
} | |
string MakeHexString(byte[] array) | |
{ | |
var sb = new StringBuilder(); | |
foreach (var x in array) | |
{ | |
sb.Append($"{x:x2}"); | |
} | |
return sb.ToString(); | |
} | |
Task<byte[]> InterceptPacket(byte[] buffer) | |
{ | |
var asString = Encoding.UTF8.GetString(buffer).TrimEnd('\0', '\n'); | |
if (asString.Contains("<LSX>")) | |
{ | |
var xmlDocument = XDocument.Parse(asString); | |
var challengeNode = xmlDocument.Descendants("ChallengeAccepted"); | |
if (challengeNode.Any()) | |
{ | |
var entry = challengeNode.First(); | |
var data = entry.Attribute("response").Value; | |
var keySeed = | |
(((byte)data[0]) << 8) | | |
(((byte)data[1])); | |
var cRandom = new CRandom(); | |
cRandom.Seed(7); | |
cRandom.Seed((uint)(cRandom.Rand() + keySeed)); | |
var key = new byte[16]; | |
for (int i = 0; i < 16; i++) | |
{ | |
key[i] = (byte)cRandom.Rand(); | |
} | |
aes.Key = key; | |
aes.Mode = CipherMode.ECB; | |
aes.Padding = PaddingMode.PKCS7; | |
} | |
} | |
else | |
{ | |
var inBytes = ParseHexString(asString); | |
var dec = aes.CreateDecryptor(); | |
var ms = new MemoryStream(); | |
using (CryptoStream cs = new CryptoStream(ms, dec, CryptoStreamMode.Write)) | |
{ | |
cs.Write(inBytes, 0, inBytes.Length); | |
cs.FlushFinalBlock(); | |
var bytes = ms.ToArray(); | |
var str = Encoding.UTF8.GetString(bytes); | |
var xd = XDocument.Parse(str); | |
Console.WriteLine(xd.ToString()); | |
// is this a querycontentresponse? | |
var qcr = xd.Descendants("QueryContentResponse"); | |
if (qcr.Any()) | |
{ | |
var response = qcr.First(); | |
response.Add(new XElement("Game", | |
new XAttribute("contentID", "Origin.OFR.50.0001744"), | |
new XAttribute("progressValue", "0"), | |
new XAttribute("state", "INSTALLED"), | |
new XAttribute("displayName", "i don't know what this is called as the crack is in italian"), // but it is a deluxe pack | |
new XAttribute("installedVersion", "1.0.0.0"), | |
new XAttribute("availableVersion", "1.0.0.0") | |
)); | |
response.Add(new XElement("Game", | |
new XAttribute("contentID", "Origin.OFR.50.0001746"), | |
new XAttribute("progressValue", "0"), | |
new XAttribute("state", "INSTALLED"), | |
new XAttribute("displayName", "this is even more italion and idfk"), // not a deluxe pack tho | |
new XAttribute("installedVersion", "1.0.0.0"), | |
new XAttribute("availableVersion", "1.0.0.0") | |
)); | |
var sb = new StringBuilder(); | |
var xw = XmlWriter.Create(sb, new XmlWriterSettings() | |
{ | |
OmitXmlDeclaration = true, | |
Indent = true, | |
IndentChars = " ", | |
NewLineChars = "\n" | |
}); | |
xd.Save(xw); | |
xw.Flush(); | |
var outStr = " " + sb.ToString().Replace("\n", "\n "); | |
var enc = aes.CreateEncryptor(); | |
var oms = new MemoryStream(); | |
using (CryptoStream ocs = new CryptoStream(oms, enc, CryptoStreamMode.Write)) | |
{ | |
var b = Encoding.UTF8.GetBytes(outStr); | |
ocs.Write(b, 0, b.Length); | |
ocs.FlushFinalBlock(); | |
var od = oms.ToArray(); | |
var oldBuffer = buffer; | |
buffer = Encoding.UTF8.GetBytes(MakeHexString(od)).Append((byte)0).ToArray(); | |
} | |
} | |
} | |
} | |
return Task.FromResult(buffer); | |
} | |
// game->ebisu thread | |
Task.Run(() => InterceptionStream(client, remoteClient, async (buffer) => | |
{ | |
Console.WriteLine($"game->ebisu: {buffer.Length}"); | |
return await InterceptPacket(buffer); | |
})); | |
// ebisu->game thread | |
Task.Run(() => InterceptionStream(remoteClient, client, async (buffer) => | |
{ | |
Console.WriteLine($"ebisu->game: {buffer.Length}"); | |
return await InterceptPacket(buffer); | |
})); | |
} | |
} | |
class CRandom | |
{ | |
private uint randSeed; | |
public void Seed(uint seed) | |
{ | |
randSeed = seed; | |
} | |
public int Rand() | |
{ | |
randSeed = randSeed * 214013 + 2531011; | |
return (int)((randSeed >> 16) & 0xFFFF); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, total noob, not a programmer and I have no idea what to do with this but I need help! I'm 90 hours in and for no reason at all the game wouldn't load my save, it says that I'm missing two dlc's. Please help me step by step and I'll build a shrine in your name