From 385c8ebc50caa81f8a1beb3ce51fac2355be19c0 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Mon, 4 Nov 2019 20:22:13 +0100 Subject: [PATCH] Output: Option to suppress constructs with [CompilerGeneratedAttribute] --- Il2CppDumper/Il2CppCSharpDumper.cs | 18 ++++++++++++++++-- Il2CppDumper/Program.cs | 7 +++++-- Il2CppTests/TestRunner.cs | 3 ++- README.md | 7 ++++--- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Il2CppDumper/Il2CppCSharpDumper.cs b/Il2CppDumper/Il2CppCSharpDumper.cs index b765e6f..a747240 100644 --- a/Il2CppDumper/Il2CppCSharpDumper.cs +++ b/Il2CppDumper/Il2CppCSharpDumper.cs @@ -17,6 +17,11 @@ namespace Il2CppInspector // Namespace prefixes whose contents should be skipped public List ExcludedNamespaces { get; set; } + // Suppress types, fields and methods with the CompilerGenerated attribute; suppress the attribute itself from property getters and setters + public bool SuppressGenerated { get; set; } + + private const string CGAttribute = "System.Runtime.CompilerServices.CompilerGeneratedAttribute"; + public Il2CppCSharpDumper(Il2CppModel model) => this.model = model; private StreamWriter writer; @@ -49,6 +54,9 @@ namespace Il2CppInspector } private void writeType(TypeInfo type, string prefix = "") { + // Don't output compiler-generated types if desired + if (SuppressGenerated && type.GetCustomAttributes(CGAttribute).Any()) + return; // Only print namespace if we're not nested if (!type.IsNested) @@ -132,6 +140,9 @@ namespace Il2CppInspector writer.Write(prefix + "\t// Fields\n"); foreach (var field in type.DeclaredFields) { + if (SuppressGenerated && field.GetCustomAttributes(CGAttribute).Any()) + continue; + if (field.IsNotSerialized) writer.Write(prefix + "\t[NonSerialized]\n"); @@ -191,8 +202,8 @@ namespace Il2CppInspector string modifiers = prop.GetMethod?.GetModifierString() ?? prop.SetMethod.GetModifierString(); writer.Write($"{prefix}\t{modifiers}{prop.PropertyType.CSharpName} {prop.Name} {{ "); - writer.Write((prop.GetMethod != null ? prop.GetMethod.CustomAttributes.ToString(inline: true) + "get; " : "") - + (prop.SetMethod != null ? prop.SetMethod.CustomAttributes.ToString(inline: true) + "set; " : "") + "}"); + writer.Write((prop.GetMethod != null ? prop.GetMethod.CustomAttributes.Where(a => !SuppressGenerated || a.AttributeType.FullName != CGAttribute).ToString(inline: true) + "get; " : "") + + (prop.SetMethod != null ? prop.SetMethod.CustomAttributes.Where(a => !SuppressGenerated || a.AttributeType.FullName != CGAttribute).ToString(inline: true) + "set; " : "") + "}"); if ((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0) || (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0)) writer.Write(" // "); writer.Write((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0 ? Il2CppModel.FormatAddress(prop.GetMethod.VirtualAddress) + " " : "") @@ -255,6 +266,9 @@ namespace Il2CppInspector // Don't re-output methods for constructors, properties, events etc. foreach (var method in type.DeclaredMethods.Except(usedMethods)) { + if (SuppressGenerated && method.GetCustomAttributes(CGAttribute).Any()) + continue; + // Attributes writer.Write(method.CustomAttributes.ToString(prefix + "\t")); // IL2CPP doesn't seem to retain return type attributes diff --git a/Il2CppDumper/Program.cs b/Il2CppDumper/Program.cs index 6d24045..5076f47 100644 --- a/Il2CppDumper/Program.cs +++ b/Il2CppDumper/Program.cs @@ -19,7 +19,7 @@ namespace Il2CppInspector Console.WriteLine("(c) 2017-2019 Katy Coe - www.djkaty.com"); Console.WriteLine(""); - // Command-line usage: dotnet run [--bin=] [--metadata=] [--cs-out=] [--py-out=] [--exclude-namespaces=|none] + // Command-line usage: dotnet run [--bin=] [--metadata=] [--cs-out=] [--py-out=] [--exclude-namespaces=|none] [--suppress-compiler-generated=false] // Defaults to libil2cpp.so or GameAssembly.dll if binary file not specified IConfiguration config = new ConfigurationBuilder().AddCommandLine(args).Build(); @@ -27,6 +27,8 @@ namespace Il2CppInspector string metaFile = config["metadata"] ?? "global-metadata.dat"; string outCsFile = config["cs-out"] ?? "types.cs"; string outPythonFile = config["py-out"] ?? "ida.py"; + if (!bool.TryParse(config["suppress-compiler-generated"], out var suppressGenerated)) + suppressGenerated = true; // Exclusions var excludedNamespaces = config["exclude-namespaces"]?.Split(',').ToList() ?? @@ -63,7 +65,8 @@ namespace Il2CppInspector var model = new Il2CppModel(il2cpp); // C# signatures output - new Il2CppCSharpDumper(model) {ExcludedNamespaces = excludedNamespaces}.WriteFile(outCsFile + (i++ > 0 ? "-" + (i-1) : "")); + new Il2CppCSharpDumper(model) {ExcludedNamespaces = excludedNamespaces, SuppressGenerated = suppressGenerated} + .WriteFile(outCsFile + (i++ > 0 ? "-" + (i-1) : "")); // IDA Python script output // TODO: IDA Python script output diff --git a/Il2CppTests/TestRunner.cs b/Il2CppTests/TestRunner.cs index 223981e..37400c1 100644 --- a/Il2CppTests/TestRunner.cs +++ b/Il2CppTests/TestRunner.cs @@ -53,7 +53,8 @@ namespace Il2CppInspector // Dump each image in the binary separately int i = 0; foreach (var il2cpp in inspectors) - new Il2CppCSharpDumper(new Il2CppModel(il2cpp)) {ExcludedNamespaces = excludedNamespaces}.WriteFile(testPath + @"\test-result" + (i++ > 0 ? "-" + (i - 1) : "") + ".cs"); + new Il2CppCSharpDumper(new Il2CppModel(il2cpp)) {ExcludedNamespaces = excludedNamespaces, SuppressGenerated = true} + .WriteFile(testPath + @"\test-result" + (i++ > 0 ? "-" + (i - 1) : "") + ".cs"); // Compare test result with expected result for (i = 0; i < inspectors.Count; i++) { diff --git a/README.md b/README.md index 948bf2a..e1dce00 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Extract types, methods, properties and fields from Unity IL2CPP binaries. * 32-bit and 64-bit support for all file formats * Supports ARMv7, Thumb-2, ARMv8 (A64), x86 and x64 architectures regardless of file format * Supports metadata versions 16, 21, 22, 23, 24, 24.1 (Unity 2018.3+) and 24.2 (Unity 2019+) (other versions may or may not work) -* Support for classes, methods, constructors, fields, properties, enumerations, events, delegates, interfaces, structs, nested types, generic types, generic methods and default field values +* Support for classes, methods, constructors, fields, properties, enumerations, events, delegates, interfaces, structs, pointers, attributes, nested types, generic types, generic methods and default field values * Static symbol table scanning for ELF and Mach-O binaries if present * Dynamic symbol table scanning for ELF binaries if present * Symbol relocation handling for ELF binaries @@ -31,7 +31,7 @@ The output binary is placed in `Il2CppInspector/Il2CppDumper/bin/Release/netcore ### Usage ``` -Il2CppDumper [--bin=] [--metadata=] [--cs-out=] [--exclude-namespaces=|none] +Il2CppDumper [--bin=] [--metadata=] [--cs-out=] [--exclude-namespaces=|none] [--suppress-compiler-generated=false] ``` Defaults if not specified: @@ -40,7 +40,7 @@ Defaults if not specified: - _metadata-file_ - `global-metadata.dat` - _output-file_ - `types.cs` -To exclude types from certain namespaces from being generated in the C¤ source file output, provide a comma-separated list of case-sensitive namespaces in `--exclude-namespaces`. The following namespaces will be excluded if no argument is specified: +To exclude types from certain namespaces from being generated in the C# source file output, provide a comma-separated list of case-sensitive namespaces in `--exclude-namespaces`. The following namespaces will be excluded if no argument is specified: ``` System @@ -52,6 +52,7 @@ Microsoft.Win32 Providing an argument to `--exclude-namespaces` will override the default list. To output all namespaces, use `--exclude-namespaces=none`. +By default, types and fields declared with the `System.Runtime.CompilerServices.CompilerGeneratedAttribute` attribute will be suppresssed from the C# code output. The attribute itself will be suppressed from property getters and setters. This is useful if you would like to be able to compile the output code. To include these constructs in the output, use `--suppress-compiler-generated=false`. File format and architecture are automatically detected.