using System.Reflection; using System.Runtime.Loader; using Mono.Cecil; using Mono.Cecil.Cil; if (args.Length == 3 && args[0] == "--patch-loader") { if (Path.GetFullPath(args[1]).Equals(Path.GetFullPath(args[2]), StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("Write a separate loader copy; do not overwrite the source."); using var assembly = AssemblyDefinition.ReadAssembly(args[1]); int changes = 0; foreach (var type in assembly.MainModule.Types) foreach (var method in type.Methods.Where(m => m.HasBody)) foreach (var instruction in method.Body.Instructions) if (type.FullName == "BepInEx.Unity.IL2CPP.Il2CppInteropManager" && instruction.OpCode == OpCodes.Ldstr && (string)instruction.Operand == "global-metadata.dat") { instruction.Operand = "global-metadata.interop.dat"; Console.WriteLine($"Redirected metadata input in {method.Name}"); changes++; } if (changes != 1) throw new InvalidOperationException($"Expected one loader metadata reference, found {changes}."); assembly.Write(args[2]); Console.WriteLine($"Created loader copy with {changes} metadata path reference(s) changed."); return; } if (args.Length is < 2 or > 5) { Console.Error.WriteLine("Usage: AugustInterop [GameAssembly.dll]"); Console.Error.WriteLine(" or: AugustInterop --patch-loader "); Environment.ExitCode = 1; return; } var core = args[0]; AssemblyLoadContext.Default.Resolving += (_, name) => { var path = Path.Combine(core, name.Name + ".dll"); return File.Exists(path) ? AssemblyLoadContext.Default.LoadFromAssemblyPath(path) : null; }; var library = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(core, "LibCpp2IL.dll")); if (args.Length > 1) { var primitives = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(core, "AssetRipper.Primitives.dll")); var versionType = primitives.GetType("AssetRipper.Primitives.UnityVersion")!; var version = versionType.GetMethod("Parse", new[] { typeof(string) })!.Invoke(null, new object[] { "2020.3.33f1" }); var type = library.GetType("LibCpp2IL.Metadata.Il2CppMetadata")!; var metadata = type.GetMethod("ReadFrom")!.Invoke(null, new object[] { File.ReadAllBytes(args[1]), version }); Console.WriteLine("Metadata parsed successfully."); foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)) if (field.GetValue(metadata) is Array array) Console.WriteLine($"{field.Name}: {array.Length}"); if (args.Length > 2) { var registry = library.GetTypes().Single(t => t.Name == "LibCpp2IlBinaryRegistry"); registry.GetMethod("RegisterBuiltInBinarySupport")!.Invoke(null, null); var main = library.GetType("LibCpp2IL.LibCpp2IlMain")!; var result = main.GetMethod("LoadFromFile")!.Invoke(null, new[] { (object)args[2], Path.GetFullPath(args[1]), version }); Console.WriteLine($"Binary + metadata initialization: {result}"); if (args.Length > 3 && args[3] == "--literal-find" && args.Length > 4) LiteralFinder.Run(main, metadata, args[2], args[4]); else if (args.Length > 3) NativeInspect.Run(main, metadata, args[2], args[3], args.Length > 4 ? args[4] : ""); } }