Skip to content

Instantly share code, notes, and snippets.

@Donaldduck8
Created April 24, 2024 22:33
Show Gist options
  • Save Donaldduck8/21e296a8d96b350339cb818f8e554915 to your computer and use it in GitHub Desktop.
Save Donaldduck8/21e296a8d96b350339cb818f8e554915 to your computer and use it in GitHub Desktop.
Automatic decryptor for packed Tyrone assemblies
using Mono.Cecil;
using Mono.Cecil.Cil;
void Main()
{
var assembly = Assembly.LoadFile(@"C:\Users\Donald\Desktop\bf8d6a6c87df124721dc95f7420c67d15668a14865d5719505737e8d78bb335c.exe_Dumps\3.bin");
var assemblyDef = AssemblyDefinition.ReadAssembly(@"C:\Users\Donald\Desktop\bf8d6a6c87df124721dc95f7420c67d15668a14865d5719505737e8d78bb335c.exe_Dumps\3.bin");
string[] resourceNames = assemblyDef.MainModule.Resources.Select(resource => resource.Name.Split(".").FirstOrDefault()).ToArray();
uint[] tokens = new uint[]{
0x06000004,
0x06000005,
0x06000006,
0x06000007,
0x06000008
};
Dictionary<uint, MethodInfo> decryptionFunctions = new Dictionary<uint, System.Reflection.MethodInfo>();
foreach (uint token in tokens)
{
decryptionFunctions.Add(new MetadataToken(token).RID, GetStringDecryptionMethod(assembly, (int)token));
}
(var resourceNameField, var resourceName) = GetResourceNameField(assemblyDef, decryptionFunctions, resourceNames);
var xorKeyField = GetXORKeyField(assemblyDef, resourceNameField);
var xorKey = GetXORKey(assemblyDef, decryptionFunctions, xorKeyField);
var resourceIndex = assemblyDef.MainModule.Resources.Select(resource => resource.Name).ToList().IndexOf(resourceName + ".resources");
var resource = (EmbeddedResource) assemblyDef.MainModule.Resources.ElementAt(resourceIndex);
var resourceStream = resource.GetResourceStream();
var reader = new ResourceReader(resourceStream);
reader.GetResourceData(resourceName, out var _, out byte[] resourceData);
// The first 4 bytes are just the length
resourceData = resourceData.Skip(4).ToArray();
byte[] decryptedResource = xor(resourceData, xorKey);
Console.WriteLine(decryptedResource);
}
public static byte[] xor(byte[] ct, string key)
{
byte[] array = Encoding.ASCII.GetBytes(key);
for (int i = 0; i <= ct.Length; i++) {
ct[i % ct.Length] = Convert.ToByte((Convert.ToInt32((int)(ct[i % ct.Length] ^ array[i % array.Length])) - Convert.ToInt32(ct[(i + 1) % ct.Length]) +256) % 256);
}
Array.Resize<byte>(ref ct, ct.Length - 1);
return ct;
}
String GetXORKey(AssemblyDefinition assemblyDef, Dictionary<uint, MethodInfo> decryptionFunctions, FieldDefinition xorKeyField)
{
foreach (var instruction in GetAllInstructions(assemblyDef))
{
if (instruction.OpCode == OpCodes.Stsfld && instruction.Operand is FieldDefinition)
{
var operand = (FieldDefinition)instruction.Operand;
if (operand.MetadataToken.RID == xorKeyField.MetadataToken.RID)
{
var call = instruction.Previous;
Debug.Assert(OpCodes.Call == call.OpCode);
Debug.Assert(call.Operand is MethodReference);
var ldc = call.Previous;
Debug.Assert(OpCodes.Ldc_I4 == ldc.OpCode);
return decryptWrapper(decryptionFunctions, ldc, call);
}
}
}
return null;
}
FieldDefinition GetXORKeyField(AssemblyDefinition assemblyDef, FieldDefinition resourceNameField)
{
foreach (var instruction in GetAllInstructions(assemblyDef))
{
if (instruction.OpCode == OpCodes.Ldsfld && instruction.Operand is FieldDefinition)
{
var operand = (FieldDefinition)instruction.Operand;
if (operand.MetadataToken.RID == resourceNameField.MetadataToken.RID)
{
var next_ldsfld_instruction = instruction.Next.Next;
Debug.Assert(next_ldsfld_instruction.OpCode == OpCodes.Ldsfld);
Debug.Assert(next_ldsfld_instruction.Operand is FieldDefinition);
var other_field = (FieldDefinition)next_ldsfld_instruction.Operand;
return other_field;
}
}
}
return null;
}
(FieldDefinition, String) GetResourceNameField(AssemblyDefinition assemblyDef, Dictionary<uint, MethodInfo> decryptionFunctions, string[] resourceNames)
{
foreach (var instruction in GetAllInstructions(assemblyDef)) {
if (instruction.OpCode == OpCodes.Call && instruction.Operand is MethodReference)
{
var methodRef = (MethodReference)instruction.Operand;
if (methodRef is GenericInstanceMethod)
{
methodRef = methodRef.GetElementMethod();
}
if (decryptionFunctions.ContainsKey(methodRef.MetadataToken.RID))
{
var ldc = instruction.Previous;
Debug.Assert(OpCodes.Ldc_I4 == ldc.OpCode);
var decrypted_string = decryptWrapper(decryptionFunctions, ldc, instruction);
if (resourceNames.Contains(decrypted_string))
{
var stsfld = instruction.Next;
Debug.Assert(OpCodes.Stsfld == stsfld.OpCode);
var resource_name_field = stsfld.Operand;
return ((FieldDefinition) resource_name_field, decrypted_string);
}
}
}
}
return (null, null);
}
String decryptWrapper(Dictionary<uint, MethodInfo> decryptionFunctions, Instruction ldc, Instruction call)
{
var methodRef = (MethodReference)call.Operand;
if (methodRef is GenericInstanceMethod)
{
methodRef = methodRef.GetElementMethod();
}
var argument = ldc.Operand;
var uint_arg = (uint)(int)argument;
if (!decryptionFunctions.TryGetValue(methodRef.MetadataToken.RID, out var decryptionFunction))
{
throw new Exception();
}
try
{
return Decrypt(decryptionFunction, uint_arg);
}
catch (Exception e)
{
Console.WriteLine($"Method: {methodRef.MetadataToken.RID + 0x06000000:X}, Value: {uint_arg}");
throw(e);
}
}
IEnumerable<Instruction> GetAllInstructions(AssemblyDefinition assemblyDef, bool nonEmpty = true)
{
foreach (var type in assemblyDef.MainModule.Types)
{
foreach (var method in type.Methods)
{
if (nonEmpty && !method.HasBody)
{
continue;
}
foreach (var instruction in method.Body.Instructions)
{
yield return instruction;
}
}
}
}
MethodInfo GetStringDecryptionMethod(Assembly assembly, int token)
{
var MethodProto = assembly.Modules.First().ResolveMethod(token);
var MethodInfo = (MethodInfo)MethodProto;
var Method = MethodInfo.MakeGenericMethod(new Type[] { typeof(string) });
return Method;
}
string Decrypt(MethodInfo method, UInt32 parameter)
{
return (string) method.Invoke(null, new object[] { parameter });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment