Skip to content

Instantly share code, notes, and snippets.

@nta
Created April 10, 2017 11:31
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nta/ad7ad4b3399e781200817d231788df4d to your computer and use it in GitHub Desktop.
Save nta/ad7ad4b3399e781200817d231788df4d to your computer and use it in GitHub Desktop.
Mass Effect: Andromeda - DLC 'unlock'
// 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);
}
}
}
@default36
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment