Output: Option to suppress constructs with [CompilerGeneratedAttribute]

This commit is contained in:
Katy Coe
2019-11-04 20:22:13 +01:00
parent a46947ac61
commit 385c8ebc50
4 changed files with 27 additions and 8 deletions

View File

@@ -17,6 +17,11 @@ namespace Il2CppInspector
// Namespace prefixes whose contents should be skipped // Namespace prefixes whose contents should be skipped
public List<string> ExcludedNamespaces { get; set; } public List<string> 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; public Il2CppCSharpDumper(Il2CppModel model) => this.model = model;
private StreamWriter writer; private StreamWriter writer;
@@ -49,6 +54,9 @@ namespace Il2CppInspector
} }
private void writeType(TypeInfo type, string prefix = "") { 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 // Only print namespace if we're not nested
if (!type.IsNested) if (!type.IsNested)
@@ -132,6 +140,9 @@ namespace Il2CppInspector
writer.Write(prefix + "\t// Fields\n"); writer.Write(prefix + "\t// Fields\n");
foreach (var field in type.DeclaredFields) { foreach (var field in type.DeclaredFields) {
if (SuppressGenerated && field.GetCustomAttributes(CGAttribute).Any())
continue;
if (field.IsNotSerialized) if (field.IsNotSerialized)
writer.Write(prefix + "\t[NonSerialized]\n"); writer.Write(prefix + "\t[NonSerialized]\n");
@@ -191,8 +202,8 @@ namespace Il2CppInspector
string modifiers = prop.GetMethod?.GetModifierString() ?? prop.SetMethod.GetModifierString(); string modifiers = prop.GetMethod?.GetModifierString() ?? prop.SetMethod.GetModifierString();
writer.Write($"{prefix}\t{modifiers}{prop.PropertyType.CSharpName} {prop.Name} {{ "); writer.Write($"{prefix}\t{modifiers}{prop.PropertyType.CSharpName} {prop.Name} {{ ");
writer.Write((prop.GetMethod != null ? prop.GetMethod.CustomAttributes.ToString(inline: true) + "get; " : "") 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.ToString(inline: true) + "set; " : "") + "}"); + (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)) if ((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0) || (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0))
writer.Write(" // "); writer.Write(" // ");
writer.Write((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0 ? Il2CppModel.FormatAddress(prop.GetMethod.VirtualAddress) + " " : "") 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. // Don't re-output methods for constructors, properties, events etc.
foreach (var method in type.DeclaredMethods.Except(usedMethods)) { foreach (var method in type.DeclaredMethods.Except(usedMethods)) {
if (SuppressGenerated && method.GetCustomAttributes(CGAttribute).Any())
continue;
// Attributes // Attributes
writer.Write(method.CustomAttributes.ToString(prefix + "\t")); writer.Write(method.CustomAttributes.ToString(prefix + "\t"));
// IL2CPP doesn't seem to retain return type attributes // IL2CPP doesn't seem to retain return type attributes

View File

@@ -19,7 +19,7 @@ namespace Il2CppInspector
Console.WriteLine("(c) 2017-2019 Katy Coe - www.djkaty.com"); Console.WriteLine("(c) 2017-2019 Katy Coe - www.djkaty.com");
Console.WriteLine(""); Console.WriteLine("");
// Command-line usage: dotnet run [--bin=<binary-file>] [--metadata=<metadata-file>] [--cs-out=<output-file>] [--py-out=<output-file>] [--exclude-namespaces=<ns1,n2,...>|none] // Command-line usage: dotnet run [--bin=<binary-file>] [--metadata=<metadata-file>] [--cs-out=<output-file>] [--py-out=<output-file>] [--exclude-namespaces=<ns1,n2,...>|none] [--suppress-compiler-generated=false]
// Defaults to libil2cpp.so or GameAssembly.dll if binary file not specified // Defaults to libil2cpp.so or GameAssembly.dll if binary file not specified
IConfiguration config = new ConfigurationBuilder().AddCommandLine(args).Build(); IConfiguration config = new ConfigurationBuilder().AddCommandLine(args).Build();
@@ -27,6 +27,8 @@ namespace Il2CppInspector
string metaFile = config["metadata"] ?? "global-metadata.dat"; string metaFile = config["metadata"] ?? "global-metadata.dat";
string outCsFile = config["cs-out"] ?? "types.cs"; string outCsFile = config["cs-out"] ?? "types.cs";
string outPythonFile = config["py-out"] ?? "ida.py"; string outPythonFile = config["py-out"] ?? "ida.py";
if (!bool.TryParse(config["suppress-compiler-generated"], out var suppressGenerated))
suppressGenerated = true;
// Exclusions // Exclusions
var excludedNamespaces = config["exclude-namespaces"]?.Split(',').ToList() ?? var excludedNamespaces = config["exclude-namespaces"]?.Split(',').ToList() ??
@@ -63,7 +65,8 @@ namespace Il2CppInspector
var model = new Il2CppModel(il2cpp); var model = new Il2CppModel(il2cpp);
// C# signatures output // 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 // IDA Python script output
// TODO: IDA Python script output // TODO: IDA Python script output

View File

@@ -53,7 +53,8 @@ namespace Il2CppInspector
// Dump each image in the binary separately // Dump each image in the binary separately
int i = 0; int i = 0;
foreach (var il2cpp in inspectors) 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 // Compare test result with expected result
for (i = 0; i < inspectors.Count; i++) { for (i = 0; i < inspectors.Count; i++) {

View File

@@ -6,7 +6,7 @@ Extract types, methods, properties and fields from Unity IL2CPP binaries.
* 32-bit and 64-bit support for all file formats * 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 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) * 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 * Static symbol table scanning for ELF and Mach-O binaries if present
* Dynamic symbol table scanning for ELF binaries if present * Dynamic symbol table scanning for ELF binaries if present
* Symbol relocation handling for ELF binaries * Symbol relocation handling for ELF binaries
@@ -31,7 +31,7 @@ The output binary is placed in `Il2CppInspector/Il2CppDumper/bin/Release/netcore
### Usage ### Usage
``` ```
Il2CppDumper [--bin=<binary-file>] [--metadata=<metadata-file>] [--cs-out=<output-file>] [--exclude-namespaces=<ns1,ns2,...>|none] Il2CppDumper [--bin=<binary-file>] [--metadata=<metadata-file>] [--cs-out=<output-file>] [--exclude-namespaces=<ns1,ns2,...>|none] [--suppress-compiler-generated=false]
``` ```
Defaults if not specified: Defaults if not specified:
@@ -40,7 +40,7 @@ Defaults if not specified:
- _metadata-file_ - `global-metadata.dat` - _metadata-file_ - `global-metadata.dat`
- _output-file_ - `types.cs` - _output-file_ - `types.cs`
To exclude types from certain namespaces from being generated in the C<EFBFBD> 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 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`. 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. File format and architecture are automatically detected.