From a5d0ea39e621efda98936cc5706159cfbf6b05ff Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Tue, 5 Jan 2021 03:42:51 +0100 Subject: [PATCH] DLL: Add initial code to create custom attributes --- Il2CppInspector.Common/Il2CppInspector.csproj | 1 + .../Outputs/AssemblyShims.cs | 109 ++++++++++++++++++ README.md | 1 + 3 files changed, 111 insertions(+) create mode 100644 Il2CppInspector.Common/Outputs/AssemblyShims.cs diff --git a/Il2CppInspector.Common/Il2CppInspector.csproj b/Il2CppInspector.Common/Il2CppInspector.csproj index 56ff45f..488f935 100644 --- a/Il2CppInspector.Common/Il2CppInspector.csproj +++ b/Il2CppInspector.Common/Il2CppInspector.csproj @@ -38,6 +38,7 @@ + diff --git a/Il2CppInspector.Common/Outputs/AssemblyShims.cs b/Il2CppInspector.Common/Outputs/AssemblyShims.cs new file mode 100644 index 0000000..a5359a4 --- /dev/null +++ b/Il2CppInspector.Common/Outputs/AssemblyShims.cs @@ -0,0 +1,109 @@ +/* + Copyright 2017-2020 Perfare - https://github.com/Perfare/Il2CppDumper + Copyright 2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty + + All rights reserved. +*/ + +using System; +using System.IO; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using Il2CppInspector.Reflection; +using Assembly = System.Reflection.Assembly; +using BindingFlags = System.Reflection.BindingFlags; + +namespace Il2CppInspector.Outputs +{ + public static class dnlibExtensions + { + // Add a default parameterless constructor that calls a specified base constructor + public static MethodDefUser AddDefaultConstructor(this TypeDefUser type, IMethod @base) { + var ctor = new MethodDefUser(".ctor", MethodSig.CreateInstance(type.Module.CorLibTypes.Void), + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); + + var ctorBody = new CilBody(); + ctorBody.Instructions.Add(OpCodes.Ldarg_0.ToInstruction()); + ctorBody.Instructions.Add(OpCodes.Call.ToInstruction(@base)); + ctorBody.Instructions.Add(OpCodes.Ret.ToInstruction()); + + type.Methods.Add(ctor); + return ctor; + } + } + + // Output module to create .NET DLLs containing type definitions + public class AssemblyShims + { + private readonly TypeModel model; + + // The namespace for our custom types + private const string rootNamespace = "Il2CppInspector.DLL"; // Il2CppDummyDll + + public AssemblyShims(TypeModel model) => this.model = model; + + // Create a new DLL assembly definition + private ModuleDefUser CreateAssembly(string name) { + var module = new ModuleDefUser(name + ".dll") { Kind = ModuleKind.Dll }; + + var ourVersion = Assembly.GetAssembly(typeof(Il2CppInspector)).GetName().Version; + + var asm = new AssemblyDefUser(name, ourVersion); + asm.Modules.Add(module); + + return module; + } + + // Generate and save all DLLs + public void Write(string outputPath) { + Directory.CreateDirectory(outputPath); + + // Create DLL with our custom types + var module = CreateAssembly("Il2CppInspector"); + + var importer = new Importer(module); + var attributeCtor = typeof(Attribute).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]; + var attributeTypeRef = importer.Import(typeof(Attribute)); + var attributeCtorRef = importer.Import(attributeCtor); + + var stringField = new FieldSig(module.CorLibTypes.String); + + // Create a type deriving from System.Attribute and add it to the assembly + TypeDefUser createAttribute(string name) { + var attribute = new TypeDefUser(rootNamespace, name, attributeTypeRef); + attribute.Attributes = TypeAttributes.Public | TypeAttributes.BeforeFieldInit; + module.Types.Add(attribute); + return attribute; + } + + // Create our custom attributes for compatibility with Il2CppDumper + var addressAttribute = createAttribute("AddressAttribute"); + addressAttribute.Fields.Add(new FieldDefUser("RVA", stringField, FieldAttributes.Public)); + addressAttribute.Fields.Add(new FieldDefUser("Offset", stringField, FieldAttributes.Public)); + addressAttribute.Fields.Add(new FieldDefUser("VA", stringField, FieldAttributes.Public)); + addressAttribute.Fields.Add(new FieldDefUser("Slot", stringField, FieldAttributes.Public)); + addressAttribute.AddDefaultConstructor(attributeCtorRef); + + var fieldOffsetAttribute = createAttribute("FieldOffsetAttribute"); + fieldOffsetAttribute.Fields.Add(new FieldDefUser("Offset", stringField, FieldAttributes.Public)); + fieldOffsetAttribute.AddDefaultConstructor(attributeCtorRef); + + var attributeAttribute = createAttribute("AttributeAttribute"); + attributeAttribute.Fields.Add(new FieldDefUser("Name", stringField, FieldAttributes.Public)); + attributeAttribute.Fields.Add(new FieldDefUser("RVA", stringField, FieldAttributes.Public)); + attributeAttribute.Fields.Add(new FieldDefUser("Offset", stringField, FieldAttributes.Public)); + attributeAttribute.AddDefaultConstructor(attributeCtorRef); + + var metadataOffsetAttribute = createAttribute("MetadataOffsetAttribute"); + metadataOffsetAttribute.Fields.Add(new FieldDefUser("Offset", stringField, FieldAttributes.Public)); + metadataOffsetAttribute.AddDefaultConstructor(attributeCtorRef); + + var tokenAttribute = createAttribute("TokenAttribute"); + tokenAttribute.Fields.Add(new FieldDefUser("Token", stringField, FieldAttributes.Public)); + tokenAttribute.AddDefaultConstructor(attributeCtorRef); + + // Write DLL to disk + module.Write(Path.Combine(outputPath, module.Name)); + } + } +} diff --git a/README.md b/README.md index 697a8e1..8cd2bdd 100644 --- a/README.md +++ b/README.md @@ -707,6 +707,7 @@ This project uses: - [Ookii.Dialogs.Wpf](https://github.com/augustoproiete/ookii-dialogs-wpf) - [XamlAnimatedGif](https://github.com/XamlAnimatedGif/WpfAnimatedGif) by Thomas Levesque - [.NET Core Plugins](https://github.com/natemcmaster/DotNetCorePlugins) by Nate McMaster +- [dnlib](https://github.com/0xd4d/dnlib) by 0xd4d Thanks to the following individuals whose code and research helped me develop this tool: