:fortelove:
This commit is contained in:
18 files changed
+561
-232
No files matched your search
@@ -129,7 +129,7 @@ namespace Reactor.Greenhouse
|
||||
foreach (var nested in type.Nested)
|
||||
{
|
||||
var nestedDef = typeDef.NestedTypes.Single(t =>
|
||||
TestType(type, t, mappings) &&
|
||||
TestType(nested, t, mappings) &&
|
||||
nested.Original.Index == null || typeDef.NestedTypes.IndexOf(t) == nested.Original.Index
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Mono.Cecil;
|
||||
|
||||
@@ -24,5 +26,15 @@ namespace Reactor.Greenhouse
|
||||
var offset = attribute.Fields.Single(x => x.Name == "Offset");
|
||||
return new System.ComponentModel.UInt32Converter().ConvertFrom(offset) as uint?;
|
||||
}
|
||||
|
||||
private static readonly Stopwatch _stopwatch = new Stopwatch();
|
||||
|
||||
public static TimeSpan Time(this Action action)
|
||||
{
|
||||
_stopwatch.Restart();
|
||||
action();
|
||||
_stopwatch.Stop();
|
||||
return _stopwatch.Elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Rocks;
|
||||
|
||||
namespace Reactor.Greenhouse.Generation
|
||||
{
|
||||
public class GenerationContext
|
||||
{
|
||||
public ModuleDefinition CleanModule { get; }
|
||||
public ModuleDefinition ObfuscatedModule { get; }
|
||||
|
||||
public IEnumerable<TypeDefinition> AllCleanTypes { get; }
|
||||
public IEnumerable<TypeDefinition> AllObfuscatedTypes { get; }
|
||||
|
||||
public Dictionary<TypeDefinition, TypeContext> Map { get; } = new Dictionary<TypeDefinition, TypeContext>();
|
||||
|
||||
public GenerationContext(ModuleDefinition cleanModule, ModuleDefinition obfuscatedModule)
|
||||
{
|
||||
CleanModule = cleanModule;
|
||||
ObfuscatedModule = obfuscatedModule;
|
||||
|
||||
AllCleanTypes = CleanModule.GetAllTypes();
|
||||
AllObfuscatedTypes = ObfuscatedModule.GetAllTypes();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
using System;
|
||||
using Mono.Cecil;
|
||||
using Reactor.OxygenFilter;
|
||||
|
||||
namespace Reactor.Greenhouse.Generation
|
||||
{
|
||||
public static class Generator
|
||||
{
|
||||
public static TypeAttributes IgnoreVisibility(this TypeAttributes typeAttributes)
|
||||
{
|
||||
return typeAttributes & ~TypeAttributes.VisibilityMask;
|
||||
}
|
||||
|
||||
public static FieldAttributes IgnoreVisibility(this FieldAttributes fieldAttributes)
|
||||
{
|
||||
return fieldAttributes & ~FieldAttributes.FieldAccessMask;
|
||||
}
|
||||
|
||||
public static MethodAttributes IgnoreVisibility(this MethodAttributes methodAttributes)
|
||||
{
|
||||
return methodAttributes & ~MethodAttributes.MemberAccessMask;
|
||||
}
|
||||
|
||||
private static bool IsAssemblyCSharp(this IMetadataScope scope)
|
||||
{
|
||||
return scope.Name != "Assembly-CSharp.dll";
|
||||
}
|
||||
|
||||
public static Mappings Generate(GenerationContext context)
|
||||
{
|
||||
var result = new Mappings();
|
||||
|
||||
var lookupTypes = Extensions.Time(() =>
|
||||
{
|
||||
LookupTypes(context);
|
||||
});
|
||||
|
||||
Console.WriteLine("LookupTypes took " + lookupTypes);
|
||||
|
||||
foreach (var (obfuscatedType, typeContext) in context.Map)
|
||||
{
|
||||
var mappedType = typeContext.ToMappedType(obfuscatedType);
|
||||
if (mappedType == null)
|
||||
continue;
|
||||
|
||||
result.Types.Add(mappedType);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool TestEnum(TypeDefinition cleanType, TypeDefinition obfuscatedType)
|
||||
{
|
||||
if (!obfuscatedType.IsEnum)
|
||||
return false;
|
||||
|
||||
if (cleanType.Fields.Count != obfuscatedType.Fields.Count)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < cleanType.Fields.Count; i++)
|
||||
{
|
||||
var cleanField = cleanType.Fields[i];
|
||||
var obfuscatedField = obfuscatedType.Fields[i];
|
||||
|
||||
if (cleanField.Name != obfuscatedField.Name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cleanField.HasConstant && !cleanField.Constant.Equals(obfuscatedField.Constant))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static double TestField(FieldDefinition cleanField, FieldDefinition obfuscatedField)
|
||||
{
|
||||
var points = 0d;
|
||||
|
||||
if (cleanField.Attributes.IgnoreVisibility() != obfuscatedField.Attributes.IgnoreVisibility())
|
||||
{
|
||||
points -= 1;
|
||||
}
|
||||
|
||||
if (cleanField.HasConstant)
|
||||
{
|
||||
points += cleanField.Constant.Equals(obfuscatedField.Constant) ? 1 : -1;
|
||||
}
|
||||
|
||||
if (cleanField.Name == obfuscatedField.Name)
|
||||
{
|
||||
points += 1;
|
||||
}
|
||||
|
||||
if (cleanField.FieldType.FullName == obfuscatedField.FieldType.FullName)
|
||||
{
|
||||
points += 1;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static double TestMethod(MethodDefinition cleanMethod, MethodDefinition obfuscatedMethod)
|
||||
{
|
||||
var points = 0d;
|
||||
|
||||
if (cleanMethod.Name == obfuscatedMethod.Name)
|
||||
{
|
||||
points += 1;
|
||||
}
|
||||
|
||||
if (cleanMethod.ReturnType.FullName == obfuscatedMethod.ReturnType.FullName)
|
||||
{
|
||||
points += cleanMethod.ReturnType.FullName == "System.Void" ? 0.5 : 1;
|
||||
}
|
||||
else if (cleanMethod.ReturnType.Scope.IsAssemblyCSharp())
|
||||
{
|
||||
points -= 1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < cleanMethod.Parameters.Count; i++)
|
||||
{
|
||||
var cleanParameter = cleanMethod.Parameters[i];
|
||||
|
||||
if (obfuscatedMethod.Parameters.Count <= i)
|
||||
{
|
||||
points -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
var obfuscatedParameter = obfuscatedMethod.Parameters[i];
|
||||
|
||||
if (cleanParameter.ParameterType.FullName == obfuscatedParameter.ParameterType.FullName)
|
||||
{
|
||||
points += 1;
|
||||
}
|
||||
else if (cleanParameter.ParameterType.Scope.IsAssemblyCSharp())
|
||||
{
|
||||
points -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (obfuscatedMethod.Parameters.Count > cleanMethod.Parameters.Count)
|
||||
{
|
||||
points -= obfuscatedMethod.Parameters.Count - cleanMethod.Parameters.Count;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static double TestType(TypeDefinition cleanType, TypeDefinition obfuscatedType)
|
||||
{
|
||||
if (cleanType.Name.StartsWith("<"))
|
||||
return 0;
|
||||
|
||||
if (cleanType.Attributes.IgnoreVisibility() != obfuscatedType.Attributes.IgnoreVisibility())
|
||||
return 0;
|
||||
|
||||
if (cleanType.IsEnum)
|
||||
{
|
||||
return TestEnum(cleanType, obfuscatedType) ? double.MaxValue : 0;
|
||||
}
|
||||
|
||||
if (cleanType.BaseType != null && obfuscatedType.BaseType != null && cleanType.BaseType.FullName != obfuscatedType.BaseType.FullName)
|
||||
{
|
||||
if (cleanType.BaseType.Scope.IsAssemblyCSharp() && !obfuscatedType.BaseType.Name.IsObfuscated())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
var points = 0d;
|
||||
|
||||
// this will only work with up to date mono dll (:fortelove:)
|
||||
if (obfuscatedType.Fields.Count != cleanType.Fields.Count || obfuscatedType.Properties.Count != cleanType.Properties.Count || obfuscatedType.NestedTypes.Count != cleanType.NestedTypes.Count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (var i = 0; i < cleanType.Fields.Count; i++)
|
||||
{
|
||||
var cleanField = cleanType.Fields[i];
|
||||
|
||||
if (obfuscatedType.Fields.Count <= i)
|
||||
{
|
||||
points -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
var obfuscatedField = obfuscatedType.Fields[i];
|
||||
|
||||
points += TestField(cleanField, obfuscatedField);
|
||||
}
|
||||
|
||||
if (obfuscatedType.Fields.Count > cleanType.Fields.Count)
|
||||
{
|
||||
points -= obfuscatedType.Fields.Count - cleanType.Fields.Count;
|
||||
}
|
||||
|
||||
foreach (var cleanMethod in cleanType.Methods)
|
||||
{
|
||||
var winnerPoints = 0d;
|
||||
|
||||
foreach (var obfuscatedMethod in obfuscatedType.Methods)
|
||||
{
|
||||
var methodPoints = TestMethod(cleanMethod, obfuscatedMethod);
|
||||
|
||||
if (methodPoints > winnerPoints && methodPoints >= 1)
|
||||
{
|
||||
winnerPoints = methodPoints;
|
||||
}
|
||||
}
|
||||
|
||||
if (winnerPoints > 0)
|
||||
{
|
||||
points += winnerPoints;
|
||||
}
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static void LookupTypes(GenerationContext context)
|
||||
{
|
||||
foreach (var cleanType in context.AllCleanTypes)
|
||||
{
|
||||
if (cleanType.Name.StartsWith("<"))
|
||||
continue;
|
||||
|
||||
TypeDefinition winner = null;
|
||||
var winnerPoints = 0d;
|
||||
|
||||
foreach (var obfuscatedType in context.AllObfuscatedTypes)
|
||||
{
|
||||
if (obfuscatedType.Name.StartsWith("<") && obfuscatedType.Name.EndsWith(">"))
|
||||
continue;
|
||||
|
||||
var points = TestType(cleanType, obfuscatedType);
|
||||
|
||||
if (points > winnerPoints)
|
||||
{
|
||||
winnerPoints = points;
|
||||
winner = obfuscatedType;
|
||||
}
|
||||
}
|
||||
|
||||
if (winnerPoints != 0 && winner != null)
|
||||
{
|
||||
var typeContext = new TypeContext(context, winnerPoints, cleanType);
|
||||
if (!context.Map.TryAdd(winner, typeContext))
|
||||
{
|
||||
Console.WriteLine($"{winner.FullName} = {cleanType.FullName} - {winnerPoints}");
|
||||
|
||||
var points = context.Map[winner].Points;
|
||||
if (points.Equals(winnerPoints))
|
||||
{
|
||||
Console.WriteLine("Warning: duplicate, remove all");
|
||||
context.Map.Remove(winner);
|
||||
}
|
||||
else if (winnerPoints >= points)
|
||||
{
|
||||
Console.WriteLine("Warning: duplicate, replace");
|
||||
context.Map[winner] = typeContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: duplicate, skip");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Rocks;
|
||||
using Reactor.OxygenFilter;
|
||||
|
||||
namespace Reactor.Greenhouse.Generation
|
||||
{
|
||||
public class TypeContext
|
||||
{
|
||||
public GenerationContext Context { get; }
|
||||
public double Points { get; }
|
||||
public TypeDefinition CleanType { get; }
|
||||
|
||||
public string CleanFullName => CleanType.FullName;
|
||||
|
||||
public TypeContext(GenerationContext context, double points, TypeDefinition cleanType)
|
||||
{
|
||||
Context = context;
|
||||
Points = points;
|
||||
CleanType = cleanType;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return CleanFullName;
|
||||
}
|
||||
|
||||
private static readonly Regex CompilerGeneratedRegex = new Regex(@"^<([\w\d]+)>.__\d+$", RegexOptions.Compiled);
|
||||
|
||||
public MappedType ToMappedType(TypeDefinition obfuscatedType)
|
||||
{
|
||||
var mappedType = new MappedType(obfuscatedType.FullName, CleanType.Name);
|
||||
|
||||
for (var i = 0; i < CleanType.Fields.Count; i++)
|
||||
{
|
||||
var cleanField = CleanType.Fields[i];
|
||||
var obfuscatedField = obfuscatedType.Fields[i];
|
||||
|
||||
if (!obfuscatedField.Name.IsObfuscated())
|
||||
continue;
|
||||
|
||||
mappedType.Fields.Add(new MappedMember(obfuscatedField.Name, cleanField.Name));
|
||||
}
|
||||
|
||||
for (var i = 0; i < CleanType.Properties.Count; i++)
|
||||
{
|
||||
var cleanProperty = CleanType.Properties[i];
|
||||
var obfuscatedProperty = obfuscatedType.Properties[i];
|
||||
|
||||
if (!obfuscatedProperty.Name.IsObfuscated())
|
||||
continue;
|
||||
|
||||
mappedType.Properties.Add(new MappedMember(obfuscatedProperty.Name, cleanProperty.Name));
|
||||
}
|
||||
|
||||
foreach (var cleanMethod in CleanType.GetMethods())
|
||||
{
|
||||
var matching = new List<MethodDefinition>();
|
||||
|
||||
foreach (var obfuscatedMethod in obfuscatedType.GetMethods())
|
||||
{
|
||||
if (cleanMethod.ReturnType.FullName != obfuscatedMethod.ReturnType.FullName)
|
||||
continue;
|
||||
|
||||
if (cleanMethod.Attributes.IgnoreVisibility() != obfuscatedMethod.Attributes.IgnoreVisibility())
|
||||
continue;
|
||||
|
||||
if (cleanMethod.Parameters.Count != obfuscatedMethod.Parameters.Count)
|
||||
continue;
|
||||
|
||||
var validParameters = true;
|
||||
|
||||
for (var i = 0; i < cleanMethod.Parameters.Count; i++)
|
||||
{
|
||||
var cleanParameter = cleanMethod.Parameters[i];
|
||||
var obfuscatedParameter = obfuscatedMethod.Parameters[i];
|
||||
|
||||
var obfuscatedParameterContext = Context.Map.SingleOrDefault(x => x.Key.FullName == obfuscatedParameter.ParameterType.FullName).Value;
|
||||
|
||||
if (cleanParameter.ParameterType.FullName != (obfuscatedParameterContext == null ? obfuscatedParameter.ParameterType.FullName : obfuscatedParameterContext.CleanFullName))
|
||||
{
|
||||
validParameters = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validParameters)
|
||||
continue;
|
||||
|
||||
matching.Add(obfuscatedMethod);
|
||||
|
||||
if (matching.Count > 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (matching.Count == 1)
|
||||
{
|
||||
var matched = matching.Single();
|
||||
|
||||
mappedType.Methods.Add(new MappedMethod(new OriginalDescriptor
|
||||
{
|
||||
Name = matched.Name,
|
||||
Signature = matched.GetSignature()
|
||||
}, cleanMethod.Name));
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < CleanType.NestedTypes.Count; i++)
|
||||
{
|
||||
var cleanNested = CleanType.NestedTypes[i];
|
||||
var obfuscatedNested = obfuscatedType.NestedTypes[i];
|
||||
|
||||
if (cleanNested.Fields.Count != obfuscatedNested.Fields.Count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var match = CompilerGeneratedRegex.Match(cleanNested.Name);
|
||||
|
||||
var nested = new MappedType(obfuscatedNested.FullName, match.Success ? (match.Groups[1].Value + "__d") : cleanNested.Name.Replace("<>", ""));
|
||||
|
||||
foreach (var nestedField in obfuscatedNested.Fields)
|
||||
{
|
||||
switch (nestedField.Name)
|
||||
{
|
||||
case "<>1__state":
|
||||
nested.Fields.Add(new MappedMember(nestedField.Name, "__state"));
|
||||
continue;
|
||||
case "<>2__current":
|
||||
nested.Fields.Add(new MappedMember(nestedField.Name, "__current"));
|
||||
continue;
|
||||
case "<>4__this":
|
||||
nested.Fields.Add(new MappedMember(nestedField.Name, "__this"));
|
||||
continue;
|
||||
}
|
||||
|
||||
var fieldMatch = CompilerGeneratedRegex.Match(nestedField.Name);
|
||||
|
||||
if (fieldMatch.Success)
|
||||
{
|
||||
nested.Fields.Add(new MappedMember(nestedField.Name, fieldMatch.Groups[1].Value));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var nestedMethod in obfuscatedNested.Methods)
|
||||
{
|
||||
var methodMatch = CompilerGeneratedRegex.Match(nestedMethod.Name);
|
||||
|
||||
if (methodMatch.Success)
|
||||
{
|
||||
nested.Methods.Add(new MappedMethod(new OriginalDescriptor
|
||||
{
|
||||
Name = nestedMethod.Name,
|
||||
Signature = nestedMethod.GetSignature()
|
||||
}, methodMatch.Groups[1].Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (!obfuscatedNested.Name.IsObfuscated() && nested.Mapped == cleanNested.Name && !nested.Fields.Any() && !nested.Methods.Any())
|
||||
continue;
|
||||
|
||||
mappedType.Nested.Add(nested);
|
||||
}
|
||||
|
||||
if (!obfuscatedType.Name.IsObfuscated() && !mappedType.Fields.Any() && !mappedType.Methods.Any() && !mappedType.Properties.Any() && !mappedType.Nested.Any())
|
||||
return null;
|
||||
|
||||
return mappedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Rocks;
|
||||
using Reactor.OxygenFilter;
|
||||
|
||||
namespace Reactor.Greenhouse
|
||||
{
|
||||
public static class Generator
|
||||
{
|
||||
private static TypeAttributes IgnoreVisibility(this TypeAttributes typeAttributes)
|
||||
{
|
||||
return typeAttributes & ~TypeAttributes.VisibilityMask;
|
||||
}
|
||||
|
||||
public static Mappings Generate(ModuleDefinition old, ModuleDefinition latest)
|
||||
{
|
||||
var matches = new Dictionary<TypeDefinition, SortedList<double, TypeDefinition>>();
|
||||
|
||||
var result = new Mappings();
|
||||
|
||||
foreach (var oldType in old.GetAllTypes())
|
||||
{
|
||||
if (oldType.Name.StartsWith("<") || oldType.Namespace.StartsWith("GoogleMobileAds"))
|
||||
continue;
|
||||
|
||||
var list = new SortedList<double, TypeDefinition>(Comparer<double>.Create((x, y) => y.CompareTo(x)));
|
||||
matches[oldType] = list;
|
||||
|
||||
var exact = latest.GetAllTypes().FirstOrDefault(x => x.FullName == oldType.FullName);
|
||||
if (exact != null)
|
||||
{
|
||||
list.Add(double.MaxValue, exact);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oldType.IsEnum)
|
||||
{
|
||||
var first = oldType.Fields.Select(x => x.Name).ToArray();
|
||||
var type = latest.GetAllTypes().SingleOrDefault(x => x.IsEnum && x.Fields.Select(f => f.Name).SequenceEqual(first));
|
||||
if (type != null)
|
||||
{
|
||||
list.Add(double.MaxValue, type);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
static bool Test(TypeReference typeReference)
|
||||
{
|
||||
return typeReference.IsGenericParameter || typeReference.Namespace != string.Empty || !typeReference.Name.IsObfuscated();
|
||||
}
|
||||
|
||||
var methodNames = oldType.GetMethods().Select(x => x.Name).ToArray();
|
||||
var fieldNames = oldType.Fields.Select(x => x.Name).ToArray();
|
||||
var propertyNames = oldType.Properties.Select(x => x.Name).ToArray();
|
||||
|
||||
var methodSignatures = oldType.GetMethods().Where(x => Test(x.ReturnType) && x.Parameters.All(p => Test(p.ParameterType))).Select(x => x.GetSignature()).ToArray();
|
||||
var fieldSignatures = oldType.Fields.Where(x => Test(x.FieldType) && (!x.FieldType.HasGenericParameters || x.FieldType.GenericParameters.All(Test))).Select(x => x.GetSignature()).ToArray();
|
||||
|
||||
var types = latest.GetAllTypes()
|
||||
.Where(t => t.Attributes.IgnoreVisibility() == oldType.Attributes.IgnoreVisibility())
|
||||
.ToArray();
|
||||
|
||||
foreach (var t in types)
|
||||
{
|
||||
var points = 0d;
|
||||
points += t.GetMethods().Count(m => !m.Name.IsObfuscated() && methodNames.Contains(m.Name));
|
||||
points += t.Fields.Count(f => !f.Name.IsObfuscated() && fieldNames.Contains(f.Name)) * 2d;
|
||||
points += t.Properties.Count(p => propertyNames.Contains((p.GetMethod?.Name ?? p.SetMethod.Name).Substring(4))) * 2d;
|
||||
|
||||
var fieldSignaturesPoints = fieldSignatures.Count(s => t.Fields.Any(f => f.GetSignature().ToString() == s.ToString()));
|
||||
points += Math.Max(0, fieldSignaturesPoints - Math.Abs(t.Fields.Count - fieldSignaturesPoints)) / 2d;
|
||||
|
||||
var methodSignaturesPoints = methodSignatures.Count(s => t.GetMethods().Any(m => m.GetSignature().ToString() == s.ToString()));
|
||||
points += Math.Max(0, methodSignaturesPoints - Math.Abs(t.GetMethods().Count() - methodSignaturesPoints) / 2d) / 2d;
|
||||
|
||||
if (points != 0)
|
||||
{
|
||||
list.TryAdd(points, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (oldType, list) in matches)
|
||||
{
|
||||
foreach (var (points, type) in list)
|
||||
{
|
||||
if (matches.Where(x => x.Key != oldType).SelectMany(x => x.Value).Any(x => x.Value == type && x.Key > points))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list.Clear();
|
||||
list.Add(double.MaxValue, type);
|
||||
|
||||
var mapped = new MappedType(new OriginalDescriptor { Name = type.FullName }, oldType.Name);
|
||||
|
||||
var i = 0;
|
||||
foreach (var field in type.Fields)
|
||||
{
|
||||
var j = 0;
|
||||
var i1 = i;
|
||||
var oldFields = oldType.Fields.Where(x => j++ == i1 && x.GetSignature().ToString() == field.GetSignature().ToString()).ToArray();
|
||||
if (oldFields.Length == 1)
|
||||
{
|
||||
var oldField = oldFields.First();
|
||||
if (oldField.Name == field.Name || !field.Name.IsObfuscated())
|
||||
continue;
|
||||
|
||||
mapped.Fields.Add(new MappedMember(new OriginalDescriptor { Index = i1 }, oldField.Name));
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
foreach (var method in type.Methods)
|
||||
{
|
||||
if (!method.HasParameters || method.IsSetter || method.IsGetter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var oldMethods = oldType.Methods.Where(x => x.Name == method.Name && x.Parameters.Count == method.Parameters.Count).ToArray();
|
||||
if (oldMethods.Length != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var oldMethod = oldMethods.Single();
|
||||
|
||||
var oldParameters = oldMethod.Parameters.Select(x => x.Name).ToList();
|
||||
|
||||
if (method.Parameters.Select(x => x.Name).SequenceEqual(oldParameters))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mapped.Methods.Add(new MappedMethod(new OriginalDescriptor { Name = method.Name, Signature = method.GetSignature() }, null)
|
||||
{
|
||||
Parameters = oldParameters
|
||||
});
|
||||
}
|
||||
|
||||
if (type.Name == oldType.Name || (!type.Name.IsObfuscated() && !mapped.Fields.Any() && !mapped.Methods.Any()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result.Types.Add(mapped);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Submodule Reactor.Greenhouse/Mappings updated: b127276f6a...a2ac4373f2.
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||
using Mono.Cecil;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Reactor.Greenhouse.Generation;
|
||||
using Reactor.Greenhouse.Setup;
|
||||
using Reactor.Greenhouse.Setup.Provider;
|
||||
using Reactor.OxygenFilter;
|
||||
@@ -45,8 +46,9 @@ namespace Reactor.Greenhouse
|
||||
ContractResolver = ShouldSerializeContractResolver.Instance,
|
||||
};
|
||||
|
||||
Console.WriteLine($"Generating mappings from {gameManager.PreObfuscation.Name} ({gameManager.PreObfuscation.Version})");
|
||||
using var old = ModuleDefinition.ReadModule(File.OpenRead(gameManager.PreObfuscation.Dll));
|
||||
var oldFile = Path.Combine("work", "Assembly-CSharp-2020.12.9s.dll");
|
||||
Console.WriteLine($"Generating mappings from {oldFile}");
|
||||
using var cleanModule = ModuleDefinition.ReadModule(File.OpenRead(oldFile));
|
||||
|
||||
if (!steam && !itch)
|
||||
{
|
||||
@@ -56,16 +58,18 @@ namespace Reactor.Greenhouse
|
||||
|
||||
if (steam)
|
||||
{
|
||||
await GenerateAsync(gameManager.Steam, old);
|
||||
await GenerateAsync(gameManager.Steam, cleanModule);
|
||||
}
|
||||
|
||||
if (itch)
|
||||
{
|
||||
await GenerateAsync(gameManager.Itch, old);
|
||||
await GenerateAsync(gameManager.Itch, cleanModule);
|
||||
}
|
||||
|
||||
new OxygenFilter.OxygenFilter().Start(File.ReadAllText(Path.Combine("bin", "2020.12.9s.json")), new FileInfo(gameManager.Steam.Dll), new FileInfo("test.dll"));
|
||||
}
|
||||
|
||||
private static async Task GenerateAsync(Game game, ModuleDefinition old)
|
||||
private static async Task GenerateAsync(Game game, ModuleDefinition cleanModule)
|
||||
{
|
||||
Console.WriteLine($"Compiling mappings for {game.Name} ({game.Version})");
|
||||
|
||||
@@ -73,7 +77,7 @@ namespace Reactor.Greenhouse
|
||||
var version = game.Version;
|
||||
var postfix = game.Postfix;
|
||||
|
||||
var generated = Generator.Generate(old, moduleDef);
|
||||
var generated = Generator.Generate(new GenerationContext(cleanModule, moduleDef));
|
||||
|
||||
await File.WriteAllTextAsync(Path.Combine("work", version + postfix + ".generated.json"), JsonConvert.SerializeObject(generated, Formatting.Indented));
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<PackageReference Include="AngleSharp" Version="0.14.0" />
|
||||
<PackageReference Include="DepotDownloader.Library" Version="0.1.2" />
|
||||
<PackageReference Include="Iced" Version="1.10.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
||||
<ProjectReference Include="..\Reactor.OxygenFilter\Reactor.OxygenFilter.csproj" />
|
||||
|
||||
@@ -10,34 +10,25 @@ namespace Reactor.Greenhouse.Setup
|
||||
{
|
||||
public string WorkPath { get; }
|
||||
|
||||
public Game PreObfuscation { get; }
|
||||
public Game Steam { get; }
|
||||
public Game Itch { get; }
|
||||
|
||||
public GameManager()
|
||||
{
|
||||
WorkPath = Path.GetFullPath("work");
|
||||
PreObfuscation = new Game(new SteamProvider(true), "preobfuscation", Path.Combine(WorkPath, "preobfuscation"));
|
||||
Steam = new Game(new SteamProvider(false), "steam", Path.Combine(WorkPath, "steam"));
|
||||
Itch = new Game(new ItchProvider(), "itch", Path.Combine(WorkPath, "itch"));
|
||||
}
|
||||
|
||||
public async Task SetupAsync(bool setupSteam, bool setupItch)
|
||||
{
|
||||
var preObfuscation = PreObfuscation.Provider.IsUpdateNeeded();
|
||||
var steam = setupSteam && Steam.Provider.IsUpdateNeeded();
|
||||
var itch = setupItch && Itch.Provider.IsUpdateNeeded();
|
||||
|
||||
if (preObfuscation || steam || itch)
|
||||
if (steam || itch)
|
||||
{
|
||||
ContentDownloader.ShutdownSteam3();
|
||||
|
||||
if (preObfuscation)
|
||||
{
|
||||
await PreObfuscation.DownloadAsync();
|
||||
Console.WriteLine($"Downloaded {nameof(PreObfuscation)} ({PreObfuscation.Version})");
|
||||
}
|
||||
|
||||
if (steam)
|
||||
{
|
||||
await Steam.DownloadAsync();
|
||||
@@ -53,8 +44,6 @@ namespace Reactor.Greenhouse.Setup
|
||||
|
||||
ContentDownloader.ShutdownSteam3();
|
||||
|
||||
PreObfuscation.UpdateVersion();
|
||||
|
||||
if (setupSteam)
|
||||
{
|
||||
Steam.UpdateVersion();
|
||||
@@ -65,13 +54,6 @@ namespace Reactor.Greenhouse.Setup
|
||||
Itch.UpdateVersion();
|
||||
}
|
||||
|
||||
if (PreObfuscation.Version != "2020.9.9")
|
||||
{
|
||||
throw new ArgumentException("Pre obfuscation version is invalid");
|
||||
}
|
||||
|
||||
PreObfuscation.Dump();
|
||||
|
||||
if (setupSteam)
|
||||
{
|
||||
Steam.Dump();
|
||||
|
||||
@@ -8,8 +8,13 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
public static class Context
|
||||
{
|
||||
// Path#Combine is borken on visual studio
|
||||
public static string DataPath { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + Path.DirectorySeparatorChar + ".reactor";
|
||||
public static string TempPath { get; } = Path.Combine(DataPath, "temp");
|
||||
public static string RootPath { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + Path.DirectorySeparatorChar + ".reactor";
|
||||
public static string TempPath { get; } = Path.Combine(RootPath, "tmp");
|
||||
public static string DataPath => RootPath + Path.DirectorySeparatorChar + GameVersion;
|
||||
public static string MappedPath => DataPath + Path.DirectorySeparatorChar + ComputeHash(MappingsJson);
|
||||
|
||||
public static string GameVersion { get; internal set; }
|
||||
public static string MappingsJson { get; internal set; }
|
||||
|
||||
public static string ComputeHash(FileInfo file)
|
||||
{
|
||||
@@ -18,7 +23,7 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
|
||||
var hash = md5.ComputeHash(assemblyStream);
|
||||
|
||||
return Encoding.UTF8.GetString(hash);
|
||||
return ByteArrayToString(hash);
|
||||
}
|
||||
|
||||
public static string ComputeHash(string text)
|
||||
@@ -27,7 +32,18 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
|
||||
var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(text));
|
||||
|
||||
return Encoding.UTF8.GetString(hash);
|
||||
return ByteArrayToString(hash);
|
||||
}
|
||||
|
||||
public static string ByteArrayToString(byte[] data)
|
||||
{
|
||||
var builder = new StringBuilder(data.Length * 2);
|
||||
foreach (var b in data)
|
||||
{
|
||||
builder.AppendFormat("{0:x2}", b);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,12 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
[Required]
|
||||
public string[] Input { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Mappings { get; set; }
|
||||
|
||||
[Output]
|
||||
public string[] Deobfuscated { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var path = Path.Combine(Context.DataPath, "mapped");
|
||||
var path = Path.Combine(Context.MappedPath, "mapped");
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
@@ -34,10 +31,10 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
|
||||
var mappings = JsonConvert.DeserializeObject<Mappings>(Mappings);
|
||||
var mappings = JsonConvert.DeserializeObject<Mappings>(Context.MappingsJson);
|
||||
|
||||
var resolver = new DefaultAssemblyResolver();
|
||||
resolver.AddSearchDirectory(Path.Combine(Context.DataPath, "references"));
|
||||
resolver.AddSearchDirectory(Path.Combine(Context.MappedPath, "references"));
|
||||
resolver.AddSearchDirectory(Path.Combine(AmongUs, "BepInEx", "core"));
|
||||
resolver.AddSearchDirectory(Path.Combine(AmongUs, "BepInEx", "plugins"));
|
||||
resolver.AddSearchDirectory(Path.Combine(AmongUs, "BepInEx", "unhollowed"));
|
||||
|
||||
@@ -10,31 +10,29 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
[Required]
|
||||
public string AmongUs { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Mappings { get; set; }
|
||||
|
||||
[Output]
|
||||
public string ReferencesPath { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
ReferencesPath = Path.Combine(Context.DataPath, "references");
|
||||
ReferencesPath = Path.Combine(Context.MappedPath, "references");
|
||||
|
||||
Directory.CreateDirectory(Context.DataPath);
|
||||
Directory.CreateDirectory(Context.MappedPath);
|
||||
|
||||
var skip = true;
|
||||
|
||||
var gameAssemblyPath = Path.Combine(AmongUs, "GameAssembly.dll");
|
||||
var hash = Context.ComputeHash(new FileInfo(gameAssemblyPath));
|
||||
var hashPath = Path.Combine(Context.DataPath, "GameAssembly.dll.md5");
|
||||
var hashPath = Path.Combine(Context.MappedPath, "GameAssembly.dll.md5");
|
||||
|
||||
if (!File.Exists(hashPath) || hash != File.ReadAllText(hashPath))
|
||||
{
|
||||
skip = false;
|
||||
}
|
||||
|
||||
var mappingsHash = Context.ComputeHash(Mappings);
|
||||
var mappingsHashPath = Path.Combine(Context.DataPath, "mappings.md5");
|
||||
var mappingsHash = Context.ComputeHash(Context.MappingsJson);
|
||||
var mappingsHashPath = Path.Combine(Context.MappedPath, "mappings.md5");
|
||||
|
||||
if (!File.Exists(mappingsHashPath) || mappingsHash != File.ReadAllText(mappingsHashPath))
|
||||
{
|
||||
@@ -46,11 +44,6 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Directory.Exists(Context.TempPath))
|
||||
{
|
||||
Directory.Delete(Context.TempPath, true);
|
||||
}
|
||||
|
||||
var dumperConfig = new Il2CppDumper.Config
|
||||
{
|
||||
GenerateScript = false,
|
||||
@@ -62,7 +55,7 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
Il2CppDumper.Il2CppDumper.PerformDump(
|
||||
gameAssemblyPath,
|
||||
Path.Combine(AmongUs, "Among Us_Data", "il2cpp_data", "Metadata", "global-metadata.dat"),
|
||||
Context.TempPath, dumperConfig, _ =>
|
||||
Context.DataPath, dumperConfig, _ =>
|
||||
{
|
||||
}
|
||||
);
|
||||
@@ -71,8 +64,8 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
|
||||
var oxygenFilter = new OxygenFilter();
|
||||
|
||||
var dumpedDll = new FileInfo(Path.Combine(Context.TempPath, "DummyDll", "Assembly-CSharp.dll"));
|
||||
oxygenFilter.Start(Mappings, dumpedDll, dumpedDll);
|
||||
var dumpedDll = new FileInfo(Path.Combine(Context.DataPath, "DummyDll", "Assembly-CSharp.dll"));
|
||||
oxygenFilter.Start(Context.MappingsJson, dumpedDll, dumpedDll);
|
||||
|
||||
Log.LogMessage(MessageImportance.High, "Executing Il2CppUnhollower generator");
|
||||
|
||||
@@ -83,8 +76,8 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
{
|
||||
GameAssemblyPath = gameAssemblyPath,
|
||||
MscorlibPath = Path.Combine(AmongUs, "mono", "Managed", "mscorlib.dll"),
|
||||
SourceDir = Path.Combine(Context.TempPath, "DummyDll"),
|
||||
OutputDir = Path.Combine(Context.TempPath, "unhollowed"),
|
||||
SourceDir = Path.Combine(Context.DataPath, "DummyDll"),
|
||||
OutputDir = Path.Combine(Context.DataPath, "unhollowed"),
|
||||
UnityBaseLibsDir = Path.Combine(AmongUs, "BepInEx", "unity-libs"),
|
||||
NoCopyUnhollowerLibs = true
|
||||
};
|
||||
|
||||
@@ -14,14 +14,13 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
[Required]
|
||||
public string Mappings { get; set; }
|
||||
|
||||
[Output]
|
||||
public string MappingsJson { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
Context.GameVersion = GameVersion;
|
||||
|
||||
if (File.Exists(Mappings))
|
||||
{
|
||||
MappingsJson = File.ReadAllText(Mappings);
|
||||
Context.MappingsJson = File.ReadAllText(Mappings);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,14 +34,14 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
|
||||
if (File.Exists(file))
|
||||
{
|
||||
MappingsJson = File.ReadAllText(file);
|
||||
Context.MappingsJson = File.ReadAllText(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
var httpClient = new HttpClient();
|
||||
var json = httpClient.GetStringAsync($"https://github.com/{repo}/releases/download/{version}/{GameVersion}.json").GetAwaiter().GetResult();
|
||||
|
||||
MappingsJson = json;
|
||||
Context.MappingsJson = json;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -18,13 +18,11 @@
|
||||
</Target>
|
||||
|
||||
<Target Name="LoadMappings">
|
||||
<LoadMappings GameVersion="$(GameVersion)" Mappings="$(Mappings)">
|
||||
<Output TaskParameter="MappingsJson" PropertyName="MappingsJson" />
|
||||
</LoadMappings>
|
||||
<LoadMappings GameVersion="$(GameVersion)" Mappings="$(Mappings)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="GenerateReferences" BeforeTargets="PrepareForBuild" DependsOnTargets="LoadMappings">
|
||||
<GenerateReferences AmongUs="$(AmongUs)" Mappings="$(MappingsJson)">
|
||||
<GenerateReferences AmongUs="$(AmongUs)">
|
||||
<Output TaskParameter="ReferencesPath" PropertyName="ReferencesPath" />
|
||||
</GenerateReferences>
|
||||
|
||||
@@ -38,7 +36,7 @@
|
||||
</Target>
|
||||
|
||||
<Target Name="Deobfuscate" AfterTargets="GenerateReferences">
|
||||
<Deobfuscate AmongUs="$(AmongUs)" Input="@(Deobfuscate)" Mappings="$(MappingsJson)">
|
||||
<Deobfuscate AmongUs="$(AmongUs)" Input="@(Deobfuscate)">
|
||||
<Output TaskParameter="Deobfuscated" PropertyName="Deobfuscated" />
|
||||
</Deobfuscate>
|
||||
|
||||
@@ -48,6 +46,6 @@
|
||||
</Target>
|
||||
|
||||
<Target Name="Reobfuscate" AfterTargets="Build">
|
||||
<Reobfuscate GameVersion="$(GameVersion)" AmongUs="$(AmongUs)" Input="$(ProjectDir)$(OutputPath)$(AssemblyName).dll" ReferencedAssemblies="@(ReferencePath)" />
|
||||
<Reobfuscate AmongUs="$(AmongUs)" Input="$(ProjectDir)$(OutputPath)$(AssemblyName).dll" ReferencedAssemblies="@(ReferencePath)" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
<Version>0.2.3</Version>
|
||||
<Version>0.2.4</Version>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/NuclearPowered/Reactor.OxygenFilter</RepositoryUrl>
|
||||
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
|
||||
|
||||
@@ -11,9 +11,6 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
{
|
||||
public class Reobfuscate : Task
|
||||
{
|
||||
[Required]
|
||||
public string GameVersion { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AmongUs { get; set; }
|
||||
|
||||
@@ -270,7 +267,7 @@ namespace Reactor.OxygenFilter.MSBuild
|
||||
|
||||
var outputDirectory = Path.Combine(Path.GetDirectoryName(Input), "reobfuscated");
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
moduleDefinition.Write(Path.Combine(outputDirectory, Path.GetFileNameWithoutExtension(Input) + $"-{GameVersion}.dll"));
|
||||
moduleDefinition.Write(Path.Combine(outputDirectory, Path.GetFileNameWithoutExtension(Input) + $"-{Context.GameVersion}.dll"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,16 @@ namespace Reactor.OxygenFilter
|
||||
}
|
||||
}
|
||||
|
||||
public MappedMember(string original, string mapped) : this(
|
||||
new OriginalDescriptor
|
||||
{
|
||||
Name = original
|
||||
},
|
||||
mapped
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(MappedMember obj, bool compareOriginal = true)
|
||||
{
|
||||
if (obj == null)
|
||||
@@ -195,5 +205,9 @@ namespace Reactor.OxygenFilter
|
||||
public MappedType(OriginalDescriptor original, string mapped) : base(original, mapped)
|
||||
{
|
||||
}
|
||||
|
||||
public MappedType(string original, string mapped) : base(original, mapped)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user