diff --git a/Cpp2IL/AssemblyBuilder.cs b/Cpp2IL/AssemblyBuilder.cs index b672d20a..25d6d71b 100644 --- a/Cpp2IL/AssemblyBuilder.cs +++ b/Cpp2IL/AssemblyBuilder.cs @@ -11,10 +11,8 @@ namespace Cpp2IL { - internal static partial class AssemblyBuilder + internal static class AssemblyBuilder { - - /// /// Creates all the Assemblies defined in the provided metadata, along with (stub) definitions of all the types contained therein, and registers them with the resolver. /// @@ -124,7 +122,8 @@ public static void ConfigureHierarchy(Il2CppMetadata metadata, PE.PE theDll) var currentAssembly = firstTypeDefinition.Module.Assembly; //Ensure type directory exists - Directory.CreateDirectory(Path.Combine(Path.GetFullPath("cpp2il_out"), "types", currentAssembly.Name.Name)); + if(!Program.CommandLineOptions.SkipMetadataTextFiles && !Program.CommandLineOptions.SkipAnalysis) + Directory.CreateDirectory(Path.Combine(Path.GetFullPath("cpp2il_out"), "types", currentAssembly.Name.Name)); var lastTypeIndex = imageDef.firstTypeIndex + imageDef.typeCount; var methods = new List<(TypeDefinition type, List methods)>(); @@ -370,7 +369,8 @@ private static List ProcessTypeContents(Il2CppMetadata metadata, ilTypeDefinition.Events.Add(eventDefinition); } - File.WriteAllText(Path.Combine(Path.GetFullPath("cpp2il_out"), "types", ilTypeDefinition.Module.Assembly.Name.Name, ilTypeDefinition.Name.Replace("<", "_").Replace(">", "_").Replace("|", "_") + "_metadata.txt"), typeMetaText.ToString()); + if(!Program.CommandLineOptions.SkipMetadataTextFiles) + File.WriteAllText(Path.Combine(Path.GetFullPath("cpp2il_out"), "types", ilTypeDefinition.Module.Assembly.Name.Name, ilTypeDefinition.Name.Replace("<", "_").Replace(">", "_").Replace("|", "_") + "_metadata.txt"), typeMetaText.ToString()); if (cppTypeDefinition.genericContainerIndex < 0) return typeMethods; //Finished processing if not generic diff --git a/Cpp2IL/PE/PE.cs b/Cpp2IL/PE/PE.cs index 66f5979b..7cebac3c 100644 --- a/Cpp2IL/PE/PE.cs +++ b/Cpp2IL/PE/PE.cs @@ -332,7 +332,7 @@ public bool PlusSearch(int methodCount, int typeDefinitionsCount) List methodBodyRuntimeInit = Utils.GetMethodBodyAtRawAddress(this, MapVirtualAddressToRaw(virtualAddressRuntimeInit), false); Disassembler.Translator.IncludeBinary = true; - File.WriteAllText(Path.Combine("cpp2il_out", "runtime_init_dump.txt"), string.Join('\n', methodBodyRuntimeInit.Select(i => i.ToString()))); + // File.WriteAllText(Path.Combine("cpp2il_out", "runtime_init_dump.txt"), string.Join('\n', methodBodyRuntimeInit.Select(i => i.ToString()))); //This is kind of sketchy, but look for a global read (i.e an LEA where the second base is RIP), as that's the framework version read, then there's a MOV, then 4 calls, the third of which is our target. //So as to ensure compat with 2018, ensure we have a call before this LEA. diff --git a/Cpp2IL/Program.cs b/Cpp2IL/Program.cs index dce78af8..11edbcdc 100644 --- a/Cpp2IL/Program.cs +++ b/Cpp2IL/Program.cs @@ -30,6 +30,9 @@ internal class Options [Option("skip-analysis", Required = false, HelpText = "Skip the analysis section and stop once DummyDLLs have been generated.")] public bool SkipAnalysis { get; set; } + + [Option("skip-metadata-txts", Required = false, HelpText = "Skip the generation of [classname]_metadata.txt files.")] + public bool SkipMetadataTextFiles { get; set; } } public static float MetadataVersion = 24f; @@ -43,6 +46,7 @@ internal class Options private static List Assemblies = new List(); internal static Il2CppMetadata? Metadata; internal static PE.PE ThePE; + internal static Options CommandLineOptions; public static void PrintUsage() { @@ -55,13 +59,13 @@ public static void Main(string[] args) Console.WriteLine("A Tool to Reverse Unity's \"il2cpp\" Build Process."); Console.WriteLine("Running on " + Environment.OSVersion.Platform); - Options commandLineOptions = null; + CommandLineOptions = null; Parser.Default.ParseArguments(args).WithParsed(options => { - commandLineOptions = options; + CommandLineOptions = options; }); - if (commandLineOptions == null) + if (CommandLineOptions == null) { return; } @@ -93,7 +97,7 @@ public static void Main(string[] args) // return; // } - var baseGamePath = commandLineOptions.GamePath; + var baseGamePath = CommandLineOptions.GamePath; Console.WriteLine("Using path: " + baseGamePath); @@ -105,11 +109,12 @@ public static void Main(string[] args) } var assemblyPath = Path.Combine(baseGamePath, "GameAssembly.dll"); - var exeName = Path.GetFileNameWithoutExtension(Directory.GetFiles(baseGamePath).First(f => f.EndsWith(".exe") && !blacklistedExecutableFilenames.Contains(f))); + var exeName = Path.GetFileNameWithoutExtension(Directory.GetFiles(baseGamePath) + .First(f => f.EndsWith(".exe") && !blacklistedExecutableFilenames.Any(bl => f.EndsWith(bl)))); - if (commandLineOptions.ExeName != null) + if (CommandLineOptions.ExeName != null) { - exeName = commandLineOptions.ExeName; + exeName = CommandLineOptions.ExeName; Console.WriteLine($"Using OVERRIDDEN game name: {exeName}"); } else @@ -136,10 +141,32 @@ public static void Main(string[] args) Console.WriteLine("\nAttempting to determine Unity version..."); - var unityVer = FileVersionInfo.GetVersionInfo(unityPlayerPath); - - var unityVerUseful = new[] {unityVer.FileMajorPart, unityVer.FileMinorPart, unityVer.FileBuildPart}; - + int[] unityVerUseful; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + var unityVer = FileVersionInfo.GetVersionInfo(unityPlayerPath); + + unityVerUseful = new[] {unityVer.FileMajorPart, unityVer.FileMinorPart, unityVer.FileBuildPart}; + } + else + { + //Globalgamemanagers + var globalgamemanagersPath = Path.Combine(baseGamePath, $"{exeName}_Data", "globalgamemanagers"); + var ggmBytes = File.ReadAllBytes(globalgamemanagersPath); + var verString = new StringBuilder(); + var idx = 0x14; + while (ggmBytes[idx] != 0) + { + verString.Append(Convert.ToChar(ggmBytes[idx])); + idx++; + } + + var unityVer = verString.ToString(); + unityVer = unityVer.Substring(0, unityVer.IndexOf("f")); + Console.WriteLine("Read version string from globalgamemanagers: " + unityVer); + unityVerUseful = unityVer.Split(".").Select(int.Parse).ToArray(); + } + Console.WriteLine("This game is built with Unity version " + string.Join(".", unityVerUseful)); if (unityVerUseful[0] <= 4) @@ -246,7 +273,7 @@ public static void Main(string[] args) #endregion KeyFunctionAddresses keyFunctionAddresses = null; - if (!commandLineOptions.SkipAnalysis) + if (!CommandLineOptions.SkipAnalysis) { Console.WriteLine("\tPass 5: Locating Globals..."); @@ -281,7 +308,7 @@ public static void Main(string[] args) Directory.CreateDirectory(outputPath); var methodOutputDir = Path.Combine(outputPath, "types"); - if (!Directory.Exists(methodOutputDir)) + if (!CommandLineOptions.SkipAnalysis && !Directory.Exists(methodOutputDir)) Directory.CreateDirectory(methodOutputDir); Console.WriteLine("Saving Header DLLs to " + outputPath + "..."); @@ -294,7 +321,7 @@ public static void Main(string[] args) assembly.Write(dllPath); - if (assembly.Name.Name != "Assembly-CSharp" || commandLineOptions.SkipAnalysis) continue; + if (assembly.Name.Name != "Assembly-CSharp" || CommandLineOptions.SkipAnalysis) continue; Console.WriteLine("Dumping method bytes to " + methodOutputDir); Directory.CreateDirectory(Path.Combine(methodOutputDir, assembly.Name.Name));