From 36291c009c4db4d23e884783bd65749a4eeb5b92 Mon Sep 17 00:00:00 2001 From: js6pak Date: Fri, 22 Jan 2021 10:16:12 +0100 Subject: [PATCH] :fortelove: --- Reactor.Greenhouse/Compiler.cs | 2 +- Reactor.Greenhouse/Extensions.cs | 12 + .../Generation/GenerationContext.cs | 26 ++ Reactor.Greenhouse/Generation/Generator.cs | 277 ++++++++++++++++++ Reactor.Greenhouse/Generation/TypeContext.cs | 174 +++++++++++ Reactor.Greenhouse/Generator.cs | 161 ---------- Reactor.Greenhouse/Mappings | 2 +- Reactor.Greenhouse/Program.cs | 16 +- Reactor.Greenhouse/Reactor.Greenhouse.csproj | 1 + Reactor.Greenhouse/Setup/GameManager.cs | 20 +- Reactor.OxygenFilter.MSBuild/Context.cs | 24 +- Reactor.OxygenFilter.MSBuild/Deobfuscate.cs | 9 +- .../GenerateReferences.cs | 27 +- Reactor.OxygenFilter.MSBuild/LoadMappings.cs | 11 +- ...OxygenFilter.MSBuild.TargetFramework.props | 10 +- .../Reactor.OxygenFilter.MSBuild.csproj | 2 +- Reactor.OxygenFilter.MSBuild/Reobfuscate.cs | 5 +- Reactor.OxygenFilter/Mappings.cs | 14 + 18 files changed, 561 insertions(+), 232 deletions(-) create mode 100644 Reactor.Greenhouse/Generation/GenerationContext.cs create mode 100644 Reactor.Greenhouse/Generation/Generator.cs create mode 100644 Reactor.Greenhouse/Generation/TypeContext.cs delete mode 100644 Reactor.Greenhouse/Generator.cs diff --git a/Reactor.Greenhouse/Compiler.cs b/Reactor.Greenhouse/Compiler.cs index be4960d..d989e96 100644 --- a/Reactor.Greenhouse/Compiler.cs +++ b/Reactor.Greenhouse/Compiler.cs @@ -129,7 +129,7 @@ private static void Compile(this MappedType type, TypeDefinition typeDef, Mappin 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 ); diff --git a/Reactor.Greenhouse/Extensions.cs b/Reactor.Greenhouse/Extensions.cs index 0b75195..0437c88 100644 --- a/Reactor.Greenhouse/Extensions.cs +++ b/Reactor.Greenhouse/Extensions.cs @@ -1,3 +1,5 @@ +using System; +using System.Diagnostics; using System.Linq; using Mono.Cecil; @@ -24,5 +26,15 @@ public static CustomAttribute GetCustomAttribute(this ICustomAttributeProvider c 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; + } } } diff --git a/Reactor.Greenhouse/Generation/GenerationContext.cs b/Reactor.Greenhouse/Generation/GenerationContext.cs new file mode 100644 index 0000000..49a88c1 --- /dev/null +++ b/Reactor.Greenhouse/Generation/GenerationContext.cs @@ -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 AllCleanTypes { get; } + public IEnumerable AllObfuscatedTypes { get; } + + public Dictionary Map { get; } = new Dictionary(); + + public GenerationContext(ModuleDefinition cleanModule, ModuleDefinition obfuscatedModule) + { + CleanModule = cleanModule; + ObfuscatedModule = obfuscatedModule; + + AllCleanTypes = CleanModule.GetAllTypes(); + AllObfuscatedTypes = ObfuscatedModule.GetAllTypes(); + } + } +} diff --git a/Reactor.Greenhouse/Generation/Generator.cs b/Reactor.Greenhouse/Generation/Generator.cs new file mode 100644 index 0000000..caa8ef2 --- /dev/null +++ b/Reactor.Greenhouse/Generation/Generator.cs @@ -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"); + } + } + } + } + } + } +} diff --git a/Reactor.Greenhouse/Generation/TypeContext.cs b/Reactor.Greenhouse/Generation/TypeContext.cs new file mode 100644 index 0000000..20aeff4 --- /dev/null +++ b/Reactor.Greenhouse/Generation/TypeContext.cs @@ -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(); + + 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; + } + } +} diff --git a/Reactor.Greenhouse/Generator.cs b/Reactor.Greenhouse/Generator.cs deleted file mode 100644 index 5408642..0000000 --- a/Reactor.Greenhouse/Generator.cs +++ /dev/null @@ -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>(); - - var result = new Mappings(); - - foreach (var oldType in old.GetAllTypes()) - { - if (oldType.Name.StartsWith("<") || oldType.Namespace.StartsWith("GoogleMobileAds")) - continue; - - var list = new SortedList(Comparer.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; - } - } -} diff --git a/Reactor.Greenhouse/Mappings b/Reactor.Greenhouse/Mappings index b127276..a2ac437 160000 --- a/Reactor.Greenhouse/Mappings +++ b/Reactor.Greenhouse/Mappings @@ -1 +1 @@ -Subproject commit b127276f6a67d9ecbcdbddaa57935734d780e15b +Subproject commit a2ac4373f2aaf2399eecaa1c0a29d6e74897333b diff --git a/Reactor.Greenhouse/Program.cs b/Reactor.Greenhouse/Program.cs index 39cf349..4848b5c 100644 --- a/Reactor.Greenhouse/Program.cs +++ b/Reactor.Greenhouse/Program.cs @@ -10,6 +10,7 @@ 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 @@ public static async Task GenerateAsync(bool steam, bool itch) 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 @@ public static async Task GenerateAsync(bool steam, bool itch) 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 @@ private static async Task GenerateAsync(Game game, ModuleDefinition old) 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)); diff --git a/Reactor.Greenhouse/Reactor.Greenhouse.csproj b/Reactor.Greenhouse/Reactor.Greenhouse.csproj index ebd873f..d7c7d66 100644 --- a/Reactor.Greenhouse/Reactor.Greenhouse.csproj +++ b/Reactor.Greenhouse/Reactor.Greenhouse.csproj @@ -10,6 +10,7 @@ + diff --git a/Reactor.Greenhouse/Setup/GameManager.cs b/Reactor.Greenhouse/Setup/GameManager.cs index f899e6e..35aa6b9 100644 --- a/Reactor.Greenhouse/Setup/GameManager.cs +++ b/Reactor.Greenhouse/Setup/GameManager.cs @@ -10,34 +10,25 @@ public class GameManager { 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 @@ public async Task SetupAsync(bool setupSteam, bool setupItch) ContentDownloader.ShutdownSteam3(); - PreObfuscation.UpdateVersion(); - if (setupSteam) { Steam.UpdateVersion(); @@ -65,13 +54,6 @@ public async Task SetupAsync(bool setupSteam, bool setupItch) Itch.UpdateVersion(); } - if (PreObfuscation.Version != "2020.9.9") - { - throw new ArgumentException("Pre obfuscation version is invalid"); - } - - PreObfuscation.Dump(); - if (setupSteam) { Steam.Dump(); diff --git a/Reactor.OxygenFilter.MSBuild/Context.cs b/Reactor.OxygenFilter.MSBuild/Context.cs index c2eaa7d..d667a41 100644 --- a/Reactor.OxygenFilter.MSBuild/Context.cs +++ b/Reactor.OxygenFilter.MSBuild/Context.cs @@ -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 @@ public static string ComputeHash(FileInfo file) var hash = md5.ComputeHash(assemblyStream); - return Encoding.UTF8.GetString(hash); + return ByteArrayToString(hash); } public static string ComputeHash(string text) @@ -27,7 +32,18 @@ public static string ComputeHash(string text) 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(); } } } diff --git a/Reactor.OxygenFilter.MSBuild/Deobfuscate.cs b/Reactor.OxygenFilter.MSBuild/Deobfuscate.cs index cd909a6..cdc93bc 100644 --- a/Reactor.OxygenFilter.MSBuild/Deobfuscate.cs +++ b/Reactor.OxygenFilter.MSBuild/Deobfuscate.cs @@ -17,15 +17,12 @@ public class Deobfuscate : Task [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 @@ public override bool Execute() ContractResolver = new CamelCasePropertyNamesContractResolver() }; - var mappings = JsonConvert.DeserializeObject(Mappings); + var mappings = JsonConvert.DeserializeObject(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")); diff --git a/Reactor.OxygenFilter.MSBuild/GenerateReferences.cs b/Reactor.OxygenFilter.MSBuild/GenerateReferences.cs index a5c753d..d23f2f2 100644 --- a/Reactor.OxygenFilter.MSBuild/GenerateReferences.cs +++ b/Reactor.OxygenFilter.MSBuild/GenerateReferences.cs @@ -10,31 +10,29 @@ public class GenerateReferences : Task [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 @@ public override bool Execute() return true; } - if (Directory.Exists(Context.TempPath)) - { - Directory.Delete(Context.TempPath, true); - } - var dumperConfig = new Il2CppDumper.Config { GenerateScript = false, @@ -62,7 +55,7 @@ public override bool Execute() 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 @@ public override bool Execute() 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 @@ public override bool Execute() { 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 }; diff --git a/Reactor.OxygenFilter.MSBuild/LoadMappings.cs b/Reactor.OxygenFilter.MSBuild/LoadMappings.cs index eed71d3..f13d47f 100644 --- a/Reactor.OxygenFilter.MSBuild/LoadMappings.cs +++ b/Reactor.OxygenFilter.MSBuild/LoadMappings.cs @@ -14,14 +14,13 @@ public class LoadMappings : Task [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 @@ public override bool Execute() 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 { diff --git a/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.TargetFramework.props b/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.TargetFramework.props index be3e0bc..f5e6a0d 100644 --- a/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.TargetFramework.props +++ b/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.TargetFramework.props @@ -18,13 +18,11 @@ - - - + - + @@ -38,7 +36,7 @@ - + @@ -48,6 +46,6 @@ - + \ No newline at end of file diff --git a/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.csproj b/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.csproj index 6658216..89c7561 100644 --- a/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.csproj +++ b/Reactor.OxygenFilter.MSBuild/Reactor.OxygenFilter.MSBuild.csproj @@ -4,7 +4,7 @@ latest true - 0.2.3 + 0.2.4 git https://github.com/NuclearPowered/Reactor.OxygenFilter LGPL-3.0-or-later diff --git a/Reactor.OxygenFilter.MSBuild/Reobfuscate.cs b/Reactor.OxygenFilter.MSBuild/Reobfuscate.cs index ae45ba4..deb672b 100644 --- a/Reactor.OxygenFilter.MSBuild/Reobfuscate.cs +++ b/Reactor.OxygenFilter.MSBuild/Reobfuscate.cs @@ -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 @@ void ReobfuscateType(TypeReference t) 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; } diff --git a/Reactor.OxygenFilter/Mappings.cs b/Reactor.OxygenFilter/Mappings.cs index 0b96eba..1aaa803 100644 --- a/Reactor.OxygenFilter/Mappings.cs +++ b/Reactor.OxygenFilter/Mappings.cs @@ -156,6 +156,16 @@ public MappedMember(OriginalDescriptor original, string mapped) } } + 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 @@ public MappedType() public MappedType(OriginalDescriptor original, string mapped) : base(original, mapped) { } + + public MappedType(string original, string mapped) : base(original, mapped) + { + } } }