using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using AsmResolver; using AsmResolver.DotNet; using AsmResolver.DotNet.Builder; using AsmResolver.DotNet.Code.Cil; using AsmResolver.DotNet.Collections; using AsmResolver.DotNet.Signatures; using AsmResolver.PE; using AsmResolver.PE.Builder; using AsmResolver.PE.DotNet.Cil; using AsmResolver.PE.DotNet.Metadata.Tables; using AssetRipper.CIL; using AssetRipper.Primitives; using Cpp2IL.Core; using Cpp2IL.Core.Api; using Cpp2IL.Core.Attributes; using Cpp2IL.Core.Exceptions; using Cpp2IL.Core.Extensions; using Cpp2IL.Core.Graphs; using Cpp2IL.Core.Graphs.Processors; using Cpp2IL.Core.ISIL; using Cpp2IL.Core.Il2CppApiFunctions; using Cpp2IL.Core.InstructionSets; using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Model.CustomAttributes; using Cpp2IL.Core.OutputFormats; using Cpp2IL.Core.ProcessingLayers; using Cpp2IL.Core.Utils; using Cpp2IL.Core.Utils.AsmResolver; using Disarm; using Disarm.InternalDisassembly; using Gee.External.Capstone; using Gee.External.Capstone.Arm; using Gee.External.Capstone.Arm64; using Iced.Intel; using LibCpp2IL; using LibCpp2IL.BinaryStructures; using LibCpp2IL.Logging; using LibCpp2IL.Metadata; using LibCpp2IL.NintendoSwitch; using LibCpp2IL.Reflection; using LibCpp2IL.Wasm; using Microsoft.CodeAnalysis; using StableNameDotNet; using StableNameDotNet.Providers; using WasmDisassembler; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("Cpp2IL.Core.Tests")] [assembly: RegisterCpp2IlPlugin(typeof(Cpp2IlCorePlugin))] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("N/A")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Samboy063 2019-2023")] [assembly: AssemblyDescription("Reverses Unity's IL2CPP Build Process")] [assembly: AssemblyFileVersion("2022.1.0.0")] [assembly: AssemblyInformationalVersion("2022.1.0-pre-release.18+adebee78bcc7936a9d531da6679295e0b48d9614")] [assembly: AssemblyProduct("Cpp2IL.Core")] [assembly: AssemblyTitle("Cpp2IL.Core")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/SamboyCoding/Cpp2IL.git")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2022.1.0.0")] [assembly: TypeForwardedTo(typeof(IsExternalInit))] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] [Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] internal sealed class ObsoletedOSPlatformAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public ObsoletedOSPlatformAttribute(string platformName) { } public ObsoletedOSPlatformAttribute(string platformName, string? message) { Message = message; } } } namespace System.Runtime.CompilerServices2 { [AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)] [ExcludeFromCodeCoverage] [Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] internal sealed class InlineArrayAttribute : Attribute { public int Length { get; } public InlineArrayAttribute(int length) { Length = length; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] [ExcludeFromCodeCoverage] [Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] internal sealed class DisableRuntimeMarshallingAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] internal sealed class UnsafeAccessorAttribute : Attribute { public UnsafeAccessorKind Kind { get; } public string? Name { get; set; } public UnsafeAccessorAttribute(UnsafeAccessorKind kind) { Kind = kind; } } internal enum UnsafeAccessorKind { Constructor, Method, StaticMethod, Field, StaticField } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] [Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] internal sealed class RequiresDynamicCodeAttribute : Attribute { public string Message { get; } public string? Url { get; set; } public RequiresDynamicCodeAttribute(string message) { Message = message; } } } namespace Cpp2IL.Core { public static class Cpp2IlApi { public static ApplicationAnalysisContext? CurrentAppContext; public static Cpp2IlRuntimeArgs? RuntimeOptions; internal static bool LowMemoryMode => RuntimeOptions?.LowMemoryMode ?? false; [RequiresUnreferencedCode("Plugins are loaded dynamically.")] public static void Init(string pluginsDir = "Plugins") { Cpp2IlPluginManager.LoadFromDirectory(Path.Combine(Environment.CurrentDirectory, pluginsDir)); Cpp2IlPluginManager.InitAll(); } public static UnityVersion DetermineUnityVersion(string? unityPlayerPath, string? gameDataPath) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return LibCpp2IlMain.DetermineUnityVersion(unityPlayerPath, gameDataPath); } public static UnityVersion GetVersionFromGlobalGameManagers(byte[] ggmBytes) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return LibCpp2IlMain.GetVersionFromGlobalGameManagers(ggmBytes); } public static UnityVersion GetVersionFromDataUnity3D(Stream fileStream) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return LibCpp2IlMain.GetVersionFromDataUnity3D(fileStream); } public static void ConfigureLib(bool allowUserToInputAddresses) { LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput = allowUserToInputAddresses; LibCpp2IlMain.Settings.DisableMethodPointerMapping = false; LibLogger.Writer = (LogWriter)(object)new LibLogWriter(); } [MemberNotNull("CurrentAppContext")] public static void InitializeLibCpp2Il(string assemblyPath, string metadataPath, UnityVersion unityVersion, bool allowUserToInputAddresses = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (IsLibInitialized()) { ResetInternalState(); } ConfigureLib(allowUserToInputAddresses); try { if (!LibCpp2IlMain.LoadFromFile(assemblyPath, metadataPath, unityVersion)) { throw new Exception("Initialization with LibCpp2Il failed"); } } catch (Exception innerException) { throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", innerException); } OnLibInitialized(); } [MemberNotNull("CurrentAppContext")] public static void InitializeLibCpp2Il(byte[] assemblyData, byte[] metadataData, UnityVersion unityVersion, bool allowUserToInputAddresses = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (IsLibInitialized()) { ResetInternalState(); } ConfigureLib(allowUserToInputAddresses); try { if (!LibCpp2IlMain.Initialize(assemblyData, metadataData, unityVersion)) { throw new Exception("Initialization with LibCpp2Il failed"); } } catch (Exception innerException) { throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", innerException); } OnLibInitialized(); } [MemberNotNull("CurrentAppContext")] private static void OnLibInitialized() { MiscUtils.Init(); LibCpp2IlMain.Binary.AllCustomAttributeGenerators.ToList().ForEach(delegate(ulong ptr) { SharedState.AttributeGeneratorStarts.Add(ptr); }); DateTime now = DateTime.Now; Logger.InfoNewline("Creating application model..."); CurrentAppContext = new ApplicationAnalysisContext(LibCpp2IlMain.Binary, LibCpp2IlMain.TheMetadata, LibCpp2IlMain.MetadataVersion); Logger.InfoNewline($"Application model created in {(DateTime.Now - now).TotalMilliseconds}ms"); } public static void ResetInternalState() { SharedState.Clear(); MiscUtils.Reset(); LibCpp2IlMain.Reset(); CurrentAppContext = null; } private static bool IsLibInitialized() { if (LibCpp2IlMain.Binary != null) { return LibCpp2IlMain.TheMetadata != null; } return false; } } public class Cpp2IlCorePlugin : Cpp2IlPlugin { private sealed class AsmResolverDllOutputFormatLegacy : AsmResolverDllOutputFormatDefault { public override string OutputFormatId => "dummydll"; public override string OutputFormatName => "DLL output format for backwards compatibility."; } public override string Name => "Cpp2IL Built-In"; public override string Description => "Core Cpp2IL plugin containing built-in instruction sets, binaries, and other core functionality."; public override void OnLoad() { Logger.VerboseNewline("Initializing...", "Core Plugin"); DateTime now = DateTime.Now; Logger.VerboseNewline("\tRegistering built-in instruction set handlers...", "Core Plugin"); InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.X86_32); InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.X86_64); InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.WASM); InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.ARM_V7); if (Environment.GetEnvironmentVariable("CPP2IL_LEGACY_ARM64") != null) { InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.ARM_V8); } else { InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.ARM_V8); } Logger.VerboseNewline("\tRegistering built-in binary parsers...", "Core Plugin"); LibCpp2IlBinaryRegistry.RegisterBuiltInBinarySupport(); Logger.VerboseNewline("\tRegistering built-in output formats...", "Core Plugin"); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); Logger.VerboseNewline("\tRegistering built-in processing layers", "Core Plugin"); ProcessingLayerRegistry.Register(); ProcessingLayerRegistry.Register(); ProcessingLayerRegistry.Register(); ProcessingLayerRegistry.Register(); ProcessingLayerRegistry.Register(); ProcessingLayerRegistry.Register(); TimeSpan timeSpan = DateTime.Now - now; Logger.VerboseNewline($"Core plugin loaded in {timeSpan.Ticks} ticks ({timeSpan.TotalMilliseconds}ms)", "Core Plugin"); } } public static class Cpp2IlPluginManager { private static List _loadedPlugins = new List(); [RequiresUnreferencedCode("Plugins are loaded dynamically.")] internal static void LoadFromDirectory(string pluginsDir) { Logger.InfoNewline("Loading plugins from " + pluginsDir + "...", "Plugins"); if (!Directory.Exists(pluginsDir)) { return; } foreach (string item in Directory.EnumerateFiles(pluginsDir)) { if (Path.GetExtension(item) == ".dll") { Logger.VerboseNewline("\tLoading " + Path.GetFileName(item) + "...", "Plugins"); Assembly.LoadFrom(item); } } } internal static void InitAll() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Logger.VerboseNewline("Collecting and instantiating plugins...", "Plugins"); Assembly[] array = assemblies; foreach (Assembly assembly in array) { List list = assembly.GetCustomAttributes().ToList(); if (list.Count == 0) { continue; } foreach (RegisterCpp2IlPluginAttribute item2 in list) { Cpp2IlPlugin item; try { Logger.VerboseNewline($"\tLoading plugin {item2.PluginType.FullName} from assembly: {assembly.GetName().Name}.dll", "Plugins"); item = (Cpp2IlPlugin)Activator.CreateInstance(item2.PluginType); } catch (Exception value) { Logger.ErrorNewline($"Plugin {item2.PluginType.FullName} from assembly {assembly.GetName().Name} threw an exception during construction: {value}. It will not be loaded.", "Plugins"); continue; } _loadedPlugins.Add(item); } } Logger.VerboseNewline("Invoking OnLoad on " + _loadedPlugins.Count + " plugins.", "Plugins"); foreach (Cpp2IlPlugin loadedPlugin in _loadedPlugins) { try { loadedPlugin.OnLoad(); Logger.InfoNewline("Using Plugin: " + loadedPlugin.Name, "Plugins"); } catch (Exception value2) { Logger.ErrorNewline($"Plugin {loadedPlugin.GetType().FullName} threw an exception during OnLoad: {value2}. It will not receive any further events.", "Plugins"); _loadedPlugins.Remove(loadedPlugin); } } Logger.VerboseNewline("OnLoad complete", "Plugins"); } public static bool TryProcessGamePath(string gamePath, ref Cpp2IlRuntimeArgs args) { foreach (Cpp2IlPlugin loadedPlugin in _loadedPlugins) { if (loadedPlugin.HandleGamePath(gamePath, ref args)) { return true; } } return false; } public static void CallOnFinish() { foreach (Cpp2IlPlugin loadedPlugin in _loadedPlugins) { loadedPlugin.CallOnFinish(); } } } public class Cpp2IlRuntimeArgs { public bool Valid; public UnityVersion UnityVersion; public string PathToAssembly; public string PathToMetadata; public string? WasmFrameworkJsFile; public List ProcessingLayersToRun = new List(); public readonly Dictionary ProcessingLayerConfigurationOptions = new Dictionary(); public Cpp2IlOutputFormat? OutputFormat; public string OutputRootDirectory; public bool LowMemoryMode; } public static class Il2CppArrayUtils { public class UsefulOffset { public string name; public uint offset; public Type type; public bool is32Bit; public UsefulOffset(string name, uint offset, Type type, bool is32Bit) { this.name = name; this.offset = offset; this.type = type; this.is32Bit = is32Bit; base..ctor(); } } public static uint FirstItemOffset = (((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 16u : 32u); public static readonly List UsefulOffsets = new List(2) { new UsefulOffset("length", 12u, typeof(int), is32Bit: true), new UsefulOffset("length", 24u, typeof(int), is32Bit: false) }; public static string? GetOffsetName(uint offset) { bool is32Bit = ((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit; return UsefulOffsets.FirstOrDefault((UsefulOffset o) => o.is32Bit == is32Bit && o.offset == offset)?.name; } public static bool IsIl2cppLengthAccessor(uint offset) { return GetOffsetName(offset) == "length"; } public static bool IsAtLeastFirstItemPtr(uint offset) { return offset >= FirstItemOffset; } } public static class Il2CppClassUsefulOffsets { public class UsefulOffset { public string name; public uint offset; public Type type; public bool is32Bit; public UsefulOffset(string name, uint offset, Type type, bool is32Bit) { this.name = name; this.offset = offset; this.type = type; this.is32Bit = is32Bit; base..ctor(); } } public const int X86_INTERFACE_OFFSETS_OFFSET = 80; public const int X86_64_INTERFACE_OFFSETS_OFFSET = 176; private static readonly int V24_2_VTABLE_OFFSET = (((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 2457 : 312); private static readonly int PRE_24_2_VTABLE_OFFSET = (((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 2457 : 296); public static readonly int VTABLE_OFFSET = (((double)LibCpp2IlMain.MetadataVersion >= 24.2) ? V24_2_VTABLE_OFFSET : PRE_24_2_VTABLE_OFFSET); public static readonly List UsefulOffsets = new List(13) { new UsefulOffset("cctor_finished", 116u, typeof(uint), is32Bit: true), new UsefulOffset("flags1", 187u, typeof(byte), is32Bit: true), new UsefulOffset("interfaceOffsets", 80u, typeof(IntPtr), is32Bit: true), new UsefulOffset("static_fields", 92u, typeof(IntPtr), is32Bit: true), new UsefulOffset("elementType", 64u, typeof(IntPtr), is32Bit: false), new UsefulOffset("interfaceOffsets", 176u, typeof(IntPtr), is32Bit: false), new UsefulOffset("static_fields", 184u, typeof(IntPtr), is32Bit: false), new UsefulOffset("rgctx_data", 192u, typeof(IntPtr), is32Bit: false), new UsefulOffset("cctor_finished", 224u, typeof(uint), is32Bit: false), new UsefulOffset("interface_offsets_count", 298u, typeof(ushort), is32Bit: false), new UsefulOffset("flags1", 306u, typeof(byte), is32Bit: false), new UsefulOffset("flags2", 307u, typeof(byte), is32Bit: false), new UsefulOffset("vtable", 312u, typeof(IntPtr), is32Bit: false) }; public static bool IsStaticFieldsPtr(uint offset) { return GetOffsetName(offset) == "static_fields"; } public static bool IsInterfaceOffsetsPtr(uint offset) { return GetOffsetName(offset) == "interfaceOffsets"; } public static bool IsInterfaceOffsetsCount(uint offset) { return GetOffsetName(offset) == "interface_offsets_count"; } public static bool IsRGCTXDataPtr(uint offset) { return GetOffsetName(offset) == "rgctx_data"; } public static bool IsElementTypePtr(uint offset) { return GetOffsetName(offset) == "elementType"; } public static bool IsPointerIntoVtable(uint offset) { return offset >= VTABLE_OFFSET; } public static string? GetOffsetName(uint offset) { bool is32Bit = ((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit; return UsefulOffsets.FirstOrDefault((UsefulOffset o) => o.is32Bit == is32Bit && o.offset == offset)?.name; } } public static class Il2CppMethodDefinitionUsefulOffsets { public class UsefulOffset { public string name; public uint offset; public Type type; public bool is32Bit; public UsefulOffset(string name, uint offset, Type type, bool is32Bit) { this.name = name; this.offset = offset; this.type = type; this.is32Bit = is32Bit; base..ctor(); } } public const int X86_SLOT_OFFSET = 0; public const int X86_64_SLOT_OFFSET = 72; public static readonly List UsefulOffsets = new List(4) { new UsefulOffset("slot", 0u, typeof(ushort), is32Bit: true), new UsefulOffset("slot", 72u, typeof(ushort), is32Bit: false), new UsefulOffset("klass", 24u, typeof(IntPtr), is32Bit: false), new UsefulOffset("methodPtr", 48u, typeof(IntPtr), is32Bit: false) }; public static bool IsSlotOffset(uint offset) { return GetOffsetName(offset) == "slot"; } public static bool IsKlassPtr(uint offset) { return GetOffsetName(offset) == "klass"; } public static bool IsMethodPtr(uint offset) { return GetOffsetName(offset) == "methodPtr"; } public static string? GetOffsetName(uint offset) { bool is32Bit = ((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit; return UsefulOffsets.FirstOrDefault((UsefulOffset o) => o.is32Bit == is32Bit && o.offset == offset)?.name; } } public static class Il2CppMethodInfoUsefulOffsets { public class UsefulOffset { public string name; public uint offset; public Type type; public bool is32Bit; public UsefulOffset(string name, uint offset, Type type, bool is32Bit) { this.name = name; this.offset = offset; this.type = type; this.is32Bit = is32Bit; base..ctor(); } } public const int X86_KLASS_OFFSET = 0; public const int X86_64_KLASS_OFFSET = 24; public static readonly List UsefulOffsets = new List(2) { new UsefulOffset("klass", 0u, typeof(ushort), is32Bit: true), new UsefulOffset("klass", 24u, typeof(IntPtr), is32Bit: false) }; public static bool IsKlassPtr(uint offset) { return GetOffsetName(offset) == "klass"; } public static string? GetOffsetName(uint offset) { bool is32Bit = ((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit; return UsefulOffsets.FirstOrDefault((UsefulOffset o) => o.is32Bit == is32Bit && o.offset == offset)?.name; } } public static class SharedState { internal static readonly Dictionary ConcreteImplementations = new Dictionary(); internal static readonly HashSet AttributeGeneratorStarts = new HashSet(); internal static void Clear() { AsmResolverUtils.GenericParamsByIndexNew.Clear(); AsmResolverUtils.TypeDefsByIndex.Clear(); TypeDefinitionsAsmResolver.Reset(); ConcreteImplementations.Clear(); AttributeGeneratorStarts.Clear(); } } } namespace Cpp2IL.Core.Utils { public static class Arm64Utils { private static readonly ConcurrentDictionary CachedArm64RegNamesNew = new ConcurrentDictionary(); private static CapstoneArm64Disassembler? _arm64Disassembler; public static string GetRegisterNameNew(Arm64RegisterId registerId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Invalid comparison between Unknown and I4 //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected I4, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Invalid comparison between Unknown and I4 //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Invalid comparison between Unknown and I4 //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Invalid comparison between Unknown and I4 //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Invalid comparison between Unknown and I4 //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Invalid comparison between Unknown and I4 //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Invalid comparison between Unknown and I4 //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Invalid comparison between Unknown and I4 //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Invalid comparison between Unknown and I4 //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected I4, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Invalid comparison between Unknown and I4 //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) Arm64RegisterId key = registerId; if ((int)registerId == 0) { return ""; } if (CachedArm64RegNamesNew.TryGetValue(key, out string value)) { return value; } if ((int)registerId >= 168 && (int)registerId <= 198) { registerId = (Arm64RegisterId)(registerId - 168 + 199); } if ((int)registerId >= 199 && (int)registerId <= 227) { value = $"x{registerId - 199}"; CachedArm64RegNamesNew[key] = value; return value; } if ((int)registerId == 4) { CachedArm64RegNamesNew[key] = "sp"; return "sp"; } if ((int)registerId == 1) { CachedArm64RegNamesNew[key] = "fp"; return "fp"; } if ((int)registerId == 2) { CachedArm64RegNamesNew[key] = "lr"; return "lr"; } if (registerId - 6 <= 1) { CachedArm64RegNamesNew[key] = "xzr"; return "xzr"; } if ((int)registerId >= 8 && (int)registerId <= 39) { registerId = (Arm64RegisterId)(registerId - 8 + 228); } if ((int)registerId >= 72 && (int)registerId <= 103) { registerId = (Arm64RegisterId)(registerId - 72 + 228); } if ((int)registerId >= 8 && (int)registerId <= 39) { registerId = (Arm64RegisterId)(registerId - 8 + 228); } if ((int)registerId >= 40 && (int)registerId <= 71) { registerId = (Arm64RegisterId)(registerId - 40 + 228); } if ((int)registerId >= 104 && (int)registerId <= 135) { registerId = (Arm64RegisterId)(registerId - 104 + 228); } value = $"v{registerId - 228}"; CachedArm64RegNamesNew[key] = value; return value; } private static void InitArm64Decompilation() { CapstoneArm64Disassembler obj = CapstoneDisassembler.CreateArm64Disassembler((Arm64DisassembleMode)(((EndianAwareBinaryReader)LibCpp2IlMain.Binary).IsBigEndian ? int.MinValue : 0)); ((CapstoneDisassembler)obj).EnableInstructionDetails = true; ((CapstoneDisassembler)obj).EnableSkipDataMode = true; ((CapstoneDisassembler)(object)obj).DisassembleSyntax = (DisassembleSyntax)1; _arm64Disassembler = obj; } public static List GetArm64MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) { if (_arm64Disassembler == null) { InitArm64Decompilation(); } if (managed) { ulong addressOfNextFunctionStart = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); if (addressOfNextFunctionStart != 0) { long num = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(addressOfNextFunctionStart, true); long num2 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); if (num < num2) { num = LibCpp2IlMain.Binary.RawLength; } byte[] array = LibCpp2IlMain.Binary.GetRawBinaryContent().SubArray((int)num2..(int)num); IEnumerable source = ((CapstoneDisassembler)(object)_arm64Disassembler).Iterate(array, (long)virtAddress); if (count > 0) { source = source.Take(count); } return source.ToList(); } } int num3 = (int)LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); byte[] rawBinaryContent = LibCpp2IlMain.Binary.GetRawBinaryContent(); List list = new List(); while (!list.Any(delegate(Arm64Instruction i) { string mnemonic = ((Instruction)(object)i).Mnemonic; return (mnemonic == "b" || mnemonic == ".byte") ? true : false; }) && (count == -1 || list.Count < count)) { list.AddRange(((CapstoneDisassembler)(object)_arm64Disassembler).Iterate(rawBinaryContent.SubArray(num3..(num3 + 4)), (long)virtAddress)); virtAddress += 4; num3 += 4; } return list; } } public static class ArmV7Utils { private static CapstoneArmDisassembler? _armDisassembler; private static void InitArmDecompilation() { CapstoneArmDisassembler obj = CapstoneDisassembler.CreateArmDisassembler((ArmDisassembleMode)0); ((CapstoneDisassembler)obj).EnableInstructionDetails = true; ((CapstoneDisassembler)obj).EnableSkipDataMode = true; ((CapstoneDisassembler)(object)obj).DisassembleSyntax = (DisassembleSyntax)1; _armDisassembler = obj; } public static byte[]? TryGetMethodBodyBytesFast(ulong virtAddress, bool isCAGen) { ulong addressOfNextFunctionStart = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); ulong num = addressOfNextFunctionStart - virtAddress; if (isCAGen && num > 50000) { return null; } if (addressOfNextFunctionStart == 0) { return null; } long num2 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(addressOfNextFunctionStart, true); long num3 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); if (num2 < num3) { num2 = LibCpp2IlMain.Binary.RawLength; } return LibCpp2IlMain.Binary.GetRawBinaryContent().SubArray((int)num3..(int)num2); } public static List GetArmV7MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) { if (_armDisassembler == null) { InitArmDecompilation(); } if (managed) { ulong addressOfNextFunctionStart = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); if (addressOfNextFunctionStart != 0) { long num = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(addressOfNextFunctionStart, true); long num2 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); if (num < num2) { num = LibCpp2IlMain.Binary.RawLength; } byte[] array = LibCpp2IlMain.Binary.GetRawBinaryContent().SubArray((int)num2..(int)num); IEnumerable source = ((CapstoneDisassembler)(object)_armDisassembler).Iterate(array, (long)virtAddress); if (count > 0) { source = source.Take(count); } return source.ToList(); } } int num3 = (int)LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); byte[] rawBinaryContent = LibCpp2IlMain.Binary.GetRawBinaryContent(); List list = new List(); while (!list.Any(delegate(ArmInstruction i) { string mnemonic = ((Instruction)(object)i).Mnemonic; return (mnemonic == "b" || mnemonic == ".byte") ? true : false; }) && (count == -1 || list.Count < count)) { list.AddRange(((CapstoneDisassembler)(object)_armDisassembler).Iterate(rawBinaryContent.SubArray(num3..(num3 + 4)), (long)virtAddress)); virtAddress += 4; num3 += 4; } return list; } } public static class AttributeInjectionUtils { public static Dictionary InjectZeroParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType); ApplyAttributeUsageAttribute(appContext, multiAssemblyInjectedType, attributeTargets, allowMultiple); return multiAssemblyInjectedType.InjectConstructor(false); } public static Dictionary InjectOneParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, TypeAnalysisContext fieldType, string fieldName) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType); ApplyAttributeUsageAttribute(appContext, multiAssemblyInjectedType, attributeTargets, allowMultiple); Dictionary fields = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fieldName, fieldType, FieldAttributes.Public); Dictionary constructors = multiAssemblyInjectedType.InjectConstructor(false); return multiAssemblyInjectedType.InjectedTypes.ToDictionary((InjectedTypeAnalysisContext t) => t.DeclaringAssembly, (InjectedTypeAnalysisContext t) => (constructors[t.DeclaringAssembly], fields[t.DeclaringAssembly])); } public static Dictionary InjectTwoParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, TypeAnalysisContext fieldType1, string fieldName1, TypeAnalysisContext fieldType2, string fieldName2) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType); ApplyAttributeUsageAttribute(appContext, multiAssemblyInjectedType, attributeTargets, allowMultiple); Dictionary firstFields = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fieldName1, fieldType1, FieldAttributes.Public); Dictionary secondFields = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fieldName2, fieldType2, FieldAttributes.Public); Dictionary constructors = multiAssemblyInjectedType.InjectConstructor(false); return multiAssemblyInjectedType.InjectedTypes.ToDictionary((InjectedTypeAnalysisContext t) => t.DeclaringAssembly, (InjectedTypeAnalysisContext t) => (constructors[t.DeclaringAssembly], firstFields[t.DeclaringAssembly], secondFields[t.DeclaringAssembly])); } public static Dictionary InjectThreeParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, TypeAnalysisContext fieldType1, string fieldName1, TypeAnalysisContext fieldType2, string fieldName2, TypeAnalysisContext fieldType3, string fieldName3) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType); ApplyAttributeUsageAttribute(appContext, multiAssemblyInjectedType, attributeTargets, allowMultiple); Dictionary firstFields = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fieldName1, fieldType1, FieldAttributes.Public); Dictionary secondFields = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fieldName2, fieldType2, FieldAttributes.Public); Dictionary thirdFields = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fieldName3, fieldType3, FieldAttributes.Public); Dictionary constructors = multiAssemblyInjectedType.InjectConstructor(false); return multiAssemblyInjectedType.InjectedTypes.ToDictionary((InjectedTypeAnalysisContext t) => t.DeclaringAssembly, (InjectedTypeAnalysisContext t) => (constructors[t.DeclaringAssembly], firstFields[t.DeclaringAssembly], secondFields[t.DeclaringAssembly], thirdFields[t.DeclaringAssembly])); } public static Dictionary InjectAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, params (TypeAnalysisContext, string)[] fields) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType); ApplyAttributeUsageAttribute(appContext, multiAssemblyInjectedType, attributeTargets, allowMultiple); Dictionary[] injectedFields = new Dictionary[fields.Length]; for (int i = 0; i < fields.Length; i++) { injectedFields[i] = multiAssemblyInjectedType.InjectFieldToAllAssemblies(fields[i].Item2, fields[i].Item1, FieldAttributes.Public); } Dictionary constructors = multiAssemblyInjectedType.InjectConstructor(false); return multiAssemblyInjectedType.InjectedTypes.ToDictionary((InjectedTypeAnalysisContext t) => t.DeclaringAssembly, (InjectedTypeAnalysisContext t) => (constructors[t.DeclaringAssembly], injectedFields.Select((Dictionary d) => d[t.DeclaringAssembly]).ToArray())); } private static void ApplyAttributeUsageAttribute(ApplicationAnalysisContext appContext, MultiAssemblyInjectedType multiAssemblyInjectedType, AttributeTargets attributeTargets, bool allowMultiple) { AssemblyAnalysisContext? obj = appContext.GetAssemblyByName("mscorlib") ?? throw new Exception("Could not find mscorlib"); Il2CppType attributeTargetsType = GetAttributeTargetsType(obj); TypeAnalysisContext? obj2 = obj.GetTypeByFullName("System.AttributeUsageAttribute") ?? throw new Exception("Could not find AttributeUsageAttribute"); MethodAnalysisContext constructor = obj2.Methods.First((MethodAnalysisContext m) => (m.MethodAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public && m.Name == ".ctor"); PropertyAnalysisContext property = obj2.Properties.First((PropertyAnalysisContext p) => p.Name == "AllowMultiple"); InjectedTypeAnalysisContext[] injectedTypes = multiAssemblyInjectedType.InjectedTypes; foreach (InjectedTypeAnalysisContext obj3 in injectedTypes) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); CustomAttributeEnumParameter customAttributeEnumParameter = new CustomAttributeEnumParameter(attributeTargetsType, appContext, analyzedCustomAttribute, CustomAttributeParameterKind.ConstructorParam, 0); customAttributeEnumParameter.UnderlyingPrimitiveParameter.PrimitiveValue = (int)attributeTargets; analyzedCustomAttribute.ConstructorParameters.Add(customAttributeEnumParameter); analyzedCustomAttribute.Properties.Add(new CustomAttributeProperty(property, new CustomAttributePrimitiveParameter((IConvertible)allowMultiple, analyzedCustomAttribute, CustomAttributeParameterKind.Property, 1))); obj3.AnalyzeCustomAttributeData(); obj3.CustomAttributes.Add(analyzedCustomAttribute); } } public static void AddZeroParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor) { AnalyzedCustomAttribute item = new AnalyzedCustomAttribute(constructor); customAttributeHolder.CustomAttributes.Add(item); } public static void AddOneParameterAttribute(HasCustomAttributes customAttributeHolder, (MethodAnalysisContext, FieldAnalysisContext) attributeInfo, object fieldValue) { AddOneParameterAttribute(customAttributeHolder, attributeInfo.Item1, attributeInfo.Item2, fieldValue); } public static void AddOneParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, FieldAnalysisContext field, object fieldValue) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field, MakeFieldParameter(fieldValue, analyzedCustomAttribute, 0))); customAttributeHolder.CustomAttributes.Add(analyzedCustomAttribute); } public static void AddTwoParameterAttribute(HasCustomAttributes customAttributeHolder, (MethodAnalysisContext, FieldAnalysisContext, FieldAnalysisContext) attributeInfo, object fieldValue1, object fieldValue2) { AddTwoParameterAttribute(customAttributeHolder, attributeInfo.Item1, attributeInfo.Item2, fieldValue1, attributeInfo.Item3, fieldValue2); } public static void AddTwoParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, FieldAnalysisContext field1, object fieldValue1, FieldAnalysisContext field2, object fieldValue2) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field1, MakeFieldParameter(fieldValue1, analyzedCustomAttribute, 0))); analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field2, MakeFieldParameter(fieldValue2, analyzedCustomAttribute, 1))); customAttributeHolder.CustomAttributes.Add(analyzedCustomAttribute); } public static void AddAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, params (FieldAnalysisContext, object)[] fields) { AddAttribute(customAttributeHolder, constructor, fields.AsEnumerable()); } public static void AddAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, IEnumerable<(FieldAnalysisContext, object)> fields) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); int num = 0; foreach (var field in fields) { analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field.Item1, MakeFieldParameter(field.Item2, analyzedCustomAttribute, num))); num++; } customAttributeHolder.CustomAttributes.Add(analyzedCustomAttribute); } private static Il2CppType GetAttributeTargetsType(AssemblyAnalysisContext mscorlibAssembly) { TypeAnalysisContext typeAnalysisContext = mscorlibAssembly.GetTypeByFullName("System.AttributeTargets") ?? throw new Exception("Could not find AttributeTargets"); if (typeAnalysisContext.Definition == null) { throw new NullReferenceException("AttributeTargets had a null Definition"); } return LibCpp2IlReflection.GetTypeFromDefinition(typeAnalysisContext.Definition) ?? throw new Exception("Could not get the Il2CppType for AttributeTargets"); } private static BaseCustomAttributeParameter MakeFieldParameter(object fieldValue, AnalyzedCustomAttribute owner, int index) { return MakeCustomAttributeParameter(fieldValue, owner, index, CustomAttributeParameterKind.Field); } private static BaseCustomAttributeParameter MakeCustomAttributeParameter(object? value, AnalyzedCustomAttribute owner, int index, CustomAttributeParameterKind parameterKind) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) AnalyzedCustomAttribute owner2 = owner; Il2CppType val = (Il2CppType)((value is Il2CppType) ? value : null); if (val == null) { if (!(value is TypeAnalysisContext type)) { if (!(value is TypeAnalysisContext[] source)) { if (!(value is object[] source2)) { if (!(value is IConvertible value2)) { if (value == null) { return new CustomAttributeNullParameter(owner2, parameterKind, index); } throw new NotSupportedException(); } return new CustomAttributePrimitiveParameter(value2, owner2, parameterKind, index); } return new CustomAttributeArrayParameter(owner2, parameterKind, index) { ArrType = (Il2CppTypeEnum)28, ArrayElements = source2.Select((object obj) => (obj != null) ? MakeCustomAttributeParameter(obj, owner2, index, CustomAttributeParameterKind.ArrayElement) : new CustomAttributeNullParameter(owner2, CustomAttributeParameterKind.ArrayElement, index)).ToList() }; } return new CustomAttributeArrayParameter(owner2, parameterKind, index) { ArrType = (Il2CppTypeEnum)255, ArrayElements = ((IEnumerable)source).Select((Func)((TypeAnalysisContext t) => new InjectedCustomAttributeTypeParameter(t, owner2, CustomAttributeParameterKind.ArrayElement, index))).ToList() }; } return new InjectedCustomAttributeTypeParameter(type, owner2, parameterKind, index); } return new CustomAttributeTypeParameter(val, owner2, parameterKind, index); } } public static class CsFileUtils { public static string GetMethodParameterString(MethodAnalysisContext method) { StringBuilder stringBuilder = new StringBuilder(); bool flag = true; foreach (ParameterAnalysisContext parameter in method.Parameters) { if (!flag) { stringBuilder.Append(", "); } flag = false; stringBuilder.Append(parameter); } return stringBuilder.ToString(); } public static string GetKeyWordsForType(TypeAnalysisContext type) { StringBuilder stringBuilder = new StringBuilder(); TypeAttributes attributes = type.Definition.Attributes; if (attributes.HasFlag(TypeAttributes.NestedPrivate)) { stringBuilder.Append("private "); } else if (attributes.HasFlag(TypeAttributes.Public)) { stringBuilder.Append("public "); } else { stringBuilder.Append("internal "); } if (type.IsEnumType) { stringBuilder.Append("enum "); } else if (type.IsValueType) { stringBuilder.Append("struct "); } else if (attributes.HasFlag(TypeAttributes.ClassSemanticsMask)) { stringBuilder.Append("interface "); } else { if (attributes.HasFlag(TypeAttributes.Abstract) && attributes.HasFlag(TypeAttributes.Sealed)) { stringBuilder.Append("static "); } else if (attributes.HasFlag(TypeAttributes.Abstract)) { stringBuilder.Append("abstract "); } else if (attributes.HasFlag(TypeAttributes.Sealed)) { stringBuilder.Append("sealed "); } stringBuilder.Append("class "); } return stringBuilder.ToString().Trim(); } public static string GetKeyWordsForField(FieldAnalysisContext field) { StringBuilder stringBuilder = new StringBuilder(); FieldAttributes attributes = field.BackingData.Attributes; if (attributes.HasFlag(FieldAttributes.Public)) { stringBuilder.Append("public "); } else if (attributes.HasFlag(FieldAttributes.Family)) { stringBuilder.Append("protected "); } if (attributes.HasFlag(FieldAttributes.Assembly)) { stringBuilder.Append("internal "); } else if (attributes.HasFlag(FieldAttributes.Private)) { stringBuilder.Append("private "); } if (attributes.HasFlag(FieldAttributes.Literal)) { stringBuilder.Append("const "); } else { if (attributes.HasFlag(FieldAttributes.Static)) { stringBuilder.Append("static "); } if (attributes.HasFlag(FieldAttributes.InitOnly)) { stringBuilder.Append("readonly "); } } return stringBuilder.ToString().Trim(); } public static string GetKeyWordsForMethod(MethodAnalysisContext method, bool skipSlotRelated = false, bool skipKeywordsInvalidForAccessors = false) { StringBuilder stringBuilder = new StringBuilder(); MethodAttributes attributes = method.Definition.Attributes; if (!skipKeywordsInvalidForAccessors) { if (attributes.HasFlag(MethodAttributes.Public)) { stringBuilder.Append("public "); } else if (attributes.HasFlag(MethodAttributes.Family)) { stringBuilder.Append("protected "); } } if (attributes.HasFlag(MethodAttributes.Assembly)) { stringBuilder.Append("internal "); } else if (attributes.HasFlag(MethodAttributes.Private)) { stringBuilder.Append("private "); } if (!skipKeywordsInvalidForAccessors && attributes.HasFlag(MethodAttributes.Static)) { stringBuilder.Append("static "); } if (!(method.DeclaringType.Definition.Attributes.HasFlag(TypeAttributes.ClassSemanticsMask) || skipSlotRelated)) { if (attributes.HasFlag(MethodAttributes.Abstract)) { stringBuilder.Append("abstract "); } else if (attributes.HasFlag(MethodAttributes.VtableLayoutMask)) { stringBuilder.Append("override "); } else if (attributes.HasFlag(MethodAttributes.Virtual)) { stringBuilder.Append("virtual "); } } return stringBuilder.ToString().Trim(); } public static string GetKeyWordsForEvent(EventAnalysisContext evt) { StringBuilder stringBuilder = new StringBuilder(); MethodAttributes methodAttributes = evt.Adder?.Attributes ?? MethodAttributes.PrivateScope; MethodAttributes methodAttributes2 = evt.Remover?.Attributes ?? MethodAttributes.PrivateScope; MethodAttributes methodAttributes3 = evt.Invoker?.Attributes ?? MethodAttributes.PrivateScope; MethodAttributes methodAttributes4 = methodAttributes | methodAttributes2 | methodAttributes3; if (methodAttributes.HasFlag(MethodAttributes.Public) || methodAttributes2.HasFlag(MethodAttributes.Public) || methodAttributes3.HasFlag(MethodAttributes.Public)) { stringBuilder.Append("public "); } else if (methodAttributes4.HasFlag(MethodAttributes.Family)) { stringBuilder.Append("protected "); } if (methodAttributes.HasFlag(MethodAttributes.Assembly) || methodAttributes2.HasFlag(MethodAttributes.Assembly) || methodAttributes3.HasFlag(MethodAttributes.Assembly)) { stringBuilder.Append("internal "); } else if (methodAttributes4.HasFlag(MethodAttributes.Private)) { stringBuilder.Append("private "); } if (methodAttributes4.HasFlag(MethodAttributes.Static)) { stringBuilder.Append("static "); } if (!evt.DeclaringType.Definition.Attributes.HasFlag(TypeAttributes.ClassSemanticsMask)) { if (methodAttributes4.HasFlag(MethodAttributes.Abstract)) { stringBuilder.Append("abstract "); } else if (methodAttributes4.HasFlag(MethodAttributes.VtableLayoutMask)) { stringBuilder.Append("override "); } else if (methodAttributes4.HasFlag(MethodAttributes.Virtual)) { stringBuilder.Append("virtual "); } } stringBuilder.Append("event "); return stringBuilder.ToString().Trim(); } public static string GetKeyWordsForProperty(PropertyAnalysisContext prop) { StringBuilder stringBuilder = new StringBuilder(); MethodAttributes methodAttributes = prop.Getter?.Attributes ?? MethodAttributes.PrivateScope; MethodAttributes methodAttributes2 = prop.Setter?.Attributes ?? MethodAttributes.PrivateScope; MethodAttributes methodAttributes3 = methodAttributes | methodAttributes2; if (methodAttributes.HasFlag(MethodAttributes.Public) || methodAttributes2.HasFlag(MethodAttributes.Public)) { stringBuilder.Append("public "); } else if (methodAttributes3.HasFlag(MethodAttributes.Family)) { stringBuilder.Append("protected "); } if (methodAttributes.HasFlag(MethodAttributes.Assembly) || methodAttributes2.HasFlag(MethodAttributes.Assembly)) { stringBuilder.Append("internal "); } else if (methodAttributes3.HasFlag(MethodAttributes.Private)) { stringBuilder.Append("private "); } if (methodAttributes3.HasFlag(MethodAttributes.Static)) { stringBuilder.Append("static "); } if (!prop.DeclaringType.Definition.Attributes.HasFlag(TypeAttributes.ClassSemanticsMask)) { if (methodAttributes3.HasFlag(MethodAttributes.Abstract)) { stringBuilder.Append("abstract "); } else if (methodAttributes3.HasFlag(MethodAttributes.VtableLayoutMask)) { stringBuilder.Append("override "); } else if (methodAttributes3.HasFlag(MethodAttributes.Virtual)) { stringBuilder.Append("virtual "); } } return stringBuilder.ToString().Trim(); } public static string GetCustomAttributeStrings(HasCustomAttributes context, int indentCount, bool analyze = true, bool includeIncomplete = true) { StringBuilder stringBuilder = new StringBuilder(); if (analyze) { context.AnalyzeCustomAttributeData(); } Extensions.SortByExtractedKey(context.CustomAttributes, (Func)((AnalyzedCustomAttribute a) => a.Constructor.DeclaringType.Name)); foreach (AnalyzedCustomAttribute customAttribute in context.CustomAttributes) { if (includeIncomplete || customAttribute.IsSuitableForEmission) { if (indentCount > 0) { stringBuilder.Append('\t', indentCount); } try { stringBuilder.AppendLine(customAttribute.ToString()); } catch (Exception ex) { Logger.WarnNewline("Exception printing/formatting custom attribute: " + ex, "C# Generator"); stringBuilder.Append("/*Cpp2IL: Exception outputting custom attribute of type ").Append(customAttribute.Constructor.DeclaringType?.Name ?? "").AppendLine("*/"); } } } return stringBuilder.ToString(); } public static string GetTypeName(string originalName) { if (originalName.Contains("`")) { return originalName.Remove(originalName.IndexOf('`'), 2); } string text = originalName; if (text[text.Length - 1] == '&') { string text2 = originalName; originalName = text2.Substring(0, text2.Length - 1); } return originalName switch { "Void" => "void", "Boolean" => "bool", "Byte" => "byte", "SByte" => "sbyte", "Char" => "char", "Decimal" => "decimal", "Single" => "float", "Double" => "double", "Int32" => "int", "UInt32" => "uint", "Int64" => "long", "UInt64" => "ulong", "Int16" => "short", "UInt16" => "ushort", "String" => "string", "Object" => "object", _ => originalName, }; } public static void AppendInheritanceInfo(TypeAnalysisContext type, StringBuilder sb) { TypeAnalysisContext baseType = type.BaseType; int num; if (baseType != null) { string fullName = baseType.FullName; if (!(fullName == "System.Object") && !(fullName == "System.ValueType")) { num = ((!(fullName == "System.Enum")) ? 1 : 0); goto IL_003c; } } num = 0; goto IL_003c; IL_003c: bool flag = (byte)num != 0; if (flag) { sb.Append(" : ").Append(GetTypeName(baseType.Name)); } if (type.InterfaceContexts.Length == 0) { return; } if (!flag) { sb.Append(" : "); } bool flag2 = flag; TypeAnalysisContext[] interfaceContexts = type.InterfaceContexts; foreach (TypeAnalysisContext typeAnalysisContext in interfaceContexts) { if (flag2) { sb.Append(", "); } flag2 = true; sb.Append(GetTypeName(typeAnalysisContext.Name)); } } } internal static class GenericInstantiation { public static TypeAnalysisContext Instantiate(TypeAnalysisContext type, IReadOnlyList genericTypeParameters, IReadOnlyList genericMethodParameters) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 if (!(type is GenericParameterTypeAnalysisContext genericParameterTypeAnalysisContext)) { if (!(type is SzArrayTypeAnalysisContext szArrayTypeAnalysisContext)) { if (!(type is ArrayTypeAnalysisContext arrayTypeAnalysisContext)) { if (!(type is ByRefTypeAnalysisContext byRefTypeAnalysisContext)) { if (!(type is PointerTypeAnalysisContext pointerTypeAnalysisContext)) { if (type is GenericInstanceTypeAnalysisContext genericInstanceTypeAnalysisContext) { TypeAnalysisContext typeAnalysisContext = Instantiate(genericInstanceTypeAnalysisContext.GenericType, genericTypeParameters, genericMethodParameters); bool flag = typeAnalysisContext != genericInstanceTypeAnalysisContext.GenericType; TypeAnalysisContext[] array = new TypeAnalysisContext[genericInstanceTypeAnalysisContext.GenericArguments.Count]; for (int i = 0; i < genericInstanceTypeAnalysisContext.GenericArguments.Count; i++) { TypeAnalysisContext typeAnalysisContext2 = genericInstanceTypeAnalysisContext.GenericArguments[i]; flag |= (array[i] = Instantiate(typeAnalysisContext2, genericTypeParameters, genericMethodParameters)) != typeAnalysisContext2; } if (!flag) { return genericInstanceTypeAnalysisContext; } return new GenericInstanceTypeAnalysisContext(typeAnalysisContext, array, genericInstanceTypeAnalysisContext.DeclaringAssembly); } return type; } TypeAnalysisContext typeAnalysisContext3 = Instantiate(pointerTypeAnalysisContext.ElementType, genericTypeParameters, genericMethodParameters); if (typeAnalysisContext3 != pointerTypeAnalysisContext.ElementType) { return new PointerTypeAnalysisContext(typeAnalysisContext3, pointerTypeAnalysisContext.DeclaringAssembly); } return pointerTypeAnalysisContext; } TypeAnalysisContext typeAnalysisContext4 = Instantiate(byRefTypeAnalysisContext.ElementType, genericTypeParameters, genericMethodParameters); if (typeAnalysisContext4 != byRefTypeAnalysisContext.ElementType) { return new ByRefTypeAnalysisContext(typeAnalysisContext4, byRefTypeAnalysisContext.DeclaringAssembly); } return byRefTypeAnalysisContext; } TypeAnalysisContext typeAnalysisContext5 = Instantiate(arrayTypeAnalysisContext.ElementType, genericTypeParameters, genericMethodParameters); if (typeAnalysisContext5 != arrayTypeAnalysisContext.ElementType) { return new ArrayTypeAnalysisContext(typeAnalysisContext5, arrayTypeAnalysisContext.Rank, arrayTypeAnalysisContext.DeclaringAssembly); } return arrayTypeAnalysisContext; } TypeAnalysisContext typeAnalysisContext6 = Instantiate(szArrayTypeAnalysisContext.ElementType, genericTypeParameters, genericMethodParameters); if (typeAnalysisContext6 != szArrayTypeAnalysisContext.ElementType) { return new SzArrayTypeAnalysisContext(typeAnalysisContext6, szArrayTypeAnalysisContext.DeclaringAssembly); } return szArrayTypeAnalysisContext; } int index = genericParameterTypeAnalysisContext.Index; if ((int)genericParameterTypeAnalysisContext.Type == 19) { return genericTypeParameters[index]; } return genericMethodParameters[index]; } public static bool HasAnyGenericParameters(this TypeAnalysisContext type) { if (!(type is GenericParameterTypeAnalysisContext)) { if (!(type is SzArrayTypeAnalysisContext szArrayTypeAnalysisContext)) { if (!(type is ArrayTypeAnalysisContext arrayTypeAnalysisContext)) { if (!(type is ByRefTypeAnalysisContext byRefTypeAnalysisContext)) { if (!(type is PointerTypeAnalysisContext pointerTypeAnalysisContext)) { if (type is GenericInstanceTypeAnalysisContext genericInstanceTypeAnalysisContext) { return genericInstanceTypeAnalysisContext.GenericArguments.Any(HasAnyGenericParameters); } return false; } return pointerTypeAnalysisContext.ElementType.HasAnyGenericParameters(); } return byRefTypeAnalysisContext.ElementType.HasAnyGenericParameters(); } return arrayTypeAnalysisContext.ElementType.HasAnyGenericParameters(); } return szArrayTypeAnalysisContext.ElementType.HasAnyGenericParameters(); } return true; } } public static class Il2CppTypeReflectionDataToContext { public static TypeAnalysisContext? ToContext(this Il2CppTypeReflectionData reflectionData, AssemblyAnalysisContext assembly, int genericParamIndex = -1) { TypeAnalysisContext typeAnalysisContext2; if (reflectionData.isArray) { TypeAnalysisContext typeAnalysisContext = reflectionData.arrayType?.ToContext(assembly); if (typeAnalysisContext == null) { return null; } typeAnalysisContext2 = new ArrayTypeAnalysisContext(typeAnalysisContext, reflectionData.arrayRank, assembly); } else if (!reflectionData.isType) { typeAnalysisContext2 = new GenericParameterTypeAnalysisContext(reflectionData.variableGenericParamName, genericParamIndex, (Il2CppTypeEnum)19, assembly); } else if (!reflectionData.isGenericType) { typeAnalysisContext2 = ((reflectionData.baseType == null) ? null : assembly.AppContext.ResolveContextForType(reflectionData.baseType)); } else { TypeAnalysisContext typeAnalysisContext3 = ((reflectionData.baseType == null) ? null : assembly.AppContext.ResolveContextForType(reflectionData.baseType)); if (typeAnalysisContext3 == null) { return null; } TypeAnalysisContext[] array = new TypeAnalysisContext[reflectionData.genericParams.Length]; for (int i = 0; i < reflectionData.genericParams.Length; i++) { TypeAnalysisContext typeAnalysisContext4 = reflectionData.genericParams[i].ToContext(assembly, i); if (typeAnalysisContext4 == null) { return null; } array[i] = typeAnalysisContext4; } typeAnalysisContext2 = new GenericInstanceTypeAnalysisContext(typeAnalysisContext3, array, assembly); } if (reflectionData.isPointer && typeAnalysisContext2 != null) { return new PointerTypeAnalysisContext(typeAnalysisContext2, assembly); } return typeAnalysisContext2; } } public static class Il2CppTypeToContext { private static TypeAnalysisContext GetPrimitive(this SystemTypesContext context, Il2CppTypeEnum type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected I4, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 switch (type - 1) { default: if ((int)type != 255) { break; } return context.SystemTypeType; case 27: return context.SystemObjectType; case 0: return context.SystemVoidType; case 1: return context.SystemBooleanType; case 2: return context.SystemCharType; case 3: return context.SystemSByteType; case 4: return context.SystemByteType; case 5: return context.SystemInt16Type; case 6: return context.SystemUInt16Type; case 7: return context.SystemInt32Type; case 8: return context.SystemUInt32Type; case 23: return context.SystemIntPtrType; case 24: return context.SystemUIntPtrType; case 9: return context.SystemInt64Type; case 10: return context.SystemUInt64Type; case 11: return context.SystemSingleType; case 12: return context.SystemDoubleType; case 13: return context.SystemStringType; case 21: return context.SystemTypedReferenceType; case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 22: case 25: case 26: break; } throw new ArgumentException("Type is not a primitive", "type"); } [return: NotNullIfNotNull("type")] public static TypeAnalysisContext? ResolveIl2CppType(this AssemblyAnalysisContext context, Il2CppType? type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Invalid comparison between Unknown and I4 //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 if (type == null) { return null; } TypeAnalysisContext typeAnalysisContext; if (Il2CppTypeEnumExtensions.IsIl2CppPrimitive(type.Type)) { typeAnalysisContext = context.AppContext.SystemTypes.GetPrimitive(type.Type); } else { Il2CppTypeEnum type2 = type.Type; if (type2 - 17 <= 1) { typeAnalysisContext = context.AppContext.ResolveContextForType(type.AsClass()) ?? throw new Exception("Could not resolve type context for type " + type.AsClass().FullName); } else if ((int)type.Type == 21) { typeAnalysisContext = new GenericInstanceTypeAnalysisContext(type, context); } else { type2 = type.Type; bool flag = ((type2 - 15 <= 1 || (int)type2 == 20 || (int)type2 == 29) ? true : false); typeAnalysisContext = ((!flag) ? ((ReferencedTypeAnalysisContext)new GenericParameterTypeAnalysisContext(type, context)) : ((ReferencedTypeAnalysisContext)WrappedTypeAnalysisContext.Create(type, context))); } } if (type.Byref == 1) { typeAnalysisContext = typeAnalysisContext.MakeByReferenceType(); } return typeAnalysisContext; } } public static class MiscUtils { private static List? _allKnownFunctionStarts; private static Dictionary _primitiveSizes = new Dictionary(); public static readonly List InvalidPathChars = new List(9) { '<', '>', ':', '"', '/', '\\', '|', '?', '*' }; public static readonly HashSet InvalidPathElements = new HashSet { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; public static readonly string[] BlacklistedExecutableFilenames = new string[7] { "UnityCrashHandler.exe", "UnityCrashHandler32.exe", "UnityCrashHandler64.exe", "install.exe", "launch.exe", "MelonLoader.Installer.exe", "crashpad_handler.exe" }; internal static void Reset() { _allKnownFunctionStarts = null; } internal static void Init() { _primitiveSizes = new Dictionary(14) { { "Byte", 1uL }, { "SByte", 1uL }, { "Boolean", 1uL }, { "Int16", 2uL }, { "UInt16", 2uL }, { "Char", 2uL }, { "Int32", 4uL }, { "UInt32", 4uL }, { "Single", 4uL }, { "Int64", 8uL }, { "UInt64", 8uL }, { "Double", 8uL }, { "IntPtr", (ulong)(((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 4 : 8) }, { "UIntPtr", (ulong)(((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 4 : 8) } }; } internal static string[] GetGenericParams(string input) { if (!input.Contains('<')) { return input.Split(','); } int num = 0; List list = new List(); StringBuilder stringBuilder = new StringBuilder(); foreach (char c in input) { if (c == '<') { num++; } if (c == '>') { num--; } if (num == 0 && c == ',') { list.Add(stringBuilder.ToString()); stringBuilder.Clear(); } else { stringBuilder.Append(c); } } list.Add(stringBuilder.ToString()); return list.ToArray(); } public static string? TryGetLiteralAt(Il2CppBinary theDll, ulong rawAddr) { if (theDll.RawLength <= (long)rawAddr) { return null; } char c = Convert.ToChar(theDll.GetByteAtRawAddress(rawAddr)); if (char.IsLetterOrDigit(c) || char.IsPunctuation(c) || char.IsSymbol(c) || char.IsWhiteSpace(c)) { bool flag = theDll.GetByteAtRawAddress(rawAddr + 1) == 0 && theDll.GetByteAtRawAddress(rawAddr + 3) == 0; StringBuilder stringBuilder = new StringBuilder(); while ((theDll.GetByteAtRawAddress(rawAddr) != 0 || (flag && theDll.GetByteAtRawAddress(rawAddr + 1) != 0)) && stringBuilder.Length < 5000) { stringBuilder.Append(Convert.ToChar(theDll.GetByteAtRawAddress(rawAddr))); rawAddr++; if (flag) { rawAddr++; } } bool flag2 = theDll.GetByteAtRawAddress(rawAddr) == 0; if (stringBuilder.Length >= 4 || flag2) { return stringBuilder.ToString(); } } else if (c == '\0') { return string.Empty; } return null; } public static int GetSlotNum(int offset) { int num = offset - Il2CppClassUsefulOffsets.VTABLE_OFFSET; if (num % 16 != 0 && num % 8 == 0) { num -= 8; } if (num > 0) { return (int)((decimal)num / 16m); } return -1; } public static int GetPointerSizeBytes() { if (!((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit) { return 8; } return 4; } internal static byte[] RawBytes(IConvertible original) { if (!(original is bool value)) { if (!(original is char value2)) { if (!(original is byte b)) { if (!(original is sbyte b2)) { if (!(original is ushort value3)) { if (!(original is short value4)) { if (!(original is uint value5)) { if (!(original is int value6)) { if (!(original is ulong value7)) { if (!(original is long value8)) { if (!(original is float value9)) { if (original is double value10) { return BitConverter.GetBytes(value10); } throw new Exception($"ReinterpretBytes: Cannot get byte array from {original} (type {original.GetType()}"); } return BitConverter.GetBytes(value9); } return BitConverter.GetBytes(value8); } return BitConverter.GetBytes(value7); } return BitConverter.GetBytes(value6); } return BitConverter.GetBytes(value5); } return BitConverter.GetBytes(value4); } return BitConverter.GetBytes(value3); } return new byte[1] { (byte)b2 }; } return new byte[1] { b }; } return BitConverter.GetBytes(value2); } return BitConverter.GetBytes(value); } private static void InitFunctionStarts() { _allKnownFunctionStarts = LibCpp2IlMain.TheMetadata.methodDefs.Select((Il2CppMethodDefinition m) => m.MethodPointer).Concat(LibCpp2IlMain.Binary.ConcreteGenericImplementationsByAddress.Keys).Concat(SharedState.AttributeGeneratorStarts) .ToList(); _allKnownFunctionStarts.Sort(); } public static ulong GetAddressOfNextFunctionStart(ulong current) { if (_allKnownFunctionStarts == null) { InitFunctionStarts(); } int num = 0; int num2 = _allKnownFunctionStarts.Count - 1; ulong num3 = ulong.MaxValue; while (num2 - num >= 1) { int num4 = (num2 - num) / 2 + num; if (num2 - num == 1) { num4 = num; } ulong num5 = _allKnownFunctionStarts[num4]; if (num5 > current) { if (num5 < num3) { num3 = num5; } num2 = num4; } else { num = num4 + 1; } } num3 = _allKnownFunctionStarts[num]; if (num3 < current) { num3 = _allKnownFunctionStarts[num2]; } if (num3 <= current && num2 == _allKnownFunctionStarts.Count - 1) { return 0uL; } long num6 = default(long); if (!LibCpp2IlMain.Binary.TryMapVirtualAddressToRaw(num3, ref num6)) { return 0uL; } return num3; } public static void ExecuteSerial(IEnumerable enumerable, Action what) { foreach (T item in enumerable) { what(item); } } public static void ExecuteParallel(IEnumerable enumerable, Action what) { Action what2 = what; enumerable.AsParallel().Select(F2).ToList(); bool F2(T t) { what2(t); return true; } } public static string AnalyzeStackTracePointers(ulong[] pointers) { List methodsSortedByPointer = LibCpp2IlMain.TheMetadata.methodDefs.ToList(); Extensions.SortByExtractedKey(methodsSortedByPointer, (Func)((Il2CppMethodDefinition m) => m.MethodPointer)); List>> genericMethodsSortedByPointer = LibCpp2IlMain.Binary.ConcreteGenericImplementationsByAddress.ToList(); Extensions.SortByExtractedKey>, ulong>(genericMethodsSortedByPointer, (Func>, ulong>)((KeyValuePair> m) => m.Key)); IEnumerable values = pointers.Select(delegate(ulong p) { Il2CppMethodDefinition val = ((IEnumerable)methodsSortedByPointer).LastOrDefault((Func)((Il2CppMethodDefinition m) => m.MethodPointer <= p)); KeyValuePair> keyValuePair = genericMethodsSortedByPointer.LastOrDefault((KeyValuePair> m) => m.Key <= p); if (val == null || keyValuePair.Key == 0L) { return ""; } ulong num = p - val.MethodPointer; ulong num2 = p - keyValuePair.Key; if (Math.Min(num2, num) > 327680) { return ""; } if (num2 < num) { Cpp2IlMethodRef val2 = keyValuePair.Value.First(); return val2.DeclaringType.DeclaringAssembly.Name + " ## " + ((object)val2)?.ToString() + "(" + string.Join(", ", val2.BaseMethod.Parameters.ToList()) + ")"; } return val.DeclaringType.DeclaringAssembly.Name + " ## " + val.DeclaringType.FullName + "::" + val.Name + "(" + string.Join(", ", val.Parameters.ToList()) + ")"; }); return string.Join("\n", values); } public static string CleanPathElement(string input) { string input2 = input; InvalidPathChars.ForEach(delegate(char c) { input2 = input2.Replace(c, '_'); }); if (!InvalidPathElements.Contains(input2)) { return input2; } return "__invalidwin32name_" + input2 + "__"; } } public static class NewArm64Utils { public static List GetArm64MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) { if (managed) { ulong addressOfNextFunctionStart = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); if (addressOfNextFunctionStart != 0) { long num = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(addressOfNextFunctionStart, true); long num2 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); if (num < num2) { num = LibCpp2IlMain.Binary.RawLength; } return Disassemble(LibCpp2IlMain.Binary.GetRawBinaryContent().AsSpan((int)num2, (int)(num - num2)), virtAddress); } } int start = (int)LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress, true); byte[] rawBinaryContent = LibCpp2IlMain.Binary.GetRawBinaryContent(); Span bytes = rawBinaryContent.AsSpan(start, 4); List list = new List(); while ((count == -1 || list.Count < count) && !list.Any((Arm64Instruction i) => (int)((Arm64Instruction)(ref i)).Mnemonic == 12 || (int)((Arm64Instruction)(ref i)).Mnemonic == 0)) { list = Disassemble(bytes, virtAddress); bytes = rawBinaryContent.AsSpan(start, bytes.Length + 4); } return list; } private static List Disassemble(Span bytes, ulong virtAddress) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) try { return Disassembler.Disassemble((ReadOnlySpan)bytes, virtAddress, (Options?)new Options(true, true, false)).ToList(); } catch (Exception innerException) { throw new Exception("Failed to disassemble method body: " + string.Join(", ", from b in bytes.ToArray() select "0x" + b.ToString("X2")), innerException); } } public static List ToList(this SpanEnumerator enumerator) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) List list = new List(); while (((SpanEnumerator)(ref enumerator)).MoveNext()) { list.Add(((SpanEnumerator)(ref enumerator)).Current); } return list; } public static Arm64Instruction LastValid(this List list) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) for (int num = list.Count - 1; num >= 0; num--) { Arm64Instruction val = list[num]; Arm64Mnemonic mnemonic = ((Arm64Instruction)(ref val)).Mnemonic; if ((int)mnemonic > 1) { return list[num]; } } return list[list.Count - 1]; } } public static class V29AttributeUtils { public static Il2CppMethodDefinition[] ReadConstructors(Stream stream, uint count, ApplicationAnalysisContext context) { ApplicationAnalysisContext context2 = context; using BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true); uint[] array = new uint[count]; for (int j = 0; j < count; j++) { array[j] = binaryReader.ReadUInt32(); } if (ClassReadingBinaryReader.EnableReadableSizeInformation) { ((ClassReadingBinaryReader)context2.Metadata).TrackRead((int)(4 * count), true, true); } return array.Select((uint i) => context2.Metadata.methodDefs[i]).ToArray(); } public static AnalyzedCustomAttribute ReadAttribute(Stream stream, MethodAnalysisContext constructor, ApplicationAnalysisContext context) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); long position = stream.Position; uint num = stream.ReadUnityCompressedUint(); uint num2 = stream.ReadUnityCompressedUint(); uint num3 = stream.ReadUnityCompressedUint(); if (num + num2 + num3 == 0) { return analyzedCustomAttribute; } using BinaryReader reader = new BinaryReader(stream, Encoding.Unicode, leaveOpen: true); for (int i = 0; i < num; i++) { analyzedCustomAttribute.ConstructorParameters.Add(ReadBlob(reader, context, analyzedCustomAttribute, CustomAttributeParameterKind.ConstructorParam, i)); } for (int j = 0; j < num2; j++) { BaseCustomAttributeParameter value = ReadBlob(reader, context, analyzedCustomAttribute, CustomAttributeParameterKind.Field, j); int memberIndex = stream.ReadUnityCompressedInt(); FieldAnalysisContext field = ResolveMemberFromIndex(stream, constructor, context, memberIndex, (TypeAnalysisContext t) => t.Fields); analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field, value)); } for (int k = 0; k < num3; k++) { BaseCustomAttributeParameter value2 = ReadBlob(reader, context, analyzedCustomAttribute, CustomAttributeParameterKind.Property, k); int memberIndex2 = stream.ReadUnityCompressedInt(); PropertyAnalysisContext property = ResolveMemberFromIndex(stream, constructor, context, memberIndex2, (TypeAnalysisContext t) => t.Properties); analyzedCustomAttribute.Properties.Add(new CustomAttributeProperty(property, value2)); } if (ClassReadingBinaryReader.EnableReadableSizeInformation) { ((ClassReadingBinaryReader)context.Metadata).TrackRead((int)(stream.Position - position), true, true); } return analyzedCustomAttribute; } private static T ResolveMemberFromIndex(Stream stream, MethodAnalysisContext constructor, ApplicationAnalysisContext context, int memberIndex, Func> memberListGetter) { if (memberIndex < 0) { uint num = stream.ReadUnityCompressedUint(); memberIndex = -(memberIndex + 1); Il2CppTypeDefinition val = context.Metadata.typeDefs[num]; TypeAnalysisContext arg = context.ResolveContextForType(val) ?? throw new Exception("Unable to find type " + (object)val); return memberListGetter(arg)[memberIndex]; } return memberListGetter(constructor.DeclaringType)[memberIndex]; } private static BaseCustomAttributeParameter ReadBlob(BinaryReader reader, ApplicationAnalysisContext context, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) { BaseCustomAttributeParameter baseCustomAttributeParameter = ReadTypeAndConstructParameter(reader, context, owner, kind, index); baseCustomAttributeParameter.ReadFromV29Blob(reader, context); return baseCustomAttributeParameter; } private static BaseCustomAttributeParameter ReadTypeAndConstructParameter(BinaryReader reader, ApplicationAnalysisContext context, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Il2CppTypeEnum rawTypeEnum = (Il2CppTypeEnum)reader.ReadByte(); return ConstructParameterForType(reader, context, rawTypeEnum, owner, kind, index); } public static BaseCustomAttributeParameter ConstructParameterForType(BinaryReader reader, ApplicationAnalysisContext context, Il2CppTypeEnum rawTypeEnum, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_006f: Unknown result type (might be due to invalid IL or missing references) if ((int)rawTypeEnum <= 28) { if ((int)rawTypeEnum == 18 || (int)rawTypeEnum == 21 || (int)rawTypeEnum == 28) { throw new Exception("Object type not supported because libil2cpp is very vague"); } } else { if ((int)rawTypeEnum == 29) { return new CustomAttributeArrayParameter(owner, kind, index); } if ((int)rawTypeEnum == 85) { int num = reader.BaseStream.ReadUnityCompressedInt(); return new CustomAttributeEnumParameter(context.Binary.GetType(num), context, owner, kind, index); } if ((int)rawTypeEnum == 255) { return new CustomAttributeTypeParameter(owner, kind, index); } } return new CustomAttributePrimitiveParameter(rawTypeEnum, owner, kind, index); } } public static class WasmUtils { internal static readonly Dictionary> MethodDefinitionIndices = new Dictionary>(); private static Regex DynCallRemappingRegex = new Regex("Module\\[\\s*[\"'](dynCall_[^\"']+)[\"']\\s*\\]\\s*=\\s*Module\\[\\s*[\"']asm[\"']\\s*\\]\\[\\s*[\"']([^\"']+)[\"']\\s*\\]\\s*\\)\\.apply", RegexOptions.Compiled); public static string BuildSignature(Il2CppMethodDefinition definition) { string value = (definition.IsStatic ? "" : "i"); return $"{GetSignatureLetter(definition.ReturnType)}{value}{string.Join("", definition.Parameters.Select((Il2CppParameterReflectionData p) => GetSignatureLetter(p.Type, p.IsRefOrOut)))}i"; } private static char GetSignatureLetter(Il2CppTypeReflectionData type, bool isRefOrOut = false) { if (isRefOrOut) { return 'i'; } if (type.isPointer) { return 'i'; } return (type.baseType ?? LibCpp2IlReflection.GetType("Int32", "System")).Name switch { "Void" => 'v', "Int64" => 'j', "Single" => 'f', "Double" => 'd', _ => 'i', }; } public static string GetGhidraFunctionName(WasmFunctionDefinition functionDefinition) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) int value = (functionDefinition.IsImport ? ((WasmFile)LibCpp2IlMain.Binary).FunctionTable.IndexOf(functionDefinition) : functionDefinition.FunctionTableIndex); return $"unnamed_function_{value}"; } public static WasmFunctionDefinition? TryGetWasmDefinition(Il2CppMethodDefinition definition) { try { return GetWasmDefinition(definition); } catch { return null; } } public static WasmFunctionDefinition GetWasmDefinition(Il2CppMethodDefinition definition) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) string text = BuildSignature(definition); try { return ((WasmFile)LibCpp2IlMain.Binary).GetFunctionFromIndexAndSignature(definition.MethodPointer, text); } catch (Exception innerException) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(53, 2); defaultInterpolatedStringHandler.AppendLiteral("Failed to find wasm definition for "); defaultInterpolatedStringHandler.AppendFormatted(definition); defaultInterpolatedStringHandler.AppendLiteral("\nwhich has params "); Il2CppParameterReflectionData[] parameters = definition.Parameters; defaultInterpolatedStringHandler.AppendFormatted((parameters != null) ? Extensions.ToStringEnumerable((IEnumerable)parameters) : null); throw new Exception(defaultInterpolatedStringHandler.ToStringAndClear(), innerException); } } private static void CalculateAllMethodDefinitionIndices() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) Il2CppMethodDefinition[] methodDefs = LibCpp2IlMain.TheMetadata.methodDefs; foreach (Il2CppMethodDefinition val in methodDefs) { try { WasmFunctionDefinition wasmDefinition = GetWasmDefinition(val); int key = ((WasmFile)LibCpp2IlMain.Binary).FunctionTable.IndexOf(wasmDefinition); if (!MethodDefinitionIndices.TryGetValue(key, out List value)) { value = (MethodDefinitionIndices[key] = new List()); } value.Add(val); } catch (Exception) { } } } public static List? GetMethodDefinitionsAtIndex(int index) { if (MethodDefinitionIndices.Count == 0) { CalculateAllMethodDefinitionIndices(); } if (MethodDefinitionIndices.TryGetValue(index, out List value)) { return value; } return null; } public static Dictionary ExtractAndParseDynCallRemaps(string frameworkJsFile) { Dictionary dictionary = new Dictionary(); foreach (Match item in DynCallRemappingRegex.Matches(frameworkJsFile)) { Group group = item.Groups[1]; Group group2 = item.Groups[2]; dictionary[group2.Value] = group.Value; } return dictionary; } } public static class X86Utils { private class EnumerableCodeReader : CodeReader { private readonly IEnumerator _enumerator = bytes.GetEnumerator(); public EnumerableCodeReader(IEnumerable bytes) { } public override int ReadByte() { if (_enumerator.MoveNext()) { return _enumerator.Current; } return -1; } } private static readonly Regex UpscaleRegex = new Regex("(?:^|([^a-zA-Z]))e([a-z]{2})", RegexOptions.Compiled); private static readonly ConcurrentDictionary CachedUpscaledRegisters = new ConcurrentDictionary(); private static readonly ConcurrentDictionary CachedX86RegNamesNew = new ConcurrentDictionary(); public static InstructionList Disassemble(Memory bytes, ulong methodBase) { return Disassemble(bytes.ToArray(), methodBase); } public static InstructionList Disassemble(byte[] bytes, ulong methodBase) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) ByteArrayCodeReader val = new ByteArrayCodeReader(bytes); Decoder val2 = Decoder.Create(((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 32 : 64, (CodeReader)(object)val, (DecoderOptions)0); val2.IP = methodBase; InstructionList val3 = new InstructionList(); ulong num = val2.IP + (uint)bytes.Length; while (val2.IP < num) { Instruction val4 = val2.Decode(); val3.Add(ref val4); } return val3; } public static IEnumerable Iterate(Memory bytes, ulong methodBase) { return Iterate(bytes.AsEnumerable(), methodBase); } public static IEnumerable Iterate(IEnumerable bytes, ulong methodBase) { EnumerableCodeReader enumerableCodeReader = new EnumerableCodeReader(bytes); Decoder decoder = Decoder.Create(((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 32 : 64, (CodeReader)(object)enumerableCodeReader, (DecoderOptions)0); decoder.IP = methodBase; Instruction val = default(Instruction); decoder.Decode(ref val); while (!((Instruction)(ref val)).IsInvalid) { yield return val; decoder.Decode(ref val); } } public static Memory GetRawManagedOrCaCacheGenMethodBody(ulong ptr, bool isCaGen) { long num = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(ptr, false); if (num <= 0) { return Memory.Empty; } ulong addressOfNextFunctionStart = MiscUtils.GetAddressOfNextFunctionStart(ptr); if (addressOfNextFunctionStart == 0L || (isCaGen && addressOfNextFunctionStart - ptr > 50000)) { GetMethodBodyAtVirtAddressNew(ptr, peek: false, out byte[] rawBytes); return rawBytes; } long num2 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(addressOfNextFunctionStart, false); if (num2 <= 0) { GetMethodBodyAtVirtAddressNew(ptr, peek: false, out byte[] rawBytes2); return rawBytes2; } int num3 = (int)num2; if (num3 < num) { Logger.WarnNewline($"StartOfNextFunc returned va 0x{addressOfNextFunctionStart:X}, raw address 0x{num3:X}, for raw address 0x{num:X}. It should be more than raw address. Falling back to manual, slow, decompiler-based approach."); GetMethodBodyAtVirtAddressNew(ptr, peek: false, out byte[] rawBytes3); return rawBytes3; } byte[] rawBinaryContent = LibCpp2IlMain.Binary.GetRawBinaryContent(); int num4 = num3 - 1; if (num4 >= rawBinaryContent.Length) { Logger.WarnNewline($"StartOfNextFunc returned va 0x{addressOfNextFunctionStart:X}, raw address 0x{num3:X}, for raw address 0x{num:X}. LastPos should be less than the raw array length. Falling back to manual, slow, decompiler-based approach."); GetMethodBodyAtVirtAddressNew(ptr, peek: false, out byte[] rawBytes4); return rawBytes4; } while (rawBinaryContent[num4] == 204 && num4 > num) { num4--; } Memory memory = rawBinaryContent.AsMemory((int)num, (int)(num4 - num + 1)); if (TryFindJumpTableStart(memory, ptr, addressOfNextFunctionStart, out int startIndex, out List _)) { memory = memory.Slice(0, startIndex); } return memory; } private static bool TryFindJumpTableStart(Memory methodBytes, ulong methodPtr, ulong nextMethodPtr, out int startIndex, out List jumpTableElements) { bool flag = false; startIndex = 0; jumpTableElements = new List(); for (int i = (int)(methodPtr % 4); i < methodBytes.Length; i += 4) { ulong num = methodBytes.Span.ReadUInt(i); ulong num2 = num + 6442450944L; if (num2 > methodPtr && num2 < nextMethodPtr) { if (!flag) { startIndex = i; flag = true; } jumpTableElements.Add(num); } } return flag; } public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool peek) { byte[] rawBytes; return GetMethodBodyAtVirtAddressNew(addr, peek, out rawBytes); } public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool peek, out byte[] rawBytes) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown ulong methodBase = addr; InstructionList val = new InstructionList(); bool flag = true; List list = new List(); long num = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(addr, true); ulong addressOfNextFunctionStart = MiscUtils.GetAddressOfNextFunctionStart(addr); if (num < 0 || num >= LibCpp2IlMain.Binary.RawLength) { Logger.ErrorNewline($"Invalid call to GetMethodBodyAtVirtAddressNew, virt addr {addr} resolves to raw {num} which is out of bounds"); rawBytes = Array.Empty(); return val; } while (flag && addr < addressOfNextFunctionStart) { list.Add(LibCpp2IlMain.Binary.GetByteAtRawAddress((ulong)num)); val = Disassemble(list.ToArray(), methodBase); if (((IEnumerable)val).All((Instruction i) => (int)((Instruction)(ref i)).Mnemonic > 0) && ((IEnumerable)val).Any((Instruction i) => (int)((Instruction)(ref i)).Code == 420)) { flag = false; } if (peek && list.Count > 50) { flag = false; } else if (list.Count > 50000) { flag = false; } addr++; num++; if (num >= LibCpp2IlMain.Binary.RawLength) { flag = false; } } rawBytes = list.ToArray(); return val; } public static string UpscaleRegisters(string replaceIn) { if (CachedUpscaledRegisters.ContainsKey(replaceIn)) { return CachedUpscaledRegisters[replaceIn]; } if (replaceIn.Length < 2) { return replaceIn; } switch (replaceIn) { case "al": return "rax"; case "bl": return "rbx"; case "dl": return "rdx"; case "ax": return "rax"; case "cx": case "cl": return "rcx"; default: { if (replaceIn[0] == 'r') { if (replaceIn[replaceIn.Length - 1] == 'd') { return replaceIn.Substring(0, replaceIn.Length - 1); } } string text = UpscaleRegex.Replace(replaceIn, "$1r$2"); CachedUpscaledRegisters.TryAdd(replaceIn, text); return text; } } } public static string GetFloatingRegister(string original) { return original switch { "rcx" => "xmm0", "rdx" => "xmm1", "r8" => "xmm2", "r9" => "xmm3", _ => original, }; } public static string GetRegisterName(Register register) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((int)register == 0) { return ""; } if (!CachedX86RegNamesNew.TryGetValue(register, out string value)) { if (!RegisterExtensions.IsVectorRegister(register)) { Register fullRegister = RegisterExtensions.GetFullRegister(register); value = ((object)(Register)(ref fullRegister)).ToString().ToLowerInvariant(); } else { value = UpscaleRegisters(((object)(Register)(ref register)).ToString().ToLower()); } CachedX86RegNamesNew[register] = value; } return value; } } } namespace Cpp2IL.Core.Utils.AsmResolver { public static class AsmResolverAssemblyPopulator { public static bool IsTypeContextModule(TypeAnalysisContext typeCtx) { if (!typeCtx.Name.StartsWith("")) { return typeCtx.FullName.StartsWith(""); } return true; } public static void ConfigureHierarchy(AssemblyAnalysisContext asmCtx) { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown foreach (TypeAnalysisContext type in asmCtx.Types) { if (IsTypeContextModule(type)) { continue; } Il2CppTypeDefinition definition = type.Definition; TypeDefinition val = type.GetExtraData("AsmResolverType") ?? throw new Exception("AsmResolver type not found in type analysis context for " + type.FullName); ReferenceImporter importer = val.Module.Assembly.GetImporter(); if (definition != null) { PopulateGenericParamsForType(definition, val); } TypeAnalysisContext overrideBaseType = type.OverrideBaseType; if (overrideBaseType != null) { TypeDefinition val2 = overrideBaseType.GetExtraData("AsmResolverType") ?? throw new Exception($"{type} declares override base type {overrideBaseType} which has not had an AsmResolver type generated for it."); val.BaseType = importer.ImportType((ITypeDefOrRef)(object)val2); } else { Il2CppType val3 = ((definition != null) ? definition.RawBaseType : null); if (val3 != null) { val.BaseType = importer.ImportType(AsmResolverUtils.ImportReferenceFromIl2CppType(val.Module, val3)); } } if (definition != null) { Il2CppType[] rawInterfaces = definition.RawInterfaces; foreach (Il2CppType il2CppType in rawInterfaces) { val.Interfaces.Add(new InterfaceImplementation(importer.ImportType(AsmResolverUtils.ImportReferenceFromIl2CppType(val.Module, il2CppType)))); } } } } private static void PopulateGenericParamsForType(Il2CppTypeDefinition cppTypeDefinition, TypeDefinition ilTypeDefinition) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown TypeDefinition ilTypeDefinition2 = ilTypeDefinition; if (cppTypeDefinition.GenericContainer == null) { return; } ReferenceImporter importer = ilTypeDefinition2.Module.Assembly.GetImporter(); foreach (Il2CppGenericParameter genericParameter in cppTypeDefinition.GenericContainer.GenericParameters) { if (!AsmResolverUtils.GenericParamsByIndexNew.TryGetValue(genericParameter.Index, out GenericParameter value)) { value = new GenericParameter(Utf8String.op_Implicit(genericParameter.Name), (GenericParameterAttributes)genericParameter.flags); AsmResolverUtils.GenericParamsByIndexNew[genericParameter.Index] = value; ilTypeDefinition2.GenericParameters.Add(value); ((IEnumerable)genericParameter.ConstraintTypes).Select((Func)((Il2CppType c) => new GenericParameterConstraint(importer.ImportTypeIfNeeded(AsmResolverUtils.ImportReferenceFromIl2CppType(ilTypeDefinition2.Module, c))))).ToList().ForEach(value.Constraints.Add); } else if (!ilTypeDefinition2.GenericParameters.Contains(value)) { ilTypeDefinition2.GenericParameters.Add(value); } } } private static TypeSignature GetTypeSigFromAttributeArg(AssemblyDefinition parentAssembly, BaseCustomAttributeParameter parameter) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!(parameter is CustomAttributePrimitiveParameter customAttributePrimitiveParameter)) { if (!(parameter is CustomAttributeEnumParameter customAttributeEnumParameter)) { if (!(parameter is BaseCustomAttributeTypeParameter)) { if (parameter is CustomAttributeArrayParameter customAttributeArrayParameter) { return (TypeSignature)(object)TypeDescriptorExtensions.MakeSzArrayType((ITypeDescriptor)(object)AsmResolverUtils.GetPrimitiveTypeDef(customAttributeArrayParameter.ArrType).ToTypeSignature()); } throw new ArgumentException("Unknown custom attribute parameter type: " + parameter.GetType().FullName); } return TypeDefinitionsAsmResolver.Type.ToTypeSignature(); } return AsmResolverUtils.GetTypeSignatureFromIl2CppType(parentAssembly.ManifestModule, customAttributeEnumParameter.EnumType ?? throw new Exception("Enum type not found for " + customAttributeEnumParameter)); } return AsmResolverUtils.GetPrimitiveTypeDef(customAttributePrimitiveParameter.PrimitiveType).ToTypeSignature(); } private static CustomAttributeArgument BuildArrayArgument(AssemblyDefinition parentAssembly, CustomAttributeArrayParameter arrayParameter) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown AssemblyDefinition parentAssembly2 = parentAssembly; try { if (arrayParameter.IsNullArray) { return BuildEmptyArrayArgument(parentAssembly2, arrayParameter); } TypeSignature typeSigFromAttributeArg = GetTypeSigFromAttributeArg(parentAssembly2, arrayParameter); bool isObjectArray = (int)arrayParameter.ArrType == 28; object[] array = arrayParameter.ArrayElements.Select(delegate(BaseCustomAttributeParameter e) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown object obj; if (!(e is CustomAttributePrimitiveParameter customAttributePrimitiveParameter)) { if (!(e is CustomAttributeEnumParameter customAttributeEnumParameter)) { if (!(e is BaseCustomAttributeTypeParameter baseCustomAttributeTypeParameter)) { if (!(e is CustomAttributeNullParameter)) { throw new Exception("Not supported array element type: " + e.GetType().FullName); } obj = null; } else { obj = baseCustomAttributeTypeParameter.TypeContext?.ToTypeSignature(parentAssembly2.ManifestModule); } } else { obj = customAttributeEnumParameter.UnderlyingPrimitiveParameter.PrimitiveValue; } } else { obj = customAttributePrimitiveParameter.PrimitiveValue; } object obj2 = obj; return isObjectArray ? ((object)new BoxedArgument(GetTypeSigFromAttributeArg(parentAssembly2, e), obj2)) : obj2; }).ToArray(); return new CustomAttributeArgument(typeSigFromAttributeArg, array); } catch (Exception innerException) { throw new Exception("Failed to build array argument for " + arrayParameter, innerException); } } private static CustomAttributeArgument BuildEmptyArrayArgument(AssemblyDefinition parentAssembly, CustomAttributeArrayParameter arrayParameter) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown return new CustomAttributeArgument((TypeSignature)(arrayParameter.Kind switch { CustomAttributeParameterKind.ConstructorParam => arrayParameter.Owner.Constructor.Parameters[arrayParameter.Index].ToTypeSignature(parentAssembly.ManifestModule), CustomAttributeParameterKind.Property => arrayParameter.Owner.Properties[arrayParameter.Index].Property.ToTypeSignature(parentAssembly.ManifestModule), CustomAttributeParameterKind.Field => arrayParameter.Owner.Fields[arrayParameter.Index].Field.ToTypeSignature(parentAssembly.ManifestModule), CustomAttributeParameterKind.ArrayElement => throw new Exception("Array element cannot be an array (or at least, not implemented!)"), _ => throw new Exception("Unknown array parameter kind: " + arrayParameter.Kind), })) { IsNullArray = true }; } private static CustomAttributeArgument FromAnalyzedAttributeArgument(AssemblyDefinition parentAssembly, BaseCustomAttributeParameter parameter) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown try { if (!(parameter is CustomAttributePrimitiveParameter customAttributePrimitiveParameter)) { if (!(parameter is CustomAttributeEnumParameter customAttributeEnumParameter)) { if (!(parameter is BaseCustomAttributeTypeParameter baseCustomAttributeTypeParameter)) { if (parameter is CustomAttributeArrayParameter arrayParameter) { return BuildArrayArgument(parentAssembly, arrayParameter); } throw new ArgumentException("Unknown custom attribute parameter type: " + parameter.GetType().FullName); } return new CustomAttributeArgument(TypeDefinitionsAsmResolver.Type.ToTypeSignature(), (object)baseCustomAttributeTypeParameter.TypeContext?.ToTypeSignature(parentAssembly.ManifestModule)); } return new CustomAttributeArgument(GetTypeSigFromAttributeArg(parentAssembly, customAttributeEnumParameter), (object)customAttributeEnumParameter.UnderlyingPrimitiveParameter.PrimitiveValue); } return new CustomAttributeArgument(GetTypeSigFromAttributeArg(parentAssembly, customAttributePrimitiveParameter), (object)customAttributePrimitiveParameter.PrimitiveValue); } catch (Exception innerException) { throw new Exception("Failed to build custom attribute argument for " + parameter, innerException); } } private static CustomAttributeNamedArgument FromAnalyzedAttributeField(AssemblyDefinition parentAssembly, CustomAttributeField field) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown return new CustomAttributeNamedArgument((CustomAttributeArgumentMemberType)83, Utf8String.op_Implicit(field.Field.FieldName), GetTypeSigFromAttributeArg(parentAssembly, field.Value), FromAnalyzedAttributeArgument(parentAssembly, field.Value)); } private static CustomAttributeNamedArgument FromAnalyzedAttributeProperty(AssemblyDefinition parentAssembly, CustomAttributeProperty property) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown return new CustomAttributeNamedArgument((CustomAttributeArgumentMemberType)84, Utf8String.op_Implicit(property.Property.Name), GetTypeSigFromAttributeArg(parentAssembly, property.Value), FromAnalyzedAttributeArgument(parentAssembly, property.Value)); } private static CustomAttribute? ConvertCustomAttribute(AnalyzedCustomAttribute analyzedCustomAttribute, AssemblyDefinition assemblyDefinition) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown AssemblyDefinition assemblyDefinition2 = assemblyDefinition; MethodDefinition val = analyzedCustomAttribute.Constructor.GetExtraData("AsmResolverMethod") ?? throw new Exception($"Found a custom attribute with no AsmResolver constructor: {analyzedCustomAttribute}"); int num = analyzedCustomAttribute.Fields.Count + analyzedCustomAttribute.Properties.Count; CustomAttributeSignature val2; try { if (!analyzedCustomAttribute.HasAnyParameters && num == 0) { val2 = new CustomAttributeSignature(); } else { if (!analyzedCustomAttribute.IsSuitableForEmission) { return null; } val2 = ((num != 0) ? new CustomAttributeSignature(analyzedCustomAttribute.ConstructorParameters.Select((BaseCustomAttributeParameter p) => FromAnalyzedAttributeArgument(assemblyDefinition2, p)), analyzedCustomAttribute.Fields.Select((CustomAttributeField f) => FromAnalyzedAttributeField(assemblyDefinition2, f)).Concat(analyzedCustomAttribute.Properties.Select((CustomAttributeProperty p) => FromAnalyzedAttributeProperty(assemblyDefinition2, p)))) : new CustomAttributeSignature(analyzedCustomAttribute.ConstructorParameters.Select((BaseCustomAttributeParameter p) => FromAnalyzedAttributeArgument(assemblyDefinition2, p)))); } } catch (Exception innerException) { throw new Exception("Failed to build custom attribute signature for " + analyzedCustomAttribute, innerException); } return new CustomAttribute((ICustomAttributeType)assemblyDefinition2.GetImporter().ImportMethod((IMethodDefOrRef)(object)val), val2); } private static void CopyCustomAttributes(HasCustomAttributes source, IList destination) { if (source.CustomAttributes == null) { return; } AssemblyDefinition assemblyDefinition = source.CustomAttributeAssembly.GetExtraData("AsmResolverAssembly") ?? throw new Exception("AsmResolver assembly not found in assembly analysis context for " + source.CustomAttributeAssembly); try { foreach (AnalyzedCustomAttribute customAttribute in source.CustomAttributes) { CustomAttribute val = ConvertCustomAttribute(customAttribute, assemblyDefinition); if (val != null) { destination.Add(val); } } } catch (Exception innerException) { throw new Exception("Failed to copy custom attributes for " + source, innerException); } } public static void PopulateCustomAttributes(AssemblyAnalysisContext asmContext) { try { CopyCustomAttributes(asmContext, ((AssemblyDescriptor)asmContext.GetExtraData("AsmResolverAssembly")).CustomAttributes); foreach (TypeAnalysisContext type in asmContext.Types) { if (IsTypeContextModule(type)) { continue; } CopyCustomAttributes(type, type.GetExtraData("AsmResolverType").CustomAttributes); foreach (MethodAnalysisContext method in type.Methods) { MethodDefinition extraData = method.GetExtraData("AsmResolverMethod"); CopyCustomAttributes(method, extraData.CustomAttributes); IList parameterDefinitions = extraData.ParameterDefinitions; foreach (ParameterAnalysisContext parameter in method.Parameters) { CopyCustomAttributes(parameter, parameterDefinitions[parameter.ParamIndex].CustomAttributes); } } foreach (FieldAnalysisContext field in type.Fields) { CopyCustomAttributes(field, field.GetExtraData("AsmResolverField").CustomAttributes); } foreach (PropertyAnalysisContext property in type.Properties) { CopyCustomAttributes(property, property.GetExtraData("AsmResolverProperty").CustomAttributes); } foreach (EventAnalysisContext @event in type.Events) { CopyCustomAttributes(@event, @event.GetExtraData("AsmResolverEvent").CustomAttributes); } } } catch (Exception innerException) { throw new Exception($"Failed to populate custom attributes in {asmContext}", innerException); } } public static void CopyDataFromIl2CppToManaged(AssemblyAnalysisContext asmContext) { if (asmContext.GetExtraData("AsmResolverAssembly") == null) { throw new Exception("AsmResolver assembly not found in assembly analysis context for " + asmContext); } foreach (TypeAnalysisContext type in asmContext.Types) { if (!IsTypeContextModule(type)) { TypeDefinition? extraData = type.GetExtraData("AsmResolverType"); if (extraData == null) { Il2CppTypeDefinition? definition = type.Definition; throw new Exception("AsmResolver type not found in type analysis context for " + ((definition != null) ? definition.FullName : null)); } TypeDefinition val = extraData; try { CopyIl2CppDataToManagedType(type, val); } catch (Exception innerException) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(54, 4); defaultInterpolatedStringHandler.AppendLiteral("Failed to process type "); defaultInterpolatedStringHandler.AppendFormatted(val.FullName); defaultInterpolatedStringHandler.AppendLiteral(" (module "); ModuleDefinition module = val.Module; defaultInterpolatedStringHandler.AppendFormatted((module != null) ? module.Name : null); defaultInterpolatedStringHandler.AppendLiteral(", declaring type "); TypeDefinition declaringType = val.DeclaringType; defaultInterpolatedStringHandler.AppendFormatted((declaringType != null) ? declaringType.FullName : null); defaultInterpolatedStringHandler.AppendLiteral(") in "); defaultInterpolatedStringHandler.AppendFormatted(asmContext.Definition.AssemblyName.Name); throw new Exception(defaultInterpolatedStringHandler.ToStringAndClear(), innerException); } } } } private static void CopyIl2CppDataToManagedType(TypeAnalysisContext typeContext, TypeDefinition ilTypeDefinition) { ReferenceImporter importer = ilTypeDefinition.Module.Assembly.GetImporter(); CopyFieldsInType(importer, typeContext, ilTypeDefinition); CopyMethodsInType(importer, typeContext, ilTypeDefinition); CopyPropertiesInType(importer, typeContext, ilTypeDefinition); CopyEventsInType(importer, typeContext, ilTypeDefinition); } private static void CopyFieldsInType(ReferenceImporter importer, TypeAnalysisContext typeContext, TypeDefinition ilTypeDefinition) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown foreach (FieldAnalysisContext field in typeContext.Fields) { Il2CppFieldReflectionData backingData = field.BackingData; TypeSignature val = importer.ImportTypeSignature(field.ToTypeSignature(importer.TargetModule)); FieldDefinition val2 = new FieldDefinition(Utf8String.op_Implicit(field.FieldName), (FieldAttributes)(ushort)field.Attributes, val); if (backingData != null) { if (val2.HasDefault) { Il2CppFieldDefaultValue defaultValue = backingData.Field.DefaultValue; object obj = ((defaultValue != null) ? defaultValue.Value : null); if (obj != null) { val2.Constant = AsmResolverConstants.GetOrCreateConstant(obj); } } if (val2.HasFieldRva) { val2.FieldRva = (ISegment)new DataSegment(backingData.Field.StaticArrayInitialValue); } if (ilTypeDefinition.IsExplicitLayout) { val2.FieldOffset = backingData.FieldOffset; } } field.PutExtraData("AsmResolverField", val2); ilTypeDefinition.Fields.Add(val2); } } private static void CopyMethodsInType(ReferenceImporter importer, TypeAnalysisContext typeContext, TypeDefinition ilTypeDefinition) { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Expected O, but got Unknown //IL_0270: Expected O, but got Unknown //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Expected O, but got Unknown ReferenceImporter importer2 = importer; TypeDefinition ilTypeDefinition2 = ilTypeDefinition; foreach (MethodAnalysisContext method in typeContext.Methods) { Il2CppMethodDefinition definition = method.Definition; Il2CppType il2CppType = ((definition != null) ? definition.RawReturnType : LibCpp2IlReflection.GetTypeFromDefinition(method.InjectedReturnType.Definition ?? throw new Exception("Injected methods with injected return types not supported at the moment."))); TypeSignature val = importer2.ImportTypeSignature(AsmResolverUtils.GetTypeSignatureFromIl2CppType(importer2.TargetModule, il2CppType)); List parameters = method.Parameters; TypeSignature[] array = (TypeSignature[])(object)new TypeSignature[parameters.Count]; ParameterDefinition[] array2 = (ParameterDefinition[])(object)new ParameterDefinition[parameters.Count]; foreach (ParameterAnalysisContext parameter in method.Parameters) { int paramIndex = parameter.ParamIndex; array[paramIndex] = importer2.ImportTypeSignature(parameter.ParameterTypeContext.ToTypeSignature(importer2.TargetModule)); ushort num = (ushort)(paramIndex + 1); array2[paramIndex] = new ParameterDefinition(num, Utf8String.op_Implicit(parameter.Name), (ParameterAttributes)(ushort)parameter.ParameterAttributes); Il2CppParameterDefaultValue defaultValue = parameter.DefaultValue; if (defaultValue != null) { object obj = ((defaultValue != null) ? defaultValue.ContainedDefaultValue : null); if (obj != null) { array2[paramIndex].Constant = AsmResolverConstants.GetOrCreateConstant(obj); } else if (defaultValue != null && defaultValue.dataIndex == -1) { array2[paramIndex].Constant = AsmResolverConstants.Null; } } } MethodSignature val2 = (method.IsStatic ? MethodSignature.CreateStatic(val, array) : MethodSignature.CreateInstance(val, array)); MethodDefinition managedMethod = new MethodDefinition(Utf8String.op_Implicit(method.MethodName), (MethodAttributes)(ushort)method.Attributes, val2); if (method.Definition != null) { managedMethod.ImplAttributes = (MethodImplAttributes)(ushort)method.Definition.MethodImplAttributes; if (method.Definition.IsUnmanagedCallersOnly && typeContext.AppContext.SystemTypes.UnmanagedCallersOnlyAttributeType != null) { TypeDefinition extraData = typeContext.AppContext.SystemTypes.UnmanagedCallersOnlyAttributeType.GetExtraData("AsmResolverType"); if (extraData != null) { managedMethod.CustomAttributes.Add(new CustomAttribute((ICustomAttributeType)importer2.ImportMethod((IMethodDefOrRef)(object)extraData.GetConstructor()), new CustomAttributeSignature())); } } } ParameterDefinition[] array3 = array2; foreach (ParameterDefinition item in array3) { managedMethod.ParameterDefinitions.Add(item); } if (definition != null) { Il2CppGenericContainer genericContainer = definition.GenericContainer; if (genericContainer != null) { genericContainer.GenericParameters.ToList().ForEach(delegate(Il2CppGenericParameter p) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown if (AsmResolverUtils.GenericParamsByIndexNew.TryGetValue(p.Index, out GenericParameter value)) { if (!managedMethod.GenericParameters.Contains(value)) { managedMethod.GenericParameters.Add(value); } } else { value = new GenericParameter(Utf8String.op_Implicit(p.Name), (GenericParameterAttributes)p.flags); if (!managedMethod.GenericParameters.Contains(value)) { managedMethod.GenericParameters.Add(value); } ((IEnumerable)p.ConstraintTypes).Select((Func)((Il2CppType c) => new GenericParameterConstraint(importer2.ImportTypeIfNeeded(AsmResolverUtils.ImportReferenceFromIl2CppType(ilTypeDefinition2.Module, c))))).ToList().ForEach(value.Constraints.Add); } }); } } method.PutExtraData("AsmResolverMethod", managedMethod); ilTypeDefinition2.Methods.Add(managedMethod); } } private static void CopyPropertiesInType(ReferenceImporter importer, TypeAnalysisContext typeContext, TypeDefinition ilTypeDefinition) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown foreach (PropertyAnalysisContext property in typeContext.Properties) { Il2CppPropertyDefinition definition = property.Definition; TypeSignature val = importer.ImportTypeSignature(AsmResolverUtils.GetTypeSignatureFromIl2CppType(importer.TargetModule, definition.RawPropertyType)); PropertySignature val2 = (definition.IsStatic ? PropertySignature.CreateStatic(val) : PropertySignature.CreateInstance(val)); PropertyDefinition val3 = new PropertyDefinition(Utf8String.op_Implicit(property.Name), (PropertyAttributes)(ushort)definition.attrs, val2); MethodDefinition val4 = property.Getter?.GetExtraData("AsmResolverMethod"); MethodDefinition val5 = property.Setter?.GetExtraData("AsmResolverMethod"); if (val4 != null) { val3.Semantics.Add(new MethodSemantics(val4, (MethodSemanticsAttributes)2)); } if (val5 != null) { val3.Semantics.Add(new MethodSemantics(val5, (MethodSemanticsAttributes)1)); } if (val4 != null && val4.Parameters.Count > 0) { foreach (Parameter parameter in val4.Parameters) { ((MethodSignatureBase)val2).ParameterTypes.Add(parameter.ParameterType); } } else if (val5 != null && val5.Parameters.Count > 1) { for (int i = 0; i < val5.Parameters.Count - 1; i++) { Parameter val6 = val5.Parameters[i]; ((MethodSignatureBase)val2).ParameterTypes.Add(val6.ParameterType); } } property.PutExtraData("AsmResolverProperty", val3); ilTypeDefinition.Properties.Add(val3); } } private static void CopyEventsInType(ReferenceImporter importer, TypeAnalysisContext cppTypeDefinition, TypeDefinition ilTypeDefinition) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown foreach (EventAnalysisContext @event in cppTypeDefinition.Events) { Il2CppEventDefinition definition = @event.Definition; ITypeDefOrRef val = importer.ImportTypeIfNeeded(AsmResolverUtils.ImportReferenceFromIl2CppType(ilTypeDefinition.Module, definition.RawType)); EventDefinition val2 = new EventDefinition(Utf8String.op_Implicit(@event.Name), (EventAttributes)(ushort)definition.EventAttributes, val); MethodDefinition val3 = @event.Adder?.GetExtraData("AsmResolverMethod"); MethodDefinition val4 = @event.Remover?.GetExtraData("AsmResolverMethod"); MethodDefinition val5 = @event.Invoker?.GetExtraData("AsmResolverMethod"); if (val3 != null) { val2.Semantics.Add(new MethodSemantics(val3, (MethodSemanticsAttributes)8)); } if (val4 != null) { val2.Semantics.Add(new MethodSemantics(val4, (MethodSemanticsAttributes)16)); } if (val5 != null) { val2.Semantics.Add(new MethodSemantics(val5, (MethodSemanticsAttributes)32)); } @event.PutExtraData("AsmResolverEvent", val2); ilTypeDefinition.Events.Add(val2); } } } public static class AsmResolverConstants { public static readonly Constant Null; private static readonly Dictionary IntegerCache; private static readonly Dictionary ByteCache; private static readonly Constant SingleZero; private static readonly Constant BoolFalse; private static readonly Constant BoolTrue; static AsmResolverConstants() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Null = new Constant((ElementType)18, new DataBlobSignature(new byte[4])); IntegerCache = new Dictionary(); ByteCache = new Dictionary(); SingleZero = Constant.FromValue(0f); BoolFalse = Constant.FromValue(false); BoolTrue = Constant.FromValue(true); for (int i = 0; i < 16; i++) { IntegerCache[i] = Constant.FromValue(i); ByteCache[(byte)i] = Constant.FromValue((byte)i); } } public static Constant GetOrCreateConstant(object from) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown if (!(from is string s)) { if (!(from is bool)) { if (from is byte) { if ((byte)from < 16) { return ByteCache[(byte)from]; } } else if (from is float) { if ((float)from == 0f) { return SingleZero; } } else if (from is int num && num >= 0 && num < 16) { return IntegerCache[(int)from]; } return CreateNewConstant((IConvertible)from); } return ((bool)from) ? BoolTrue : BoolFalse; } return new Constant((ElementType)14, new DataBlobSignature(Encoding.Unicode.GetBytes(s))); } private static Constant CreateNewConstant(IConvertible from) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown return new Constant(GetElementTypeFromConstant(from), new DataBlobSignature(MiscUtils.RawBytes(from))); } private static ElementType GetElementTypeFromConstant(object? primitive) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (primitive == null) { return (ElementType)28; } ElementType result; if (!(primitive is sbyte)) { if (!(primitive is byte)) { if (!(primitive is bool)) { if (!(primitive is short)) { if (!(primitive is ushort)) { if (!(primitive is int)) { if (!(primitive is uint)) { if (!(primitive is long)) { if (!(primitive is ulong)) { if (!(primitive is float)) { if (!(primitive is double)) { if (!(primitive is string)) { if (!(primitive is char)) { throw new Exception($"Can't get a element type for the constant {primitive} of type {primitive.GetType()}"); } result = (ElementType)3; } else { result = (ElementType)14; } } else { result = (ElementType)13; } } else { result = (ElementType)12; } } else { result = (ElementType)11; } } else { result = (ElementType)10; } } else { result = (ElementType)9; } } else { result = (ElementType)8; } } else { result = (ElementType)7; } } else { result = (ElementType)6; } } else { result = (ElementType)2; } } else { result = (ElementType)5; } } else { result = (ElementType)4; } return result; } } public static class AsmResolverUtils { private static readonly Dictionary CachedTypeDefsByName = new Dictionary(); private static readonly ConcurrentDictionary ImportersByAssembly = new ConcurrentDictionary(); public static readonly ConcurrentDictionary TypeDefsByIndex = new ConcurrentDictionary(); public static readonly ConcurrentDictionary GenericParamsByIndexNew = new ConcurrentDictionary(); public static TypeDefinition GetPrimitiveTypeDef(Il2CppTypeEnum type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected I4, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 switch (type - 1) { default: if ((int)type != 255) { break; } return TypeDefinitionsAsmResolver.Type; case 27: return TypeDefinitionsAsmResolver.Object; case 0: return TypeDefinitionsAsmResolver.Void; case 1: return TypeDefinitionsAsmResolver.Boolean; case 2: return TypeDefinitionsAsmResolver.Char; case 3: return TypeDefinitionsAsmResolver.SByte; case 4: return TypeDefinitionsAsmResolver.Byte; case 5: return TypeDefinitionsAsmResolver.Int16; case 6: return TypeDefinitionsAsmResolver.UInt16; case 7: return TypeDefinitionsAsmResolver.Int32; case 8: return TypeDefinitionsAsmResolver.UInt32; case 23: return TypeDefinitionsAsmResolver.IntPtr; case 24: return TypeDefinitionsAsmResolver.UIntPtr; case 9: return TypeDefinitionsAsmResolver.Int64; case 10: return TypeDefinitionsAsmResolver.UInt64; case 11: return TypeDefinitionsAsmResolver.Single; case 12: return TypeDefinitionsAsmResolver.Double; case 13: return TypeDefinitionsAsmResolver.String; case 21: return TypeDefinitionsAsmResolver.TypedReference; case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 22: case 25: case 26: break; } throw new ArgumentException($"Type is not a primitive - {type}", "type"); } public static TypeSignature GetTypeSignatureFromIl2CppType(ModuleDefinition module, Il2CppType il2CppType) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected I4, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Invalid comparison between Unknown and I4 //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown if (il2CppType == null) { throw new ArgumentNullException("il2CppType"); } Il2CppTypeEnum type = il2CppType.Type; TypeSignature val2; switch (type - 1) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 21: case 23: case 24: case 27: val2 = GetPrimitiveTypeDef(il2CppType.Type).ToTypeSignature(); break; case 16: case 17: val2 = TypeDefsByIndex[il2CppType.Data.ClassIndex].ToTypeSignature(); break; case 19: val2 = (TypeSignature)(object)TypeDescriptorExtensions.MakeArrayType((ITypeDescriptor)(object)GetTypeSignatureFromIl2CppType(module, il2CppType.GetArrayElementType()), il2CppType.GetArrayRank()); break; case 28: val2 = (TypeSignature)(object)TypeDescriptorExtensions.MakeSzArrayType((ITypeDescriptor)(object)GetTypeSignatureFromIl2CppType(module, il2CppType.GetEncapsulatedType())); break; case 14: val2 = (TypeSignature)(object)TypeDescriptorExtensions.MakePointerType((ITypeDescriptor)(object)GetTypeSignatureFromIl2CppType(module, il2CppType.GetEncapsulatedType())); break; case 18: case 29: { bool flag = (int)il2CppType.Type == 30; val2 = (TypeSignature)new GenericParameterSignature(module, (GenericParameterType)((!flag) ? 1 : 2), (int)il2CppType.GetGenericParameterDef().genericParameterIndexInOwner); break; } case 20: { Il2CppGenericClass genericClass = il2CppType.GetGenericClass(); TypeDefsByIndex.TryGetValue(genericClass.TypeDefinitionIndex, out TypeDefinition value); if (LibCpp2IlMain.MetadataVersion >= 27f) { Il2CppType il2CppType2 = LibCpp2IlMain.Binary.ReadReadableAtVirtualAddress((ulong)genericClass.TypeDefinitionIndex); value = GetTypeSignatureFromIl2CppType(module, il2CppType2).Resolve() ?? throw new Exception("Unable to resolve base type for generic inst"); } GenericInstanceTypeSignature val = new GenericInstanceTypeSignature((ITypeDefOrRef)(object)value, value.IsValueType); Il2CppType[] types = genericClass.Context.ClassInst.Types; foreach (Il2CppType il2CppType3 in types) { val.TypeArguments.Add(GetTypeSignatureFromIl2CppType(module, il2CppType3)); } val2 = (TypeSignature)(object)val; break; } default: { Il2CppTypeEnum type2 = il2CppType.Type; throw new Exception("Don't know how to make a type signature from " + ((object)(Il2CppTypeEnum)(ref type2)).ToString()); } } if (il2CppType.Byref == 1) { val2 = (TypeSignature)(object)TypeDescriptorExtensions.MakeByReferenceType((ITypeDescriptor)(object)val2); } return val2; } public static ITypeDefOrRef ImportReferenceFromIl2CppType(ModuleDefinition module, Il2CppType il2CppType) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected I4, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (il2CppType == null) { throw new ArgumentNullException("il2CppType"); } Il2CppTypeEnum type = il2CppType.Type; switch (type - 1) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 21: case 23: case 24: case 27: return (ITypeDefOrRef)(object)GetPrimitiveTypeDef(il2CppType.Type); case 16: case 17: return (ITypeDefOrRef)(object)TypeDefsByIndex[il2CppType.Data.ClassIndex]; case 14: case 18: case 19: case 20: case 28: case 29: return GetTypeSignatureFromIl2CppType(module, il2CppType).ToTypeDefOrRef(); default: { Il2CppTypeEnum type2 = il2CppType.Type; throw new Exception("Don't know how to import a type reference from an il2cpp type of type " + ((object)(Il2CppTypeEnum)(ref type2)).ToString()); } } } public static TypeDefinition? TryLookupTypeDefKnownNotGeneric(string? name) { return TryLookupTypeDefByName(name)?.typeDefinition; } public static (TypeDefinition typeDefinition, string[] genericParams)? TryLookupTypeDefByName(string? name) { if (name == null) { return null; } string key = name.ToLower(CultureInfo.InvariantCulture); if (CachedTypeDefsByName.TryGetValue(key, out (TypeDefinition, string[])? value)) { return value; } (TypeDefinition, string[])? tuple = InternalTryLookupTypeDefByName(name); CachedTypeDefsByName[key] = tuple; return tuple; } private static (TypeDefinition typeDefinition, string[] genericParams)? InternalTryLookupTypeDefByName(string name) { string name2 = name; TypeDefinition primitive = TypeDefinitionsAsmResolver.GetPrimitive(name2); if (primitive != null) { return (primitive, Array.Empty()); } TypeAnalysisContext typeAnalysisContext = Cpp2IlApi.CurrentAppContext.AllTypes.FirstOrDefault((TypeAnalysisContext t) => t.Definition != null && string.Equals(t.Definition.FullName, name2, StringComparison.OrdinalIgnoreCase)); if (name2.EndsWith("[]")) { string text = name2; return TryLookupTypeDefByName(text.Substring(0, text.Length - 2)); } string[] array = Array.Empty(); if (typeAnalysisContext == null && name2.Contains("<")) { string text = name2; int num = name2.IndexOf("<", StringComparison.Ordinal) + 1; array = MiscUtils.GetGenericParams(text.Substring(num, text.Length - 1 - num)); name2 = name2.Substring(0, name2.IndexOf("<", StringComparison.Ordinal)); if (!name2.Contains("`")) { name2 = name2 + "`" + array.Length; } typeAnalysisContext = Cpp2IlApi.CurrentAppContext.AllTypes.FirstOrDefault(delegate(TypeAnalysisContext t) { Il2CppTypeDefinition? definition3 = t.Definition; return ((definition3 != null) ? definition3.FullName : null) == name2; }); } if (typeAnalysisContext != null) { return (typeAnalysisContext.GetExtraData("AsmResolverType"), array); } string searchString = "System." + name2; typeAnalysisContext = Cpp2IlApi.CurrentAppContext.AllTypes.FirstOrDefault(delegate(TypeAnalysisContext t) { Il2CppTypeDefinition? definition2 = t.Definition; return string.Equals((definition2 != null) ? definition2.FullName : null, searchString, StringComparison.OrdinalIgnoreCase); }); if (typeAnalysisContext != null) { return (typeAnalysisContext.GetExtraData("AsmResolverType"), array); } List list = Cpp2IlApi.CurrentAppContext.AllTypes.Where(delegate(TypeAnalysisContext t) { Il2CppTypeDefinition? definition = t.Definition; return string.Equals((definition != null) ? definition.Name : null, name2, StringComparison.OrdinalIgnoreCase); }).ToList(); if (list.Count == 1) { typeAnalysisContext = list.First(); } if (typeAnalysisContext != null) { return (typeAnalysisContext.GetExtraData("AsmResolverType"), array); } if (!name2.Contains(".")) { return null; } searchString = name2; list = Cpp2IlApi.CurrentAppContext.AllTypes.Where((TypeAnalysisContext t) => t.Definition != null && t.Definition.FullName.Replace('/', '.').EndsWith(searchString)).ToList(); if (list.Count == 1) { typeAnalysisContext = list.First(); } if (typeAnalysisContext == null) { return null; } return (typeAnalysisContext.GetExtraData("AsmResolverType"), array); } public static ReferenceImporter GetImporter(this AssemblyDefinition assemblyDefinition) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_002f: Expected O, but got Unknown if (ImportersByAssembly.TryGetValue(assemblyDefinition, out ReferenceImporter value)) { return value; } ConcurrentDictionary importersByAssembly = ImportersByAssembly; ReferenceImporter val = new ReferenceImporter(assemblyDefinition.Modules[0]); value = val; importersByAssembly[assemblyDefinition] = val; return value; } public static ITypeDefOrRef ImportTypeIfNeeded(this ReferenceImporter importer, ITypeDefOrRef type) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown TypeSpecification val = (TypeSpecification)(object)((type is TypeSpecification) ? type : null); if (val != null) { return (ITypeDefOrRef)new TypeSpecification(importer.ImportTypeSignature(val.Signature)); } return importer.ImportType(type); } public static bool IsManagedMethodWithBody(this MethodDefinition managedMethod) { if (managedMethod.Managed && !managedMethod.IsAbstract && !managedMethod.IsPInvokeImpl && !managedMethod.IsInternalCall && !managedMethod.IsNative) { return !managedMethod.IsRuntime; } return false; } } public static class ContextToTypeSignature { private static TypeDefinition GetTypeDefinition(this TypeAnalysisContext context) { return context.GetExtraData("AsmResolverType") ?? throw new Exception("AsmResolver type not found in type analysis context for " + context.FullName); } public static TypeSignature ToTypeSignature(this TypeAnalysisContext context, ModuleDefinition parentModule) { if (!(context is GenericParameterTypeAnalysisContext context2)) { if (!(context is GenericInstanceTypeAnalysisContext context3)) { if (context is WrappedTypeAnalysisContext context4) { return context4.ToTypeSignature(parentModule); } return ((ITypeDescriptor)parentModule.DefaultImporter.ImportType((ITypeDefOrRef)(object)context.GetTypeDefinition())).ToTypeSignature(); } return context3.ToTypeSignature(parentModule); } return context2.ToTypeSignature(parentModule); } public static TypeSignature ToTypeSignature(this GenericInstanceTypeAnalysisContext context, ModuleDefinition parentModule) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown ModuleDefinition parentModule2 = parentModule; ITypeDefOrRef obj = context.GenericType.ToTypeSignature(parentModule2).ToTypeDefOrRef(); TypeSignature[] array = context.GenericArguments.Select((TypeAnalysisContext a) => a.ToTypeSignature(parentModule2)).ToArray(); return (TypeSignature)new GenericInstanceTypeSignature(obj, context.IsValueType, array); } public static TypeSignature ToTypeSignature(this GenericParameterTypeAnalysisContext context, ModuleDefinition parentModule) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return (TypeSignature)new GenericParameterSignature((GenericParameterType)(((int)context.Type == 19) ? 1 : 2), context.Index); } public static TypeSignature ToTypeSignature(this WrappedTypeAnalysisContext context, ModuleDefinition parentModule) { if (!(context is SzArrayTypeAnalysisContext context2)) { if (!(context is PointerTypeAnalysisContext context3)) { if (!(context is ByRefTypeAnalysisContext context4)) { if (context is ArrayTypeAnalysisContext context5) { return context5.ToTypeSignature(parentModule); } throw new ArgumentException($"Unknown wrapped type context {context.GetType()}", "context"); } return context4.ToTypeSignature(parentModule); } return context3.ToTypeSignature(parentModule); } return context2.ToTypeSignature(parentModule); } public static TypeSignature ToTypeSignature(this SzArrayTypeAnalysisContext context, ModuleDefinition parentModule) { return (TypeSignature)(object)TypeDescriptorExtensions.MakeSzArrayType((ITypeDescriptor)(object)context.ElementType.ToTypeSignature(parentModule)); } public static TypeSignature ToTypeSignature(this PointerTypeAnalysisContext context, ModuleDefinition parentModule) { return (TypeSignature)(object)TypeDescriptorExtensions.MakePointerType((ITypeDescriptor)(object)context.ElementType.ToTypeSignature(parentModule)); } public static TypeSignature ToTypeSignature(this ByRefTypeAnalysisContext context, ModuleDefinition parentModule) { return (TypeSignature)(object)TypeDescriptorExtensions.MakeByReferenceType((ITypeDescriptor)(object)context.ElementType.ToTypeSignature(parentModule)); } public static TypeSignature ToTypeSignature(this ArrayTypeAnalysisContext context, ModuleDefinition parentModule) { return (TypeSignature)(object)TypeDescriptorExtensions.MakeArrayType((ITypeDescriptor)(object)context.ElementType.ToTypeSignature(parentModule), context.Rank); } public static TypeSignature ToTypeSignature(this ParameterAnalysisContext context, ModuleDefinition parentModule) { return context.ParameterTypeContext.ToTypeSignature(parentModule); } public static TypeSignature ToTypeSignature(this FieldAnalysisContext context, ModuleDefinition parentModule) { return context.FieldTypeContext.ToTypeSignature(parentModule); } public static TypeSignature ToTypeSignature(this EventAnalysisContext context, ModuleDefinition parentModule) { return context.EventTypeContext.ToTypeSignature(parentModule); } public static TypeSignature ToTypeSignature(this PropertyAnalysisContext context, ModuleDefinition parentModule) { return context.PropertyTypeContext.ToTypeSignature(parentModule); } } internal class Il2CppAssemblyResolver : IAssemblyResolver { internal readonly Dictionary DummyAssemblies = new Dictionary(); public AssemblyDefinition? Resolve(AssemblyDescriptor assembly) { if (DummyAssemblies.TryGetValue(Utf8String.op_Implicit(assembly.Name), out AssemblyDefinition value)) { return value; } return null; } public void AddToCache(AssemblyDescriptor descriptor, AssemblyDefinition definition) { } public bool RemoveFromCache(AssemblyDescriptor descriptor) { return true; } public bool HasCached(AssemblyDescriptor descriptor) { return true; } public void ClearCache() { } } public static class TypeDefinitionsAsmResolver { private static Dictionary _primitiveTypeMappings = new Dictionary(); public static TypeDefinition Boolean; public static TypeDefinition SByte; public static TypeDefinition Byte; public static TypeDefinition Char; public static TypeDefinition Int16; public static TypeDefinition UInt16; public static TypeDefinition Int32; public static TypeDefinition UInt32; public static TypeDefinition Int64; public static TypeDefinition UInt64; public static TypeDefinition Single; public static TypeDefinition Double; public static TypeDefinition IntPtr; public static TypeDefinition UIntPtr; public static TypeDefinition Object; public static TypeDefinition IConvertible; public static TypeDefinition ValueType; public static TypeDefinition Enum; public static TypeDefinition Type; public static TypeDefinition TypedReference; public static TypeDefinition String; public static TypeDefinition Array; public static TypeDefinition IEnumerable; public static TypeDefinition Exception; public static TypeDefinition Void; public static TypeDefinition Attribute; public static TypeDefinition MethodInfo; public static void Reset() { _primitiveTypeMappings.Clear(); Boolean = null; SByte = null; Byte = null; Char = null; Int16 = null; UInt16 = null; Int32 = null; UInt32 = null; Int64 = null; UInt64 = null; Single = null; Double = null; IntPtr = null; UIntPtr = null; Object = null; IConvertible = null; ValueType = null; Enum = null; Type = null; TypedReference = null; String = null; Array = null; IEnumerable = null; Exception = null; Void = null; Attribute = null; MethodInfo = null; } public static TypeDefinition? GetPrimitive(string name) { if (_primitiveTypeMappings.TryGetValue(name, out TypeDefinition value)) { return value; } return null; } public static void CacheNeededTypeDefinitions() { Object = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Object"); ValueType = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.ValueType"); Enum = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Enum"); String = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.String"); Int64 = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Int64"); Single = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Single"); Double = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Double"); Int32 = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Int32"); UInt32 = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.UInt32"); UInt64 = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.UInt64"); IntPtr = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.IntPtr"); UIntPtr = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.UIntPtr"); Boolean = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Boolean"); Array = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Array"); IEnumerable = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Collections.IEnumerable"); Exception = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Exception"); Void = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Void"); Attribute = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Attribute"); SByte = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.SByte"); Byte = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Byte"); Boolean = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Boolean"); Char = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Char"); Int16 = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Int16"); UInt16 = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.UInt16"); Type = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.Type"); TypedReference = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.TypedReference"); IConvertible = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.IConvertible"); MethodInfo = AsmResolverUtils.TryLookupTypeDefKnownNotGeneric("System.MethodInfo"); _primitiveTypeMappings = new Dictionary { { "string", String }, { "long", Int64 }, { "float", Single }, { "double", Double }, { "int", Int32 }, { "bool", Boolean }, { "uint", UInt32 }, { "ulong", UInt64 } }; } } } namespace Cpp2IL.Core.ProcessingLayers { public class AttributeAnalysisProcessingLayer : Cpp2IlProcessingLayer { public override string Name => "CustomAttribute Analyzer"; public override string Id => "attributeanalyzer"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { Action progressCallback2 = progressCallback; int total = appContext.Assemblies.Count + appContext.AllTypes.Select((TypeAnalysisContext t) => 1 + t.Events.Count + t.Fields.Count + t.Methods.Count + t.Properties.Count).Sum(); int count = 0; appContext.Assemblies.ForEach(delegate(AssemblyAnalysisContext a) { AnalyzeAndRaise(a, ref count, total, progressCallback2); }); foreach (TypeAnalysisContext allType in appContext.AllTypes) { AnalyzeAndRaise(allType, ref count, total, progressCallback2); allType.Events.ForEach(delegate(EventAnalysisContext e) { AnalyzeAndRaise(e, ref count, total, progressCallback2); }); allType.Fields.ForEach(delegate(FieldAnalysisContext f) { AnalyzeAndRaise(f, ref count, total, progressCallback2); }); allType.Methods.ForEach(delegate(MethodAnalysisContext m) { AnalyzeAndRaise(m, ref count, total, progressCallback2); m.Parameters.ForEach(delegate(ParameterAnalysisContext p) { AnalyzeAndRaise(p, ref count, total, progressCallback2); }); }); allType.Properties.ForEach(delegate(PropertyAnalysisContext p) { AnalyzeAndRaise(p, ref count, total, progressCallback2); }); } } private void AnalyzeAndRaise(HasCustomAttributes toAnalyze, ref int count, int total, Action? progressCallback) { toAnalyze.AnalyzeCustomAttributeData(); count++; progressCallback?.Invoke(count, total); } } public class AttributeInjectorProcessingLayer : Cpp2IlProcessingLayer { private static bool _useEzDiffMode; public override string Name => "Attribute Injector"; public override string Id => "attributeinjector"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { _useEzDiffMode = appContext.GetExtraData("attr-injector-use-ez-diff") != null; InjectAttributeAttribute(appContext); if (!_useEzDiffMode) { InjectTokenAttribute(appContext); } InjectAddressAttribute(appContext); InjectFieldOffsetAttribute(appContext); } private static void InjectFieldOffsetAttribute(ApplicationAnalysisContext appContext) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "FieldOffsetAttribute", appContext.SystemTypes.SystemAttributeType); Dictionary dictionary = multiAssemblyInjectedType.InjectFieldToAllAssemblies("Offset", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary2 = multiAssemblyInjectedType.InjectConstructor(false); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { InjectedFieldAnalysisContext field = dictionary[assembly]; InjectedMethodAnalysisContext constructor = dictionary2[assembly]; foreach (FieldAnalysisContext item in assembly.Types.SelectMany((TypeAnalysisContext t) => t.Fields)) { if (item.CustomAttributes != null && item.BackingData != null && !item.IsStatic) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field, new CustomAttributePrimitiveParameter((IConvertible)$"0x{item.Offset:X}", analyzedCustomAttribute, CustomAttributeParameterKind.Field, 0))); item.CustomAttributes.Add(analyzedCustomAttribute); } } } } private static void InjectAddressAttribute(ApplicationAnalysisContext appContext) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "AddressAttribute", appContext.SystemTypes.SystemAttributeType); Dictionary dictionary = multiAssemblyInjectedType.InjectFieldToAllAssemblies("RVA", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary2 = multiAssemblyInjectedType.InjectFieldToAllAssemblies("Offset", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary3 = multiAssemblyInjectedType.InjectFieldToAllAssemblies("Length", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary4 = multiAssemblyInjectedType.InjectConstructor(false); long value = default(long); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { InjectedFieldAnalysisContext field = dictionary[assembly]; InjectedFieldAnalysisContext field2 = dictionary2[assembly]; InjectedFieldAnalysisContext field3 = dictionary3[assembly]; InjectedMethodAnalysisContext constructor = dictionary4[assembly]; foreach (MethodAnalysisContext item in assembly.Types.SelectMany((TypeAnalysisContext t) => t.Methods)) { if (item.CustomAttributes == null || item.UnderlyingPointer == 0L) { continue; } AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(constructor); if (!_useEzDiffMode) { analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field, new CustomAttributePrimitiveParameter((IConvertible)$"0x{item.Rva:X}", analyzedCustomAttribute, CustomAttributeParameterKind.Field, 0))); if (appContext.Binary.TryMapVirtualAddressToRaw(item.UnderlyingPointer, ref value)) { analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field2, new CustomAttributePrimitiveParameter((IConvertible)$"0x{value:X}", analyzedCustomAttribute, CustomAttributeParameterKind.Field, 1))); } } analyzedCustomAttribute.Fields.Add(new CustomAttributeField(field3, new CustomAttributePrimitiveParameter((IConvertible)$"0x{item.RawBytes.Length:X}", analyzedCustomAttribute, CustomAttributeParameterKind.Field, analyzedCustomAttribute.Fields.Count))); item.CustomAttributes.Add(analyzedCustomAttribute); } } } private static void InjectTokenAttribute(ApplicationAnalysisContext appContext) { MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "TokenAttribute", appContext.SystemTypes.SystemAttributeType); Dictionary dictionary = multiAssemblyInjectedType.InjectFieldToAllAssemblies("Token", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary2 = multiAssemblyInjectedType.InjectConstructor(false); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { InjectedFieldAnalysisContext tokenField = dictionary[assembly]; InjectedMethodAnalysisContext tokenConstructor = dictionary2[assembly]; Parallel.ForEach(assembly.Types.SelectMany((TypeAnalysisContext ctx) => ctx.Methods.Cast().Concat(ctx.Fields).Concat(ctx.Events) .Concat(ctx.Properties) .Append(ctx)).Append(assembly), delegate(HasCustomAttributes context) { if (context.CustomAttributes != null && context.Token != 0) { AnalyzedCustomAttribute analyzedCustomAttribute = new AnalyzedCustomAttribute(tokenConstructor); analyzedCustomAttribute.Fields.Add(new CustomAttributeField(tokenField, new CustomAttributePrimitiveParameter((IConvertible)$"0x{context.Token:X}", analyzedCustomAttribute, CustomAttributeParameterKind.Field, 0))); context.CustomAttributes.Add(analyzedCustomAttribute); } }); } } private static void InjectAttributeAttribute(ApplicationAnalysisContext appContext) { if (LibCpp2IlMain.MetadataVersion >= 29f) { foreach (HasCustomAttributes item in appContext.Assemblies.SelectMany((AssemblyAnalysisContext ctx) => ctx.Types).SelectMany((TypeAnalysisContext ctx) => ctx.Methods.SelectMany((MethodAnalysisContext m) => m.Parameters.Cast().Append(m)).Concat(ctx.Fields).Concat(ctx.Events) .Concat(ctx.Properties) .Append(ctx))) { item.AnalyzeCustomAttributeData(); } return; } MultiAssemblyInjectedType multiAssemblyInjectedType = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "AttributeAttribute", appContext.SystemTypes.SystemAttributeType); Dictionary dictionary = multiAssemblyInjectedType.InjectFieldToAllAssemblies("Name", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary2 = multiAssemblyInjectedType.InjectFieldToAllAssemblies("RVA", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary3 = multiAssemblyInjectedType.InjectFieldToAllAssemblies("Offset", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); Dictionary dictionary4 = multiAssemblyInjectedType.InjectConstructor(false); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { InjectedFieldAnalysisContext nameField = dictionary[assembly]; InjectedFieldAnalysisContext rvaField = dictionary2[assembly]; InjectedFieldAnalysisContext offsetField = dictionary3[assembly]; InjectedMethodAnalysisContext attributeConstructor = dictionary4[assembly]; MiscUtils.ExecuteParallel(assembly.Types.SelectMany((TypeAnalysisContext ctx) => ctx.Methods.SelectMany((MethodAnalysisContext m) => m.Parameters.Cast().Append(m)).Concat(ctx.Fields).Concat(ctx.Events) .Concat(ctx.Properties) .Append(ctx)).Append(assembly), delegate(HasCustomAttributes c) { ProcessCustomAttributesForContext(c, nameField, rvaField, offsetField, attributeConstructor); }); } } private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext nameField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor) { if (_useEzDiffMode) { context.CustomAttributes = new List(); } else { context.AnalyzeCustomAttributeData(allowAnalysis: false); if (context.CustomAttributes == null) { return; } } long value = default(long); for (int i = 0; i < context.CustomAttributes.Count; i++) { AnalyzedCustomAttribute analyzedCustomAttribute = context.CustomAttributes[i]; if (!analyzedCustomAttribute.IsSuitableForEmission) { AnalyzedCustomAttribute analyzedCustomAttribute2 = new AnalyzedCustomAttribute(ctor); ulong underlyingPointer = context.CaCacheGeneratorAnalysis.UnderlyingPointer; ulong rva = context.AppContext.Binary.GetRva(underlyingPointer); if (!context.AppContext.Binary.TryMapVirtualAddressToRaw(underlyingPointer, ref value)) { value = 0L; } analyzedCustomAttribute2.Fields.Add(new CustomAttributeField(nameField, new CustomAttributePrimitiveParameter((IConvertible)analyzedCustomAttribute.Constructor.DeclaringType.Name, analyzedCustomAttribute2, CustomAttributeParameterKind.Field, 0))); analyzedCustomAttribute2.Fields.Add(new CustomAttributeField(rvaField, new CustomAttributePrimitiveParameter((IConvertible)$"0x{rva:X}", analyzedCustomAttribute2, CustomAttributeParameterKind.Field, 1))); analyzedCustomAttribute2.Fields.Add(new CustomAttributeField(offsetField, new CustomAttributePrimitiveParameter((IConvertible)$"0x{value:X}", analyzedCustomAttribute2, CustomAttributeParameterKind.Field, 2))); context.CustomAttributes[i] = analyzedCustomAttribute2; } } } } public class CallAnalysisProcessingLayer : Cpp2IlProcessingLayer { private const int MaximumCalledByAttributes = 20; public override string Name => "Call Analyzer"; public override string Id => "callanalyzer"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { InjectAttribute(appContext); } private static void InjectAttribute(ApplicationAnalysisContext appContext) { Dictionary dictionary = AttributeInjectionUtils.InjectZeroParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "DeduplicatedMethodAttribute", AttributeTargets.Method, allowMultiple: false); Dictionary dictionary2 = AttributeInjectionUtils.InjectZeroParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "ContainsInvalidInstructionsAttribute", AttributeTargets.Method, allowMultiple: false); Dictionary dictionary3 = AttributeInjectionUtils.InjectZeroParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "ContainsUnimplementedInstructionsAttribute", AttributeTargets.Method, allowMultiple: false); Dictionary dictionary4 = AttributeInjectionUtils.InjectZeroParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallAnalysisNotSupportedAttribute", AttributeTargets.Method, allowMultiple: false); Dictionary dictionary5 = AttributeInjectionUtils.InjectOneParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallsDeduplicatedMethodsAttribute", AttributeTargets.Method, allowMultiple: false, appContext.SystemTypes.SystemInt32Type, "Count"); Dictionary dictionary6 = AttributeInjectionUtils.InjectOneParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallsUnknownMethodsAttribute", AttributeTargets.Method, allowMultiple: false, appContext.SystemTypes.SystemInt32Type, "Count"); Dictionary dictionary7 = AttributeInjectionUtils.InjectOneParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallerCountAttribute", AttributeTargets.Method, allowMultiple: false, appContext.SystemTypes.SystemInt32Type, "Count"); Dictionary dictionary8 = CreateCallAttributes(appContext, "Cpp2ILInjected.CallAnalysis", "CallsAttribute"); Dictionary dictionary9 = CreateCallAttributes(appContext, "Cpp2ILInjected.CallAnalysis", "CalledByAttribute"); Dictionary dictionary10 = new Dictionary(); Dictionary dictionary11 = new Dictionary(); Dictionary dictionary12 = new Dictionary(); Dictionary> dictionary13 = new Dictionary>(); Dictionary> dictionary14 = new Dictionary>(); BaseKeyFunctionAddresses orCreateKeyFunctionAddresses = appContext.GetOrCreateKeyFunctionAddresses(); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { InjectedMethodAnalysisContext constructor = dictionary2[assembly]; InjectedMethodAnalysisContext constructor2 = dictionary3[assembly]; InjectedMethodAnalysisContext constructor3 = dictionary4[assembly]; InjectedMethodAnalysisContext constructor4 = dictionary[assembly]; foreach (MethodAnalysisContext item in assembly.Types.SelectMany((TypeAnalysisContext t) => t.Methods)) { item.AnalyzeCustomAttributeData(); if (item.CustomAttributes == null || item.UnderlyingPointer == 0L) { continue; } if (appContext.MethodsByAddress.TryGetValue(item.UnderlyingPointer, out List value) && value.Count > 1) { AttributeInjectionUtils.AddZeroParameterAttribute(item, constructor4); } List isilFromMethod = appContext.InstructionSet.GetIsilFromMethod(item); if (isilFromMethod != null && isilFromMethod.Count == 0) { if ((item.MethodAttributes & MethodAttributes.Abstract) == 0) { AttributeInjectionUtils.AddZeroParameterAttribute(item, constructor3); } continue; } if (isilFromMethod.Any((InstructionSetIndependentInstruction i) => i.OpCode == InstructionSetIndependentOpCode.Invalid)) { AttributeInjectionUtils.AddZeroParameterAttribute(item, constructor); } if (isilFromMethod.Any((InstructionSetIndependentInstruction i) => i.OpCode == InstructionSetIndependentOpCode.NotImplemented)) { AttributeInjectionUtils.AddZeroParameterAttribute(item, constructor2); } foreach (InstructionSetIndependentInstruction item2 in isilFromMethod) { if (item2.OpCode != InstructionSetIndependentOpCode.Call && item2.OpCode != InstructionSetIndependentOpCode.CallNoReturn) { continue; } if (item2.Operands.Length != 0 && item2.Operands[0].Data is IsilImmediateOperand isilImmediateOperand && !(isilImmediateOperand.Value is string)) { ulong num = isilImmediateOperand.Value.ToUInt64(null); if (appContext.MethodsByAddress.TryGetValue(num, out List value2)) { dictionary10[num] = Extensions.GetOrDefault((IDictionary)dictionary10, num, 0) + 1; MethodAnalysisContext commonMethod; if (value2.Count == 0) { dictionary11[item] = Extensions.GetOrDefault((IDictionary)dictionary11, item, 0) + 1; } else if (TryGetCommonMethodFromList(value2, out commonMethod)) { Add(dictionary13, item, commonMethod); Add(dictionary14, commonMethod, item); } else { dictionary12[item] = Extensions.GetOrDefault((IDictionary)dictionary12, item, 0) + 1; } } else if (!orCreateKeyFunctionAddresses.IsKeyFunctionAddress(num) && !appContext.Binary.IsExportedFunction(num)) { dictionary11[item] = Extensions.GetOrDefault((IDictionary)dictionary11, item, 0) + 1; } } else { dictionary11[item] = Extensions.GetOrDefault((IDictionary)dictionary11, item, 0) + 1; } } } if (Cpp2IlApi.LowMemoryMode) { GC.Collect(); } } foreach (AssemblyAnalysisContext assembly2 in appContext.Assemblies) { (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple = dictionary7[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple2 = dictionary6[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple3 = dictionary5[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext[]) callsAttributeInfo = dictionary8[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext[]) callsAttributeInfo2 = dictionary9[assembly2]; foreach (MethodAnalysisContext item3 in assembly2.Types.SelectMany((TypeAnalysisContext t) => t.Methods)) { if (item3.CustomAttributes == null || item3.UnderlyingPointer == 0L) { continue; } int orDefault = Extensions.GetOrDefault((IDictionary)dictionary11, item3, 0); if (dictionary14.TryGetValue(item3, out var value3) && value3.Count < 20) { foreach (MethodAnalysisContext item4 in value3) { AddAttribute(callsAttributeInfo2, item3, item4); } } (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple4 = tuple; AttributeInjectionUtils.AddOneParameterAttribute(item3, (tuple4.Item1, tuple4.Item2), Extensions.GetOrDefault((IDictionary)dictionary10, item3.UnderlyingPointer, 0)); if (dictionary13.TryGetValue(item3, out var value4)) { foreach (MethodAnalysisContext item5 in value4) { AddAttribute(callsAttributeInfo, item3, item5); } } if (dictionary12.TryGetValue(item3, out var value5)) { tuple4 = tuple3; AttributeInjectionUtils.AddOneParameterAttribute(item3, (tuple4.Item1, tuple4.Item2), value5); } if (orDefault > 0) { tuple4 = tuple2; AttributeInjectionUtils.AddOneParameterAttribute(item3, (tuple4.Item1, tuple4.Item2), orDefault); } } if (Cpp2IlApi.LowMemoryMode) { GC.Collect(); } } } private static void AddAttribute((InjectedMethodAnalysisContext, InjectedFieldAnalysisContext[]) callsAttributeInfo, MethodAnalysisContext annotatedMethod, MethodAnalysisContext targetMethod) { TypeAnalysisContext targetDeclaringType; string targetDeclaringTypeFullName; (FieldAnalysisContext, object) tuple = ((!TryGetDeclaringTypeForMethod(annotatedMethod, targetMethod, out targetDeclaringType, out targetDeclaringTypeFullName)) ? ((FieldAnalysisContext)callsAttributeInfo.Item2[0], (object)targetDeclaringTypeFullName) : ((FieldAnalysisContext)callsAttributeInfo.Item2[0], (object)targetDeclaringType)); (InjectedFieldAnalysisContext, string) tuple2 = (callsAttributeInfo.Item2[1], targetMethod.Name); ConcreteGenericMethodAnalysisContext concreteGenericMethodAnalysisContext = targetMethod as ConcreteGenericMethodAnalysisContext; (FieldAnalysisContext, object)? item; if (concreteGenericMethodAnalysisContext != null) { if (concreteGenericMethodAnalysisContext.MethodRef.MethodGenericParams.Length != 0) { object[] array = new object[concreteGenericMethodAnalysisContext.MethodRef.MethodGenericParams.Length]; for (int i = 0; i < array.Length; i++) { TypeAnalysisContext typeAnalysisContext = concreteGenericMethodAnalysisContext.MethodRef.MethodGenericParams[i].ToContext(concreteGenericMethodAnalysisContext.DeclaringType.DeclaringAssembly, i); if (typeAnalysisContext != null && typeAnalysisContext.IsAccessibleTo(annotatedMethod.DeclaringType)) { array[i] = typeAnalysisContext; } else { array[i] = typeAnalysisContext?.FullName; } } item = (callsAttributeInfo.Item2[2], array); } else { item = null; } } else { Il2CppMethodDefinition? definition = targetMethod.Definition; if (definition != null && definition.GenericContainer?.genericParameterCount > 0) { object[] item2 = targetMethod.Definition.GenericContainer.GenericParameters.Select((Func)((Il2CppGenericParameter p) => p.Name)).ToArray(); item = (callsAttributeInfo.Item2[2], item2); } else { item = null; } } (FieldAnalysisContext, object)? item3; if (targetMethod.ParameterCount > 0) { object[] array2 = new object[targetMethod.ParameterCount]; for (int j = 0; j < array2.Length; j++) { TypeAnalysisContext parameterTypeContext = targetMethod.Parameters[j].ParameterTypeContext; if (parameterTypeContext.IsAccessibleTo(annotatedMethod.DeclaringType) && !parameterTypeContext.HasAnyGenericParameters()) { array2[j] = parameterTypeContext; } else { array2[j] = parameterTypeContext?.FullName; } } item3 = (callsAttributeInfo.Item2[3], array2); } else { item3 = null; } TypeAnalysisContext typeAnalysisContext2; bool flag; if (targetMethod is NativeMethodAnalysisContext) { typeAnalysisContext2 = null; } else { if (targetMethod.InjectedReturnType == null) { if (concreteGenericMethodAnalysisContext != null) { MethodAnalysisContext baseMethodContext = concreteGenericMethodAnalysisContext.BaseMethodContext; if (baseMethodContext != null && (baseMethodContext.Definition != null || baseMethodContext.InjectedReturnType != null)) { flag = true; goto IL_0287; } } flag = false; goto IL_0287; } typeAnalysisContext2 = targetMethod.InjectedReturnType; } goto IL_02b0; IL_0287: typeAnalysisContext2 = (flag ? concreteGenericMethodAnalysisContext.BaseMethodContext.ReturnTypeContext : ((targetMethod.Definition != null) ? targetMethod.ReturnTypeContext : null)); goto IL_02b0; IL_02b0: (FieldAnalysisContext, object)? item4 = ((typeAnalysisContext2 == null) ? null : ((!typeAnalysisContext2.IsAccessibleTo(annotatedMethod.DeclaringType) || typeAnalysisContext2.HasAnyGenericParameters()) ? new(FieldAnalysisContext, object)?((callsAttributeInfo.Item2[4], typeAnalysisContext2.FullName)) : new(FieldAnalysisContext, object)?((callsAttributeInfo.Item2[4], typeAnalysisContext2)))); InjectedMethodAnalysisContext item5 = callsAttributeInfo.Item1; (FieldAnalysisContext, object)[] obj = new(FieldAnalysisContext, object)[2] { tuple, default((FieldAnalysisContext, object)) }; (InjectedFieldAnalysisContext, string) tuple3 = tuple2; obj[1] = (tuple3.Item1, tuple3.Item2); AttributeInjectionUtils.AddAttribute(annotatedMethod, item5, ((IEnumerable<(FieldAnalysisContext, object)>)new <>z__ReadOnlyArray<(FieldAnalysisContext, object)>(obj)).MaybeAppend<(FieldAnalysisContext, object)>(item).MaybeAppend<(FieldAnalysisContext, object)>(item3).MaybeAppend<(FieldAnalysisContext, object)>(item4)); } private static Dictionary CreateCallAttributes(ApplicationAnalysisContext appContext, string Namespace, string methodName) { return AttributeInjectionUtils.InjectAttribute(appContext, Namespace, methodName, AttributeTargets.Method, true, (appContext.SystemTypes.SystemObjectType, "Type"), (appContext.SystemTypes.SystemStringType, "Member"), (appContext.SystemTypes.SystemObjectType.MakeSzArrayType(), "MemberTypeParameters"), (appContext.SystemTypes.SystemObjectType.MakeSzArrayType(), "MemberParameters"), (appContext.SystemTypes.SystemObjectType, "ReturnType")); } private static bool TryGetCommonMethodFromList(List methods, [NotNullWhen(true)] out MethodAnalysisContext? commonMethod) { if (methods.Count < 1) { throw new ArgumentException("Count cannot be 0.", "methods"); } if (methods.Count == 1) { commonMethod = methods[0]; return true; } MethodAnalysisContext methodAnalysisContext = GetBaseMethodIfConcrete(methods[0]); for (int i = 1; i < methods.Count; i++) { MethodAnalysisContext methodAnalysisContext2 = GetBaseMethodIfConcrete(methods[i]); if (methodAnalysisContext != methodAnalysisContext2) { commonMethod = null; return false; } } commonMethod = methodAnalysisContext; return true; static MethodAnalysisContext GetBaseMethodIfConcrete(MethodAnalysisContext method) { if (!(method is ConcreteGenericMethodAnalysisContext concreteGenericMethodAnalysisContext)) { return method; } return concreteGenericMethodAnalysisContext.BaseMethodContext; } } private static bool TryGetDeclaringTypeForMethod(MethodAnalysisContext annotedMethod, MethodAnalysisContext targetMethod, [NotNullWhen(true)] out TypeAnalysisContext? targetDeclaringType, [NotNullWhen(false)] out string? targetDeclaringTypeFullName) { TypeAnalysisContext declaringType = targetMethod.DeclaringType; if (declaringType == null) { targetDeclaringType = null; targetDeclaringTypeFullName = ""; return false; } if (annotedMethod.DeclaringType != null && declaringType.IsAccessibleTo(annotedMethod.DeclaringType)) { targetDeclaringType = declaringType; targetDeclaringTypeFullName = null; return true; } targetDeclaringType = null; targetDeclaringTypeFullName = declaringType.FullName; return false; } private static void Add(Dictionary> dictionary, T key, T value) where T : notnull { if (!dictionary.TryGetValue(key, out HashSet value2)) { value2 = new HashSet(); dictionary.Add(key, value2); } value2.Add(value); } } public class DeobfuscationMapProcessingLayer : Cpp2IlProcessingLayer { private static bool _logUnknownTypes; private static int _numUnknownTypes; public override string Name => "Deobfuscation Map"; public override string Id => "deobfmap"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { string extraData = appContext.GetExtraData("deobf-map-path"); _logUnknownTypes = appContext.GetExtraData("deobf-map-log-unknown-types") != null; if (extraData == null) { Logger.WarnNewline("No deobfuscation map specified - processor will not run. You need to provide the deobf-map-path, either by programmatically adding it as extra data in the app context, or by specifying it in the --processor-config command line option.", "DeobfuscationMapProcessingLayer"); return; } byte[] array; if (extraData.StartsWith("http://") || extraData.StartsWith("https://")) { try { Logger.InfoNewline("Downloading deobfuscation map from " + extraData + "...", "DeobfuscationMapProcessingLayer"); array = new HttpClient().GetByteArrayAsync(extraData).Result; } catch (Exception ex) { Logger.ErrorNewline($"Could not download remote deobfuscation map from {extraData}: {ex.Message}. Deobfuscation will not run.", "DeobfuscationMapProcessingLayer"); return; } } else { if (!File.Exists(extraData)) { Logger.ErrorNewline("File not found: " + Path.GetFullPath(extraData) + ". Deobfuscation will not run.", "DeobfuscationMapProcessingLayer"); return; } array = File.ReadAllBytes(extraData); } Logger.InfoNewline("Parsing deobfuscation map...", "DeobfuscationMapProcessingLayer"); string deobfMap; if (array.Length > 2 && array[0] == 31 && array[1] == 139) { using MemoryStream stream = new MemoryStream(array); using GZipStream stream2 = new GZipStream(stream, CompressionMode.Decompress); using StreamReader streamReader = new StreamReader(stream2); deobfMap = streamReader.ReadToEnd(); } else { deobfMap = Encoding.UTF8.GetString(array); } Deobfuscate(appContext, deobfMap); } private static void Deobfuscate(ApplicationAnalysisContext appContext, string deobfMap) { string[] array = deobfMap.Split('\n'); _numUnknownTypes = 0; IEnumerable enumerable = array.Where((string t) => !t.Contains("::")); IEnumerable enumerable2 = array.Where((string t) => t.Contains("::")); Logger.InfoNewline($"Applying deobfuscation map ({array.Length} entries)...", "DeobfuscationMapProcessingLayer"); foreach (string item in enumerable) { ProcessLine(appContext, item); } foreach (string item2 in enumerable2) { ProcessLine(appContext, item2); } if (!_logUnknownTypes) { Logger.WarnNewline($"Encountered {_numUnknownTypes} unknown types in deobf map. Add the configuration option deobf-map-log-unknown-types=yes to log them.", "DeobfuscationMapProcessingLayer"); } } private static void ProcessLine(ApplicationAnalysisContext appContext, string line) { string[] array = line.Split(';'); if (array.Length >= 2) { string text = array[0]; string deobfuscated = array[1]; string obfuscated = text; ProcessRemapping(appContext, obfuscated, deobfuscated); } } private static void ProcessRemapping(ApplicationAnalysisContext appContext, string obfuscated, string deobfuscated) { if (obfuscated.Contains("::")) { int num = obfuscated.IndexOf("::", StringComparison.Ordinal); string obfuscated2 = obfuscated.Substring(0, num); string text = obfuscated; int num2 = num + 2; string memberName = text.Substring(num2, text.Length - num2); FieldAnalysisContext fieldAnalysisContext = GetTypeByObfName(appContext, obfuscated2)?.Fields.FirstOrDefault((FieldAnalysisContext f) => f.Name == memberName); if (fieldAnalysisContext != null) { fieldAnalysisContext.OverrideName = deobfuscated; } return; } TypeAnalysisContext typeByObfName = GetTypeByObfName(appContext, obfuscated); if (typeByObfName == null) { return; } if (typeByObfName.DeclaringType != null) { typeByObfName.OverrideName = deobfuscated; return; } int num3 = deobfuscated.LastIndexOf('.'); if (num3 != -1) { string overrideNs = deobfuscated.Substring(0, num3); string text = deobfuscated; int num2 = num3 + 1; string overrideName = text.Substring(num2, text.Length - num2); typeByObfName.OverrideNs = overrideNs; typeByObfName.OverrideName = overrideName; } else { typeByObfName.OverrideName = deobfuscated; } } private static TypeAnalysisContext? GetTypeByObfName(ApplicationAnalysisContext appContext, string obfuscated) { string obfuscated2 = obfuscated; if (obfuscated2.StartsWith(".")) { string text = obfuscated2; obfuscated2 = text.Substring(1, text.Length - 1); } int num = obfuscated2.LastIndexOf('.'); string withSlash = obfuscated2; if (num > 0) { string text2 = obfuscated2.Substring(0, num); string text = obfuscated2; int num2 = num + 1; withSlash = text2 + "/" + text.Substring(num2, text.Length - num2); } TypeAnalysisContext typeAnalysisContext = appContext.AllTypes.AsParallel().FirstOrDefault((TypeAnalysisContext t) => t.FullName == obfuscated2 || t.FullName == withSlash); if (typeAnalysisContext == null) { if (_logUnknownTypes) { Logger.WarnNewline("Could not find type " + obfuscated2, "DeobfuscationMapProcessingLayer"); } else { _numUnknownTypes++; } return null; } return typeAnalysisContext; } } public class NativeMethodDetectionProcessingLayer : Cpp2IlProcessingLayer { public override string Name => "Native Method Detection"; public override string Id => "nativemethoddetector"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { Stack<(ulong, bool)> stack = new Stack<(ulong, bool)>(); TypeAnalysisContext typeAnalysisContext = appContext.AssembliesByName["mscorlib"].InjectType("Cpp2ILInjected", "CppNativeMethods", null, TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { foreach (MethodAnalysisContext item in assembly.Types.SelectMany((TypeAnalysisContext t) => t.Methods)) { AnalyzeMethod(appContext, item, stack); } if (Cpp2IlApi.LowMemoryMode) { GC.Collect(); } } if (Cpp2IlApi.LowMemoryMode) { GC.Collect(); } while (stack.Count > 0) { var (num, flag) = stack.Pop(); if (!appContext.MethodsByAddress.ContainsKey(num)) { NativeMethodAnalysisContext nativeMethodAnalysisContext = new NativeMethodAnalysisContext(typeAnalysisContext, num, flag); typeAnalysisContext.Methods.Add(nativeMethodAnalysisContext); nativeMethodAnalysisContext.InjectedReturnType = (flag ? appContext.SystemTypes.SystemVoidType : appContext.SystemTypes.SystemObjectType); appContext.MethodsByAddress.Add(num, new List(1) { nativeMethodAnalysisContext }); AnalyzeMethod(appContext, nativeMethodAnalysisContext, stack); } } } private static void AnalyzeMethod(ApplicationAnalysisContext appContext, MethodAnalysisContext m, Stack<(ulong, bool)> nativeMethodInfoStack) { if (m.UnderlyingPointer == 0L) { return; } List isilFromMethod = appContext.InstructionSet.GetIsilFromMethod(m); if (isilFromMethod != null && isilFromMethod.Count == 0) { return; } foreach (InstructionSetIndependentInstruction item in isilFromMethod) { ulong address2; if (item.OpCode == InstructionSetIndependentOpCode.Call) { if (TryGetAddressFromInstruction(item, out var address) && !appContext.MethodsByAddress.ContainsKey(address)) { nativeMethodInfoStack.Push((address, true)); } } else if (item.OpCode == InstructionSetIndependentOpCode.CallNoReturn && TryGetAddressFromInstruction(item, out address2) && !appContext.MethodsByAddress.ContainsKey(address2)) { nativeMethodInfoStack.Push((address2, m.IsVoid)); } } } private static bool TryGetAddressFromInstruction(InstructionSetIndependentInstruction instruction, out ulong address) { if (instruction.Operands.Length != 0 && instruction.Operands[0].Data is IsilImmediateOperand isilImmediateOperand && !(isilImmediateOperand.Value is string)) { address = isilImmediateOperand.Value.ToUInt64(null); return true; } address = 0uL; return false; } } public class StableRenamingProcessingLayer : Cpp2IlProcessingLayer { private DeobfuscationMapProcessingLayer? _deobfuscationMapProcessingLayer; public override string Name => "Stable (Unhollower-Style) Renaming"; public override string Id => "stablenamer"; public override void PreProcess(ApplicationAnalysisContext context, List layers) { for (int i = 0; i < layers.Count; i++) { if (layers[i] is DeobfuscationMapProcessingLayer deobfuscationMapProcessingLayer) { Logger.InfoNewline("Found DeobfuscationMapProcessingLayer. It will be run at the correct time", "StableRenamingProcessingLayer"); _deobfuscationMapProcessingLayer = deobfuscationMapProcessingLayer; layers.RemoveAt(i); break; } } } public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { Dictionary dictionary = new Dictionary(); TypeAnalysisContext[] array = appContext.AllTypes.Where((TypeAnalysisContext t) => !(t is InjectedTypeAnalysisContext)).ToArray(); TypeAnalysisContext[] array2 = array; foreach (TypeAnalysisContext typeAnalysisContext in array2) { string stableNameForTypeIfNeeded = StableNameGenerator.GetStableNameForTypeIfNeeded((ITypeInfoProvider)(object)typeAnalysisContext, false); if (stableNameForTypeIfNeeded != null) { dictionary[stableNameForTypeIfNeeded] = Extensions.GetOrCreate(dictionary, stableNameForTypeIfNeeded, (Func)(() => 0)) + 1; typeAnalysisContext.OverrideName = stableNameForTypeIfNeeded; } } StableNameGenerator.RenamedTypes.Clear(); array2 = array; foreach (TypeAnalysisContext typeAnalysisContext2 in array2) { if (typeAnalysisContext2.OverrideName != null) { if (dictionary[typeAnalysisContext2.OverrideName] > 1) { typeAnalysisContext2.OverrideName = null; } else { StableNameGenerator.RenamedTypes[(ITypeInfoProvider)(object)typeAnalysisContext2] = typeAnalysisContext2.OverrideName; } } } array2 = array; foreach (TypeAnalysisContext typeAnalysisContext3 in array2) { if (typeAnalysisContext3.OverrideName != null) { continue; } string stableNameForTypeIfNeeded2 = StableNameGenerator.GetStableNameForTypeIfNeeded((ITypeInfoProvider)(object)typeAnalysisContext3, true); if (stableNameForTypeIfNeeded2 != null) { dictionary[stableNameForTypeIfNeeded2] = Extensions.GetOrCreate(dictionary, stableNameForTypeIfNeeded2, (Func)(() => 0)) + 1; typeAnalysisContext3.OverrideName = stableNameForTypeIfNeeded2; } } Dictionary dictionary2 = new Dictionary(); array2 = array; foreach (TypeAnalysisContext typeAnalysisContext4 in array2) { if (typeAnalysisContext4.OverrideName == null || !dictionary.TryGetValue(typeAnalysisContext4.OverrideName, out var value)) { continue; } string text = null; if (typeAnalysisContext4.OverrideName.Length > 2) { string? overrideName = typeAnalysisContext4.OverrideName; if (overrideName[overrideName.Length - 2] == '`') { string? overrideName2 = typeAnalysisContext4.OverrideName; int length = overrideName2.Length; int num = length - 2; text = overrideName2.Substring(num, length - num); string overrideName3 = typeAnalysisContext4.OverrideName; typeAnalysisContext4.OverrideName = overrideName3.Substring(0, overrideName3.Length - 2); } } if (value == 1) { typeAnalysisContext4.OverrideName += "Unique"; } else { int num = (dictionary2[typeAnalysisContext4.OverrideName] = Extensions.GetOrCreate(dictionary2, typeAnalysisContext4.OverrideName, (Func)(() => -1)) + 1); int num3 = num; typeAnalysisContext4.OverrideName += num3; } if (text != null) { typeAnalysisContext4.OverrideName += text; } } array2 = array; foreach (TypeAnalysisContext typeAnalysisContext5 in array2) { if (!typeAnalysisContext5.IsEnumType) { continue; } foreach (FieldAnalysisContext field in typeAnalysisContext5.Fields) { if (field.IsStatic && field.Attributes.HasFlag(FieldAttributes.HasDefault) && StableNameGenerator.IsObfuscated(field.Name)) { field.OverrideName = "EnumValue" + field.BackingData.DefaultValue; } } } if (_deobfuscationMapProcessingLayer != null) { Logger.InfoNewline("Running Deobfuscation Map Processing Layer Now...", "StableRenamingProcessingLayer"); _deobfuscationMapProcessingLayer.Process(appContext); Logger.InfoNewline("Deobfuscation Map Processing Layer Finished.", "StableRenamingProcessingLayer"); } array2 = array; foreach (TypeAnalysisContext obj in array2) { Dictionary dictionary3 = new Dictionary(); foreach (MethodAnalysisContext method in obj.Methods) { if (method is InjectedMethodAnalysisContext) { continue; } string stableNameForMethodIfNeeded = StableNameGenerator.GetStableNameForMethodIfNeeded((IMethodInfoProvider)(object)method); for (int j = 0; j < method.Parameters.Count; j++) { ParameterAnalysisContext parameterAnalysisContext = method.Parameters[j]; if (StableNameGenerator.IsObfuscated(parameterAnalysisContext.Name)) { parameterAnalysisContext.OverrideName = $"param_{j}"; } } if (stableNameForMethodIfNeeded != null) { int orCreate = Extensions.GetOrCreate(dictionary3, stableNameForMethodIfNeeded, (Func)(() => 0)); dictionary3[stableNameForMethodIfNeeded]++; method.OverrideName = $"{stableNameForMethodIfNeeded}_{orCreate}"; } } } array2 = array; foreach (TypeAnalysisContext obj2 in array2) { Dictionary dictionary4 = new Dictionary(); foreach (FieldAnalysisContext field2 in obj2.Fields) { if (field2 is InjectedFieldAnalysisContext) { continue; } string stableNameForFieldIfNeeded = StableNameGenerator.GetStableNameForFieldIfNeeded((IFieldInfoProvider)(object)field2); if (stableNameForFieldIfNeeded != null) { int orCreate2 = Extensions.GetOrCreate(dictionary4, stableNameForFieldIfNeeded, (Func)(() => 0)); dictionary4[stableNameForFieldIfNeeded]++; field2.OverrideName = $"{stableNameForFieldIfNeeded}_{orCreate2}"; } } } array2 = array; foreach (TypeAnalysisContext obj3 in array2) { Dictionary dictionary5 = new Dictionary(); foreach (PropertyAnalysisContext property in obj3.Properties) { string stableNameForPropertyIfNeeded = StableNameGenerator.GetStableNameForPropertyIfNeeded((IPropertyInfoProvider)(object)property); if (stableNameForPropertyIfNeeded != null) { int orCreate3 = Extensions.GetOrCreate(dictionary5, stableNameForPropertyIfNeeded, (Func)(() => 0)); dictionary5[stableNameForPropertyIfNeeded]++; property.OverrideName = $"{stableNameForPropertyIfNeeded}_{orCreate3}"; } } } array2 = array; foreach (TypeAnalysisContext obj4 in array2) { Dictionary dictionary6 = new Dictionary(); foreach (EventAnalysisContext @event in obj4.Events) { string stableNameForEventIfNeeded = StableNameGenerator.GetStableNameForEventIfNeeded((IEventInfoProvider)(object)@event); if (stableNameForEventIfNeeded != null) { int orCreate4 = Extensions.GetOrCreate(dictionary6, stableNameForEventIfNeeded, (Func)(() => 0)); dictionary6[stableNameForEventIfNeeded]++; @event.OverrideName = $"{stableNameForEventIfNeeded}_{orCreate4}"; } } } } } } namespace Cpp2IL.Core.OutputFormats { public class AsmResolverDllOutputFormatDefault : AsmResolverDllOutputFormat { public override string OutputFormatId => "dll_default"; public override string OutputFormatName => "DLL files with default method bodies"; protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) { MethodDefinitionExtensions.ReplaceMethodBodyWithMinimalImplementation(methodDefinition); } } public class AsmResolverDllOutputFormatEmpty : AsmResolverDllOutputFormat { public override string OutputFormatId => "dll_empty"; public override string OutputFormatName => "DLL files with empty method bodies"; protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown if (methodDefinition.IsManagedMethodWithBody()) { methodDefinition.CilMethodBody = new CilMethodBody(methodDefinition); } } } public class AsmResolverDllOutputFormatIlRecovery : AsmResolverDllOutputFormat { public override string OutputFormatId => "dll_il_recovery"; public override string OutputFormatName => "DLL files with IL Recovery"; protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (methodDefinition.IsManagedMethodWithBody()) { methodDefinition.CilMethodBody = new CilMethodBody(methodDefinition); CilInstructionCollection instructions = methodDefinition.CilMethodBody.Instructions; instructions.Add(CilOpCodes.Ldnull); instructions.Add(CilOpCodes.Throw); } } } public class AsmResolverDllOutputFormatThrowNull : AsmResolverDllOutputFormat { public override string OutputFormatId => "dll_throw_null"; public override string OutputFormatName => "DLL files with method bodies containing throw null"; protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (methodDefinition.IsManagedMethodWithBody()) { methodDefinition.CilMethodBody = new CilMethodBody(methodDefinition); CilInstructionCollection instructions = methodDefinition.CilMethodBody.Instructions; instructions.Add(CilOpCodes.Ldnull); instructions.Add(CilOpCodes.Throw); } } } public abstract class AsmResolverDllOutputFormat : Cpp2IlOutputFormat { private AssemblyDefinition? MostRecentCorLib { get; set; } public sealed override void DoOutput(ApplicationAnalysisContext context, string outputRoot) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown List source = BuildAssemblies(context); DateTime now = DateTime.Now; Logger.Verbose("Generating PE images...", "DllOutput"); if (!Directory.Exists(outputRoot)) { Directory.CreateDirectory(outputRoot); } List<(PEImage, Utf8String)> list = (from a in source.AsParallel() select (a.ManifestModule.ToPEImage((IPEImageBuilder)new ManagedPEImageBuilder()), a.ManifestModule.Name)).ToList(); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DllOutput"); now = DateTime.Now; Logger.Verbose("Building and writing managed PE files to disk...", "DllOutput"); ManagedPEFileBuilder val = new ManagedPEFileBuilder(); foreach (var item3 in list) { PEImage item = item3.Item1; Utf8String item2 = item3.Item2; string text = Path.Combine(outputRoot, Utf8String.op_Implicit(item2)); ((PEFileBuilder)(object)val).CreateFile(item).Write(text); } Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DllOutput"); } public List BuildAssemblies(ApplicationAnalysisContext context) { DateTime now = DateTime.Now; Logger.Verbose("Building stub assemblies...", "DllOutput"); List result = BuildStubAssemblies(context); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DllOutput"); now = DateTime.Now; Logger.Verbose("Configuring inheritance and generics...", "DllOutput"); Parallel.ForEach(context.Assemblies, AsmResolverAssemblyPopulator.ConfigureHierarchy); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DllOutput"); now = DateTime.Now; Logger.Verbose("Adding fields, methods, properties, and events (in parallel)...", "DllOutput"); MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.CopyDataFromIl2CppToManaged); MiscUtils.ExecuteParallel(context.Assemblies, FillMethodBodies); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DllOutput"); now = DateTime.Now; Logger.Verbose("Adding custom attributes to all of the above...", "DllOutput"); MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.PopulateCustomAttributes); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DllOutput"); TypeDefinitionsAsmResolver.Reset(); return result; } protected abstract void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext); protected virtual void FillMethodBodies(AssemblyAnalysisContext context) { foreach (TypeAnalysisContext type in context.Types) { if (AsmResolverAssemblyPopulator.IsTypeContextModule(type)) { continue; } try { foreach (MethodAnalysisContext method in type.Methods) { MethodDefinition? extraData = method.GetExtraData("AsmResolverMethod"); if (extraData == null) { Il2CppTypeDefinition? definition = type.Definition; string obj = ((definition != null) ? definition.FullName : null); Il2CppMethodDefinition? definition2 = method.Definition; throw new Exception("AsmResolver method not found in method analysis context for " + obj + "." + ((definition2 != null) ? definition2.Name : null)); } MethodDefinition methodDefinition = extraData; FillMethodBody(methodDefinition, method); } } catch (Exception innerException) { TypeDefinition? extraData2 = type.GetExtraData("AsmResolverType"); if (extraData2 == null) { Il2CppTypeDefinition? definition3 = type.Definition; throw new Exception("AsmResolver type not found in type analysis context for " + ((definition3 != null) ? definition3.FullName : null)); } TypeDefinition val = extraData2; DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(54, 4); defaultInterpolatedStringHandler.AppendLiteral("Failed to process type "); defaultInterpolatedStringHandler.AppendFormatted(val.FullName); defaultInterpolatedStringHandler.AppendLiteral(" (module "); ModuleDefinition module = val.Module; defaultInterpolatedStringHandler.AppendFormatted((module != null) ? module.Name : null); defaultInterpolatedStringHandler.AppendLiteral(", declaring type "); TypeDefinition declaringType = val.DeclaringType; defaultInterpolatedStringHandler.AppendFormatted((declaringType != null) ? declaringType.FullName : null); defaultInterpolatedStringHandler.AppendLiteral(") in "); defaultInterpolatedStringHandler.AppendFormatted(context.Definition.AssemblyName.Name); throw new Exception(defaultInterpolatedStringHandler.ToStringAndClear(), innerException); } } } private List BuildStubAssemblies(ApplicationAnalysisContext context) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown Il2CppAssemblyResolver assemblyResolver = new Il2CppAssemblyResolver(); DefaultMetadataResolver metadataResolver = new DefaultMetadataResolver((IAssemblyResolver)(object)assemblyResolver); AssemblyAnalysisContext assemblyContext = context.Assemblies.First((AssemblyAnalysisContext a) => a.Definition.AssemblyName.Name == "mscorlib"); MostRecentCorLib = BuildStubAssembly(assemblyContext, null, (IMetadataResolver)(object)metadataResolver); assemblyResolver.DummyAssemblies.Add(Utf8String.op_Implicit(((AssemblyDescriptor)MostRecentCorLib).Name), MostRecentCorLib); List list = (from a in context.Assemblies where a.Definition.AssemblyName.Name != "mscorlib" select BuildStubAssembly(a, MostRecentCorLib, (IMetadataResolver)(object)metadataResolver)).ToList(); list.ForEach(delegate(AssemblyDefinition a) { assemblyResolver.DummyAssemblies.Add(Utf8String.op_Implicit(((AssemblyDescriptor)a).Name), a); }); list.Add(MostRecentCorLib); return list; } private static AssemblyDefinition BuildStubAssembly(AssemblyAnalysisContext assemblyContext, AssemblyDefinition? corLib, IMetadataResolver metadataResolver) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown Il2CppAssemblyDefinition definition = assemblyContext.Definition; Il2CppImageDefinition image = definition.Image; string name = definition.AssemblyName.Name; Version version = ((definition.AssemblyName.build < 0) ? new Version(0, 0, 0, 0) : new Version(definition.AssemblyName.major, definition.AssemblyName.minor, definition.AssemblyName.build, definition.AssemblyName.revision)); AssemblyDefinition val = new AssemblyDefinition(Utf8String.op_Implicit(name), version) { HashAlgorithm = (AssemblyHashAlgorithm)definition.AssemblyName.hash_alg, Attributes = (AssemblyAttributes)definition.AssemblyName.flags, Culture = Utf8String.op_Implicit(definition.AssemblyName.Culture) }; string text = image.Name; if (text == "__Generated") { text += ".dll"; } ModuleDefinition val2 = new ModuleDefinition(text, new AssemblyReference((AssemblyDescriptor)(object)(corLib ?? val))) { MetadataResolver = metadataResolver }; val.Modules.Add(val2); foreach (TypeAnalysisContext topLevelType in assemblyContext.TopLevelTypes) { if (topLevelType.Name != "") { val2.TopLevelTypes.Add(BuildStubType(topLevelType)); } } if (corLib == null) { TypeDefinitionsAsmResolver.CacheNeededTypeDefinitions(); } foreach (TypeAnalysisContext type in assemblyContext.Types) { Il2CppTypeDefinition definition2 = type.Definition; if (definition2 == null) { continue; } TypeDefinition extraData = type.GetExtraData("AsmResolverType"); if (extraData != null) { if (definition2.IsValueType) { extraData.BaseType = val2.DefaultImporter.ImportType((ITypeDefOrRef)(object)TypeDefinitionsAsmResolver.ValueType); } else if (definition2.IsEnumType) { extraData.BaseType = val2.DefaultImporter.ImportType((ITypeDefOrRef)(object)TypeDefinitionsAsmResolver.Enum); } } } assemblyContext.PutExtraData("AsmResolverAssembly", val); return val; } private static TypeDefinition BuildStubType(TypeAnalysisContext typeContext) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown Il2CppTypeDefinition definition = typeContext.Definition; TypeDefinition val = new TypeDefinition(Utf8String.op_Implicit(typeContext.Namespace), Utf8String.op_Implicit(typeContext.Name), (TypeAttributes)typeContext.TypeAttributes); if (definition != null && ((object)definition.BaseType)?.ToString() != "System.Enum") { ConfigureTypeSize(definition, val); } foreach (TypeAnalysisContext nestedType in typeContext.NestedTypes) { val.NestedTypes.Add(BuildStubType(nestedType)); } typeContext.PutExtraData("AsmResolverType", val); if (definition != null) { AsmResolverUtils.TypeDefsByIndex[definition.TypeIndex] = val; } return val; } private static void ConfigureTypeSize(Il2CppTypeDefinition il2CppDefinition, TypeDefinition asmResolverDefinition) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown ushort num = 0; uint num2 = 0u; if (!il2CppDefinition.PackingSizeIsDefault) { num = (ushort)il2CppDefinition.PackingSize; } if (!il2CppDefinition.ClassSizeIsDefault && !il2CppDefinition.IsEnumType) { if (il2CppDefinition.Size > 1073741824) { throw new Exception($"Got invalid size for type {il2CppDefinition}: {il2CppDefinition.RawSizes}"); } num2 = ((il2CppDefinition.Size != -1) ? ((uint)il2CppDefinition.Size) : 0u); } if (num != 0 || num2 != 0) { asmResolverDefinition.ClassLayout = new ClassLayout(num, num2); } } } public class DiffableCsOutputFormat : Cpp2IlOutputFormat { public static bool IncludeMethodLength; public override string OutputFormatId => "diffable-cs"; public override string OutputFormatName => "Diffable C#"; public override void DoOutput(ApplicationAnalysisContext context, string outputRoot) { outputRoot = Path.Combine(outputRoot, "DiffableCs"); if (Directory.Exists(outputRoot)) { Logger.InfoNewline("Removing old DiffableCs output directory...", "DiffableCsOutputFormat"); Directory.Delete(outputRoot, recursive: true); } Logger.InfoNewline("Building C# files and directory structure...", "DiffableCsOutputFormat"); Dictionary dictionary = BuildOutput(context, outputRoot); Logger.InfoNewline("Writing C# files...", "DiffableCsOutputFormat"); foreach (var (path, stringBuilder2) in dictionary) { File.WriteAllText(path, stringBuilder2.ToString()); } } private static Dictionary BuildOutput(ApplicationAnalysisContext context, string outputRoot) { Dictionary dictionary = new Dictionary(); foreach (AssemblyAnalysisContext assembly in context.Assemblies) { string text = Path.Combine(outputRoot, assembly.CleanAssemblyName); Directory.CreateDirectory(text); foreach (TypeAnalysisContext topLevelType in assembly.TopLevelTypes) { if (!(topLevelType is InjectedTypeAnalysisContext)) { string text2 = Path.Combine(text, topLevelType.NamespaceAsSubdirs, MiscUtils.CleanPathElement(topLevelType.Name + ".cs")); Directory.CreateDirectory(Path.GetDirectoryName(text2)); StringBuilder stringBuilder = new StringBuilder(); if (!string.IsNullOrEmpty(topLevelType.Namespace)) { StringBuilder stringBuilder2 = stringBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder2); handler.AppendLiteral("namespace "); handler.AppendFormatted(topLevelType.Namespace); handler.AppendLiteral(";"); stringBuilder2.AppendLine(ref handler).AppendLine(); } else { stringBuilder.AppendLine("//Type is in global namespace").AppendLine(); } AppendType(stringBuilder, topLevelType); dictionary[text2] = stringBuilder; } } } return dictionary; } private static void AppendType(StringBuilder sb, TypeAnalysisContext type, int indent = 0) { AppendCustomAttributes(sb, type, indent); sb.Append('\t', indent); sb.Append(CsFileUtils.GetKeyWordsForType(type)); sb.Append(' '); sb.Append(CsFileUtils.GetTypeName(type.Name)); CsFileUtils.AppendInheritanceInfo(type, sb); sb.AppendLine(); sb.Append('\t', indent); sb.Append('{'); sb.AppendLine(); indent++; if (type.IsEnumType) { List list = type.Fields.Where((FieldAnalysisContext f) => f.IsStatic).ToList(); Extensions.SortByExtractedKey(list, (Func)((FieldAnalysisContext e) => e.Token)); foreach (FieldAnalysisContext item in list) { sb.Append('\t', indent); sb.Append(item.Name); sb.Append(" = "); sb.Append(item.BackingData.DefaultValue); sb.Append(','); sb.AppendLine(); } } else { List list2 = type.NestedTypes.Clone(); Extensions.SortByExtractedKey(list2, (Func)((TypeAnalysisContext t) => t.Name)); foreach (TypeAnalysisContext item2 in list2) { AppendType(sb, item2, indent); } List list3 = type.Fields.Clone(); Extensions.SortByExtractedKey(list3, (Func)((FieldAnalysisContext f) => (!f.IsStatic) ? (f.Offset + 4096) : f.Offset)); foreach (FieldAnalysisContext item3 in list3) { AppendField(sb, item3, indent); } sb.AppendLine(); List list4 = type.Events.Clone(); Extensions.SortByExtractedKey(list4, (Func)((EventAnalysisContext e) => e.Name)); foreach (EventAnalysisContext item4 in list4) { AppendEvent(sb, item4, indent); } List list5 = type.Properties.Clone(); Extensions.SortByExtractedKey(list5, (Func)((PropertyAnalysisContext p) => p.Name)); foreach (PropertyAnalysisContext item5 in list5) { AppendProperty(sb, item5, indent); } List list6 = type.Methods.Clone(); Extensions.SortByExtractedKey(list6, (Func)((MethodAnalysisContext m) => m.Name)); foreach (MethodAnalysisContext item6 in list6) { AppendMethod(sb, item6, indent); } } indent--; sb.Append('\t', indent); sb.Append('}'); sb.AppendLine().AppendLine(); } private static void AppendField(StringBuilder sb, FieldAnalysisContext field, int indent) { if (field is InjectedFieldAnalysisContext) { return; } AppendCustomAttributes(sb, field, indent); sb.Append('\t', indent); sb.Append(CsFileUtils.GetKeyWordsForField(field)); sb.Append(' '); sb.Append(CsFileUtils.GetTypeName(field.FieldTypeContext.Name)); sb.Append(' '); sb.Append(field.Name); object obj = field.BackingData?.DefaultValue; if (obj != null) { sb.Append(" = "); if (obj is string value) { sb.Append('"').Append(value).Append('"'); } else { sb.Append(obj); } } sb.Append("; //Field offset: 0x"); sb.Append(field.Offset.ToString("X")); if ((field.Attributes & FieldAttributes.HasFieldRVA) != 0 && field.BackingData != null) { sb.Append(" || Has Field RVA (address hidden for diffability)"); byte[] staticArrayInitialValue = field.BackingData.Field.StaticArrayInitialValue; if (staticArrayInitialValue != null && staticArrayInitialValue.Length > 0) { sb.Append(" || Field RVA Decoded (hex blob): ["); sb.Append(staticArrayInitialValue[0].ToString("X2")); for (int i = 1; i < staticArrayInitialValue.Length; i++) { byte b = staticArrayInitialValue[i]; sb.Append(' ').Append(b.ToString("X2")); } sb.Append(']'); } } sb.AppendLine(); } private static void AppendEvent(StringBuilder sb, EventAnalysisContext evt, int indent) { AppendCustomAttributes(sb, evt, indent); sb.Append('\t', indent); sb.Append(CsFileUtils.GetKeyWordsForEvent(evt)); sb.Append(' '); sb.Append(CsFileUtils.GetTypeName(evt.EventTypeContext.Name)); sb.Append(' '); sb.Append(evt.Name).AppendLine(); sb.Append('\t', indent); sb.Append('{'); sb.AppendLine(); indent++; if (evt.Adder != null) { AppendAccessor(sb, evt.Adder, "add", indent); } if (evt.Remover != null) { AppendAccessor(sb, evt.Remover, "remove", indent); } if (evt.Invoker != null) { AppendAccessor(sb, evt.Invoker, "fire", indent); } indent--; sb.Append('\t', indent); sb.Append('}'); sb.AppendLine().AppendLine(); } private static void AppendProperty(StringBuilder sb, PropertyAnalysisContext prop, int indent) { AppendCustomAttributes(sb, prop, indent); sb.Append('\t', indent); sb.Append(CsFileUtils.GetKeyWordsForProperty(prop)); sb.Append(' '); sb.Append(CsFileUtils.GetTypeName(prop.PropertyTypeContext.Name)); sb.Append(' '); sb.Append(prop.Name); sb.AppendLine(); sb.Append('\t', indent); sb.Append('{'); sb.AppendLine(); indent++; if (prop.Getter != null) { AppendAccessor(sb, prop.Getter, "get", indent); } if (prop.Setter != null) { AppendAccessor(sb, prop.Setter, "set", indent); } indent--; sb.Append('\t', indent); sb.Append('}'); sb.AppendLine().AppendLine(); } private static void AppendMethod(StringBuilder sb, MethodAnalysisContext method, int indent) { if (!(method is InjectedMethodAnalysisContext)) { AppendCustomAttributes(sb, method, indent); sb.Append('\t', indent); sb.Append(CsFileUtils.GetKeyWordsForMethod(method)); sb.Append(' '); string name = method.Name; if (!(name == ".ctor") && !(name == ".cctor")) { sb.Append(CsFileUtils.GetTypeName(method.ReturnTypeContext.Name)); sb.Append(' '); sb.Append(method.Name); } else { sb.Append(method.DeclaringType.Name); } sb.Append('('); sb.Append(CsFileUtils.GetMethodParameterString(method)); sb.Append(") { }"); if (IncludeMethodLength) { sb.Append(" //Length: "); sb.Append(method.RawBytes.Length); } sb.AppendLine().AppendLine(); } } private static void AppendAccessor(StringBuilder sb, MethodAnalysisContext accessor, string accessorType, int indent) { AppendCustomAttributes(sb, accessor, indent); sb.Append('\t', indent); sb.Append(CsFileUtils.GetKeyWordsForMethod(accessor, skipSlotRelated: true, skipKeywordsInvalidForAccessors: true)); sb.Append(' '); sb.Append(accessorType); sb.Append(" { } //Length: "); sb.Append(accessor.RawBytes.Length); sb.AppendLine(); } private static void AppendCustomAttributes(StringBuilder sb, HasCustomAttributes owner, int indent) { sb.Append(CsFileUtils.GetCustomAttributeStrings(owner, indent)); } } public class IsilDumpOutputFormat : Cpp2IlOutputFormat { public override string OutputFormatId => "isil"; public override string OutputFormatName => "ISIL Dump"; public override void DoOutput(ApplicationAnalysisContext context, string outputRoot) { ApplicationAnalysisContext context2 = context; string outputRoot2 = outputRoot; outputRoot2 = Path.Combine(outputRoot2, "IsilDump"); int count = context2.Assemblies.Count; int num = 1; foreach (AssemblyAnalysisContext assembly in context2.Assemblies) { Logger.InfoNewline($"Processing assembly {num++} of {count}: {assembly.Definition.AssemblyName.Name}", "IsilOutputFormat"); string assemblyNameClean = assembly.CleanAssemblyName; MiscUtils.ExecuteParallel(assembly.Types, delegate(TypeAnalysisContext type) { if (!(type is InjectedTypeAnalysisContext) && type.Methods.Count != 0) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Type: ").AppendLine(type.Definition.FullName).AppendLine(); foreach (MethodAnalysisContext method in type.Methods) { if (!(method is InjectedMethodAnalysisContext)) { stringBuilder.Append("Method: ").AppendLine(method.Definition.HumanReadableSignature).AppendLine(); try { stringBuilder.AppendLine("Disassembly:"); stringBuilder.Append('\t').AppendLine(context2.InstructionSet.PrintAssembly(method).Replace("\n", "\n\t")); stringBuilder.AppendLine().AppendLine("ISIL:"); method.Analyze(); if (method.ConvertedIsil == null || method.ConvertedIsil.Count == 0) { stringBuilder.AppendLine("No ISIL was generated"); } else { foreach (InstructionSetIndependentInstruction item in method.ConvertedIsil) { stringBuilder.Append('\t').Append(item).AppendLine(); } method.ReleaseAnalysisData(); stringBuilder.AppendLine(); } } catch (Exception ex) { stringBuilder.Append("Method threw an exception while analyzing - ").AppendLine(ex.ToString()).AppendLine(); } } } WriteTypeDump(outputRoot2, type, stringBuilder.ToString(), assemblyNameClean); } }); } } private static string GetFilePathForType(string outputRoot, TypeAnalysisContext type, string assemblyNameClean) { string element = Path.Combine(outputRoot, assemblyNameClean); TypeAnalysisContext typeAnalysisContext = type; while (typeAnalysisContext.DeclaringType != null) { typeAnalysisContext = typeAnalysisContext.DeclaringType; } string[] enumerable = typeAnalysisContext.Namespace.Split('.'); enumerable = (from n in enumerable.Peek(delegate(string n) { MiscUtils.InvalidPathChars.ForEach(delegate(char c) { n = n.Replace(c, '_'); }); }) select (!MiscUtils.InvalidPathElements.Contains(n)) ? n : ("__illegalwin32name_" + n + "__")).ToArray(); List list = new List(); for (TypeAnalysisContext declaringType = type.DeclaringType; declaringType != null; declaringType = declaringType.DeclaringType) { list.Add(declaringType.Name); } list.Reverse(); string filename; if (list.Count > 0) { filename = string.Join("_NestedType_", list) + "_NestedType_" + type.Name + ".txt"; } else { filename = type.Name + ".txt"; } string text = Path.Combine(enumerable.Prepend(element).ToArray()); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } MiscUtils.InvalidPathChars.ForEach(delegate(char c) { filename = filename.Replace(c, '_'); }); return Path.Combine(text, filename); } private static void WriteTypeDump(string outputRoot, TypeAnalysisContext type, string typeDump, string assemblyNameClean) { File.WriteAllText(GetFilePathForType(outputRoot, type, assemblyNameClean), typeDump); } } public class WasmMappingOutputFormat : Cpp2IlOutputFormat { public override string OutputFormatId => "wasmmappings"; public override string OutputFormatName => "WebAssembly Method Mappings"; public override void DoOutput(ApplicationAnalysisContext context, string outputRoot) { if (!(context.Binary is WasmFile)) { throw new Exception("This output format only works with WebAssembly files"); } Logger.InfoNewline("Generating WebAssembly method mappings...This may take up to a minute...", "WasmMappingOutputFormat"); StringBuilder stringBuilder = new StringBuilder(); foreach (AssemblyAnalysisContext assembly in context.Assemblies) { stringBuilder.Append("// ").Append(assembly.Definition.AssemblyName.Name).Append(".dll") .AppendLine() .AppendLine(); foreach (TypeAnalysisContext type in assembly.Types) { foreach (MethodAnalysisContext method in type.Methods) { if (!(method is InjectedMethodAnalysisContext) && method.Definition != null) { stringBuilder.Append(method.Definition.ReturnType).Append(' ').Append(method.DeclaringType.FullName) .Append("::") .Append(method.Definition.Name) .Append('(') .Append(string.Join(", ", method.Definition.Parameters.Select((Il2CppParameterReflectionData p) => $"{p.Type} {p.ParameterName}"))) .Append(") -> "); try { string ghidraFunctionName = WasmUtils.GetGhidraFunctionName(WasmUtils.GetWasmDefinition(method.Definition)); stringBuilder.AppendLine(ghidraFunctionName); } catch (Exception) { stringBuilder.AppendLine(""); } } } } stringBuilder.AppendLine().AppendLine(); } string text = Path.Combine(outputRoot, "wasm_mappings.txt"); File.WriteAllText(text, stringBuilder.ToString()); Logger.InfoNewline("Wasm mappings written to: " + text, "WasmMappingOutputFormat"); } } } namespace Cpp2IL.Core.Model { public class MultiAssemblyInjectedType { public InjectedTypeAnalysisContext[] InjectedTypes { get; } public MultiAssemblyInjectedType(InjectedTypeAnalysisContext[] injectedTypes) { InjectedTypes = injectedTypes; base..ctor(); } public Dictionary InjectMethodToAllAssemblies(string name, bool isStatic, TypeAnalysisContext returnType, MethodAttributes attributes, params TypeAnalysisContext[] args) { string name2 = name; TypeAnalysisContext returnType2 = returnType; TypeAnalysisContext[] args2 = args; return InjectedTypes.ToDictionary((InjectedTypeAnalysisContext t) => t.DeclaringAssembly, (InjectedTypeAnalysisContext t) => t.InjectMethodContext(name2, isStatic, returnType2, attributes, args2)); } public Dictionary InjectConstructor(bool isStatic, params TypeAnalysisContext[] args) { return InjectMethodToAllAssemblies(isStatic ? ".cctor" : ".ctor", isStatic, InjectedTypes.First().AppContext.SystemTypes.SystemVoidType, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, args); } public Dictionary InjectFieldToAllAssemblies(string name, TypeAnalysisContext fieldType, FieldAttributes attributes) { string name2 = name; TypeAnalysisContext fieldType2 = fieldType; return InjectedTypes.ToDictionary((InjectedTypeAnalysisContext t) => t.DeclaringAssembly, (InjectedTypeAnalysisContext t) => t.InjectFieldContext(name2, fieldType2, attributes)); } } } namespace Cpp2IL.Core.Model.CustomAttributes { public class AnalyzedCustomAttribute { public readonly MethodAnalysisContext Constructor; public readonly List ConstructorParameters; public readonly List Fields; public readonly List Properties; public bool HasAnyParameters => Constructor.ParameterCount > 0; public bool IsSuitableForEmission { get { if (HasAnyParameters) { return ConstructorParameters.Count == Constructor.ParameterCount; } return true; } } public bool AnyFieldsOrPropsSet => Fields.Count + Properties.Count > 0; public AnalyzedCustomAttribute(MethodAnalysisContext constructor) { Constructor = constructor; ConstructorParameters = new List(); Fields = new List(); Properties = new List(); base..ctor(); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder("["); string text = Constructor.DeclaringType.Name; if (text.EndsWith("Attribute")) { string text2 = text; int length = "Attribute".Length; text = text2.Substring(0, text2.Length - length); } stringBuilder.Append(text); if (HasAnyParameters || AnyFieldsOrPropsSet) { stringBuilder.Append('('); } if (!IsSuitableForEmission) { stringBuilder.Append("/*Cpp2IL Warning: missing at least one required parameter*/"); } if (ConstructorParameters.Count + Fields.Count + Properties.Count > 0) { bool flag = false; foreach (BaseCustomAttributeParameter constructorParameter in ConstructorParameters) { if (flag) { stringBuilder.Append(", "); } stringBuilder.Append(constructorParameter); flag = true; } foreach (CustomAttributeField field in Fields) { if (flag) { stringBuilder.Append(", "); } stringBuilder.Append(field); flag = true; } foreach (CustomAttributeProperty property in Properties) { if (flag) { stringBuilder.Append(", "); } stringBuilder.Append(property); flag = true; } } if (HasAnyParameters || AnyFieldsOrPropsSet) { stringBuilder.Append(')'); } stringBuilder.Append(']'); return stringBuilder.ToString(); } } public abstract class BaseCustomAttributeParameter { public AnalyzedCustomAttribute Owner { get; } public CustomAttributeParameterKind Kind { get; } public int Index { get; } protected BaseCustomAttributeParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) { Owner = owner; Kind = kind; Index = index; base..ctor(); } public abstract void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context); } public abstract class BaseCustomAttributeTypeParameter : BaseCustomAttributeParameter { public abstract TypeAnalysisContext? TypeContext { get; } protected BaseCustomAttributeTypeParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { } } public class CustomAttributeArrayParameter : BaseCustomAttributeParameter { public bool IsNullArray; public Il2CppType? EnumType; public Il2CppTypeEnum ArrType; public List ArrayElements = new List(); public CustomAttributeArrayParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) int num = reader.BaseStream.ReadUnityCompressedInt(); if (num == -1) { IsNullArray = true; return; } ArrType = (Il2CppTypeEnum)reader.ReadByte(); if ((int)ArrType == 85) { int num2 = reader.BaseStream.ReadUnityCompressedInt(); EnumType = context.Binary.GetType(num2); Il2CppTypeDefinition val = EnumType.AsClass(); ArrType = val.EnumUnderlyingType.Type; } bool flag = reader.ReadBoolean(); if (flag && (int)ArrType != 28) { throw new Exception("Array elements are type-prefixed, but the array type is not object"); } for (int i = 0; i < num; i++) { Il2CppTypeEnum rawTypeEnum = ArrType; if (flag) { rawTypeEnum = (Il2CppTypeEnum)reader.ReadByte(); } BaseCustomAttributeParameter baseCustomAttributeParameter = V29AttributeUtils.ConstructParameterForType(reader, context, rawTypeEnum, base.Owner, CustomAttributeParameterKind.ArrayElement, i); baseCustomAttributeParameter.ReadFromV29Blob(reader, context); ArrayElements.Add(baseCustomAttributeParameter); } } public override string ToString() { if (IsNullArray) { return "(array) null"; } string value = ((object)(Il2CppTypeEnum)(ref ArrType)).ToString(); if (EnumType != null) { value = ((object)EnumType.AsClass()).ToString(); } return $"new {value}[] {{{string.Join(", ", ArrayElements.Select((BaseCustomAttributeParameter x) => x.ToString()))}}}]"; } } public class CustomAttributeEnumParameter : BaseCustomAttributeParameter { public readonly Il2CppType EnumType; public readonly Il2CppType UnderlyingPrimitiveType; public readonly CustomAttributePrimitiveParameter UnderlyingPrimitiveParameter; public TypeAnalysisContext EnumTypeContext => base.Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(EnumType); public CustomAttributeEnumParameter(Il2CppType enumType, ApplicationAnalysisContext context, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) EnumType = enumType; Il2CppTypeDefinition val = EnumType.AsClass(); UnderlyingPrimitiveType = val.EnumUnderlyingType; UnderlyingPrimitiveParameter = new CustomAttributePrimitiveParameter(UnderlyingPrimitiveType.Type, owner, kind, index); } public Il2CppTypeEnum GetTypeByte() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return UnderlyingPrimitiveType.Type; } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { UnderlyingPrimitiveParameter.ReadFromV29Blob(reader, context); } public override string ToString() { Il2CppTypeDefinition val = EnumType.AsClass(); Il2CppFieldDefinition val2 = val.Fields?.FirstOrDefault((Func)delegate(Il2CppFieldDefinition f) { Il2CppFieldDefaultValue defaultValue = f.DefaultValue; return object.Equals((defaultValue != null) ? defaultValue.Value : null, UnderlyingPrimitiveParameter.PrimitiveValue); }); if (val2 != null) { return $"{val.Name}::{val2.Name} ({UnderlyingPrimitiveParameter.PrimitiveValue})"; } return UnderlyingPrimitiveParameter.ToString(); } } public class CustomAttributeField { public readonly FieldAnalysisContext Field; public readonly BaseCustomAttributeParameter Value; public CustomAttributeField(FieldAnalysisContext field, BaseCustomAttributeParameter value) { Field = field; Value = value; base..ctor(); } public override string ToString() { return $"{Field.Name} = {Value}"; } } public sealed class CustomAttributeNullParameter : BaseCustomAttributeParameter { public CustomAttributeNullParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { throw new NotSupportedException(); } } public enum CustomAttributeParameterKind { ConstructorParam, Field, Property, ArrayElement } public class CustomAttributePrimitiveParameter : BaseCustomAttributeParameter { public readonly Il2CppTypeEnum PrimitiveType; public IConvertible? PrimitiveValue; public CustomAttributePrimitiveParameter(Il2CppTypeEnum primitiveType, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) PrimitiveType = primitiveType; } public CustomAttributePrimitiveParameter(IConvertible value, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) PrimitiveValue = value; Il2CppTypeEnum primitiveType; if (!(value is string)) { if (!(value is bool)) { if (!(value is char)) { if (!(value is sbyte)) { if (!(value is byte)) { if (!(value is short)) { if (!(value is ushort)) { if (!(value is int)) { if (!(value is uint)) { if (!(value is long)) { if (!(value is ulong)) { if (!(value is float)) { if (!(value is double)) { throw new ArgumentException("Unsupported primitive type"); } primitiveType = (Il2CppTypeEnum)13; } else { primitiveType = (Il2CppTypeEnum)12; } } else { primitiveType = (Il2CppTypeEnum)11; } } else { primitiveType = (Il2CppTypeEnum)10; } } else { primitiveType = (Il2CppTypeEnum)9; } } else { primitiveType = (Il2CppTypeEnum)8; } } else { primitiveType = (Il2CppTypeEnum)7; } } else { primitiveType = (Il2CppTypeEnum)6; } } else { primitiveType = (Il2CppTypeEnum)5; } } else { primitiveType = (Il2CppTypeEnum)4; } } else { primitiveType = (Il2CppTypeEnum)3; } } else { primitiveType = (Il2CppTypeEnum)2; } } else { primitiveType = (Il2CppTypeEnum)14; } PrimitiveType = primitiveType; } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected I4, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) Il2CppTypeEnum primitiveType = PrimitiveType; switch (primitiveType - 2) { case 0: PrimitiveValue = reader.ReadBoolean(); break; case 1: PrimitiveValue = reader.ReadChar(); break; case 2: PrimitiveValue = reader.ReadSByte(); break; case 3: PrimitiveValue = reader.ReadByte(); break; case 4: PrimitiveValue = reader.ReadInt16(); break; case 5: PrimitiveValue = reader.ReadUInt16(); break; case 6: PrimitiveValue = reader.BaseStream.ReadUnityCompressedInt(); break; case 7: PrimitiveValue = reader.BaseStream.ReadUnityCompressedUint(); break; case 8: PrimitiveValue = reader.ReadInt64(); break; case 9: PrimitiveValue = reader.ReadUInt64(); break; case 10: PrimitiveValue = reader.ReadSingle(); break; case 11: PrimitiveValue = reader.ReadDouble(); break; case 12: { int num = reader.BaseStream.ReadUnityCompressedInt(); PrimitiveValue = ((num > 0) ? Encoding.UTF8.GetString(reader.ReadBytes(num)) : null); break; } default: { Il2CppTypeEnum primitiveType2 = PrimitiveType; throw new Exception("CustomAttributePrimitiveParameter constructed with a non-primitive type: " + ((object)(Il2CppTypeEnum)(ref primitiveType2)).ToString()); } } } public override string ToString() { if (!(PrimitiveValue is string str)) { return PrimitiveValue?.ToString(CultureInfo.InvariantCulture) ?? "null"; } return "\"" + str.EscapeString() + "\""; } } public class CustomAttributeProperty { public readonly PropertyAnalysisContext Property; public readonly BaseCustomAttributeParameter Value; public CustomAttributeProperty(PropertyAnalysisContext property, BaseCustomAttributeParameter value) { Property = property; Value = value; base..ctor(); } public override string ToString() { return $"{Property.Name} = {Value}"; } } public class CustomAttributeTypeParameter : BaseCustomAttributeTypeParameter { public Il2CppType? Type; public override TypeAnalysisContext? TypeContext => base.Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(Type); public CustomAttributeTypeParameter(Il2CppType? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { Type = type; } public CustomAttributeTypeParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { int num = reader.BaseStream.ReadUnityCompressedInt(); if (num == -1) { Type = null; } else { Type = context.Binary.GetType(num); } } public override string ToString() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 if (Type == null) { return "(Type) null"; } if (Il2CppTypeEnumExtensions.IsIl2CppPrimitive(Type.Type)) { return "typeof(" + LibCpp2ILUtils.GetTypeName(base.Owner.Constructor.AppContext.Metadata, base.Owner.Constructor.AppContext.Binary, Type, false); } Il2CppTypeEnum type = Type.Type; if ((int)type != 18 && (int)type != 17) { TypeAnalysisContext typeAnalysisContext = base.Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(Type); return "typeof(" + typeAnalysisContext.GetCSharpSourceString() + ")"; } return "typeof(" + Type.AsClass().Name + ")"; } } public class InjectedCustomAttributeTypeParameter : BaseCustomAttributeTypeParameter { public override TypeAnalysisContext? TypeContext { get; } public InjectedCustomAttributeTypeParameter(TypeAnalysisContext? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) { TypeContext = type; base..ctor(owner, kind, index); } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { throw new NotSupportedException(); } } } namespace Cpp2IL.Core.Model.Contexts { public class ApplicationAnalysisContext : ContextWithDataStorage { public Il2CppBinary Binary; public Il2CppMetadata Metadata; public readonly float MetadataVersion; public Cpp2IlInstructionSet InstructionSet; public SystemTypesContext SystemTypes; public readonly List Assemblies = new List(); public readonly Dictionary AssembliesByName = new Dictionary(); public readonly Dictionary> MethodsByAddress = new Dictionary>(); public readonly Dictionary ConcreteGenericMethodsByRef = new Dictionary(); private BaseKeyFunctionAddresses? _keyFunctionAddresses; public bool HasFinishedInitializing { get; private set; } public IEnumerable AllTypes => Assemblies.SelectMany((AssemblyAnalysisContext a) => a.Types); public ApplicationAnalysisContext(Il2CppBinary binary, Il2CppMetadata metadata, float metadataVersion) { Binary = binary; Metadata = metadata; MetadataVersion = metadataVersion; try { InstructionSet = InstructionSetRegistry.GetInstructionSet(binary.InstructionSetId); } catch (Exception) { throw new InstructionSetHandlerNotRegisteredException(binary.InstructionSetId); } Logger.VerboseNewline("\tUsing instruction set handler: " + InstructionSet.GetType().FullName); Il2CppAssemblyDefinition[] assemblyDefinitions = Metadata.AssemblyDefinitions; foreach (Il2CppAssemblyDefinition val in assemblyDefinitions) { Logger.VerboseNewline("\tProcessing assembly: " + val.AssemblyName.Name + "..."); AssemblyAnalysisContext assemblyAnalysisContext = new AssemblyAnalysisContext(val, this); Assemblies.Add(assemblyAnalysisContext); AssembliesByName[val.AssemblyName.Name] = assemblyAnalysisContext; } SystemTypes = new SystemTypesContext(this); PopulateMethodsByAddressTable(); HasFinishedInitializing = true; } private void PopulateMethodsByAddressTable() { Assemblies.SelectMany((AssemblyAnalysisContext a) => a.Types).SelectMany((TypeAnalysisContext t) => t.Methods).ToList() .ForEach(delegate(MethodAnalysisContext m) { ulong pointerForMethod2 = InstructionSet.GetPointerForMethod(m); if (!MethodsByAddress.ContainsKey(pointerForMethod2)) { MethodsByAddress.Add(pointerForMethod2, new List()); } MethodsByAddress[pointerForMethod2].Add(m); }); Logger.VerboseNewline("\tProcessing concrete generic methods..."); foreach (Cpp2IlMethodRef item in Binary.ConcreteGenericMethods.Values.SelectMany((List v) => v)) { try { ConcreteGenericMethodAnalysisContext concreteGenericMethodAnalysisContext = new ConcreteGenericMethodAnalysisContext(item, this); ulong pointerForMethod = InstructionSet.GetPointerForMethod(concreteGenericMethodAnalysisContext); if (!MethodsByAddress.ContainsKey(pointerForMethod)) { MethodsByAddress[pointerForMethod] = new List(); } MethodsByAddress[pointerForMethod].Add(concreteGenericMethodAnalysisContext); ConcreteGenericMethodsByRef[item] = concreteGenericMethodAnalysisContext; } catch (Exception innerException) { throw new Exception("Failed to process concrete generic method: " + (object)item, innerException); } } } public AssemblyAnalysisContext? GetAssemblyByName(string name) { if (name.Length >= 4) { string text = name; if (text[text.Length - 4] == '.') { string text2 = name; if (text2[text2.Length - 3] == 'd') { string text3 = name; name = text3.Substring(0, text3.Length - 4); goto IL_0082; } } } if (name.Length >= 6) { string text4 = name; if (text4[text4.Length - 6] == '.') { string text5 = name; if (text5[text5.Length - 5] == 'w') { string text3 = name; name = text3.Substring(0, text3.Length - 6); } } } goto IL_0082; IL_0082: return AssembliesByName[name]; } public TypeAnalysisContext? ResolveContextForType(Il2CppTypeDefinition typeDefinition) { return GetAssemblyByName(typeDefinition.DeclaringAssembly.Name)?.GetTypeByDefinition(typeDefinition); } public BaseKeyFunctionAddresses GetOrCreateKeyFunctionAddresses() { lock (InstructionSet) { if (_keyFunctionAddresses == null) { (_keyFunctionAddresses = InstructionSet.CreateKeyFunctionAddressesInstance()).Find(this); } return _keyFunctionAddresses; } } public MultiAssemblyInjectedType InjectTypeIntoAllAssemblies(string ns, string name, TypeAnalysisContext? baseType) { string ns2 = ns; string name2 = name; TypeAnalysisContext baseType2 = baseType; return new MultiAssemblyInjectedType(Assemblies.Select((AssemblyAnalysisContext a) => (InjectedTypeAnalysisContext)a.InjectType(ns2, name2, baseType2)).ToArray()); } } public class ArrayTypeAnalysisContext : WrappedTypeAnalysisContext { public override Il2CppTypeEnum Type => (Il2CppTypeEnum)20; public override string DefaultName => $"{ElementType.Name}[{Rank}]"; public sealed override bool IsValueType => false; public int Rank { get; } public ArrayTypeAnalysisContext(TypeAnalysisContext elementType, int rank, AssemblyAnalysisContext referencedFrom) { Rank = rank; base..ctor(elementType, referencedFrom); } public ArrayTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : this(referencedFrom.ResolveIl2CppType(rawType.GetArrayElementType()), rawType.GetArrayRank(), referencedFrom) { } } public class AssemblyAnalysisContext : HasCustomAttributes { public Il2CppAssemblyDefinition Definition; public List Types = new List(); public Il2CppCodeGenModule? CodeGenModule; private readonly Dictionary TypesByName = new Dictionary(); private readonly Dictionary TypesByDefinition = new Dictionary(); public IEnumerable TopLevelTypes => Types.Where((TypeAnalysisContext t) => t.DeclaringType == null); protected override int CustomAttributeIndex => Definition.CustomAttributeIndex; public override AssemblyAnalysisContext CustomAttributeAssembly => this; public override string CustomAttributeOwnerName => Definition.AssemblyName.Name; public string CleanAssemblyName => MiscUtils.CleanPathElement(Definition.AssemblyName.Name); public AssemblyAnalysisContext(Il2CppAssemblyDefinition assemblyDefinition, ApplicationAnalysisContext appContext) : base(assemblyDefinition.Token, appContext) { Definition = assemblyDefinition; if (AppContext.MetadataVersion >= 24.2f) { CodeGenModule = AppContext.Binary.GetCodegenModuleByName(Definition.Image.Name); } InitCustomAttributeData(); Il2CppTypeDefinition[] types = Definition.Image.Types; foreach (Il2CppTypeDefinition val in types) { TypeAnalysisContext typeAnalysisContext = new TypeAnalysisContext(val, this); Types.Add(typeAnalysisContext); TypesByName[val.FullName] = typeAnalysisContext; TypesByDefinition[val] = typeAnalysisContext; } foreach (TypeAnalysisContext type in Types) { if (type.Definition.NestedTypeCount >= 1) { type.NestedTypes = type.Definition.NestedTypes.Select((Il2CppTypeDefinition n) => GetTypeByFullName(n.FullName) ?? throw new Exception("Unable to find nested type by name " + n.FullName)).Peek(delegate(TypeAnalysisContext t) { t.DeclaringType = type; }).ToList(); } } } public TypeAnalysisContext InjectType(string ns, string name, TypeAnalysisContext? baseType, TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Sealed) { InjectedTypeAnalysisContext injectedTypeAnalysisContext = new InjectedTypeAnalysisContext(this, name, ns, baseType, typeAttributes); Types.Add(injectedTypeAnalysisContext); return injectedTypeAnalysisContext; } public TypeAnalysisContext? GetTypeByFullName(string fullName) { if (!TypesByName.TryGetValue(fullName, out TypeAnalysisContext value)) { return null; } return value; } public TypeAnalysisContext? GetTypeByDefinition(Il2CppTypeDefinition typeDefinition) { if (!TypesByDefinition.TryGetValue(typeDefinition, out TypeAnalysisContext value)) { return null; } return value; } public override string ToString() { return "Assembly: " + Definition.AssemblyName.Name; } } public class AttributeGeneratorMethodAnalysisContext : MethodAnalysisContext { public readonly HasCustomAttributes AssociatedMember; public override ulong UnderlyingPointer { get; } public override bool IsVoid => true; public AttributeGeneratorMethodAnalysisContext(ulong pointer, ApplicationAnalysisContext context, HasCustomAttributes associatedMember) : base(context) { UnderlyingPointer = pointer; AssociatedMember = associatedMember; RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, isAttributeGenerator: true); } } public class ByRefTypeAnalysisContext : WrappedTypeAnalysisContext { public override Il2CppTypeEnum Type => (Il2CppTypeEnum)16; public override string DefaultName => ElementType.Name + "&"; public sealed override bool IsValueType => false; public override TypeAnalysisContext ElementType => base.ElementType ?? throw new Exception("TODO Support TYPE_BYREF"); public ByRefTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom) { } public ByRefTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : this((TypeAnalysisContext)null, referencedFrom) { } } public class ConcreteGenericMethodAnalysisContext : MethodAnalysisContext { public readonly AssemblyAnalysisContext DeclaringAsm; public readonly Cpp2IlMethodRef MethodRef; public readonly MethodAnalysisContext BaseMethodContext; public sealed override ulong UnderlyingPointer => MethodRef.GenericVariantPtr; public override bool IsStatic => BaseMethodContext.IsStatic; public override bool IsVoid => BaseMethodContext.IsVoid; public override string DefaultName => BaseMethodContext.DefaultName; public override MethodAttributes Attributes => BaseMethodContext.Attributes; public override AssemblyAnalysisContext CustomAttributeAssembly => BaseMethodContext.CustomAttributeAssembly; public ConcreteGenericMethodAnalysisContext(Cpp2IlMethodRef methodRef, ApplicationAnalysisContext context) : this(methodRef, ResolveDeclaringAssembly(methodRef, context)) { } private ConcreteGenericMethodAnalysisContext(Cpp2IlMethodRef methodRef, AssemblyAnalysisContext declaringAssembly) : base(null, ResolveDeclaringType(methodRef, declaringAssembly)) { MethodRef = methodRef; DeclaringAsm = declaringAssembly; BaseMethodContext = ResolveBaseMethod(methodRef, declaringAssembly.GetTypeByDefinition(methodRef.DeclaringType)); for (int i = 0; i < BaseMethodContext.Parameters.Count; i++) { ParameterAnalysisContext parameterAnalysisContext = BaseMethodContext.Parameters[i]; TypeAnalysisContext parameterTypeContext = parameterAnalysisContext.ParameterTypeContext; TypeAnalysisContext typeAnalysisContext = GenericInstantiation.Instantiate(parameterAnalysisContext.ParameterTypeContext, ResolveTypeArray(methodRef.TypeGenericParams, declaringAssembly), ResolveTypeArray(methodRef.MethodGenericParams, declaringAssembly)); Parameters.Add((parameterTypeContext == typeAnalysisContext) ? parameterAnalysisContext : new InjectedParameterAnalysisContext(parameterAnalysisContext.Name, typeAnalysisContext, i, BaseMethodContext)); } if (UnderlyingPointer != 0L) { RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, isAttributeGenerator: false); } } private static AssemblyAnalysisContext ResolveDeclaringAssembly(Cpp2IlMethodRef methodRef, ApplicationAnalysisContext context) { return context.GetAssemblyByName(methodRef.DeclaringType.DeclaringAssembly.Name) ?? throw new Exception($"Unable to resolve declaring assembly {methodRef.DeclaringType.DeclaringAssembly.Name} for generic method {methodRef}"); } private static TypeAnalysisContext ResolveDeclaringType(Cpp2IlMethodRef methodRef, AssemblyAnalysisContext declaringAssembly) { TypeAnalysisContext? genericType = declaringAssembly.AppContext.ResolveContextForType(methodRef.DeclaringType) ?? throw new Exception($"Unable to resolve declaring type {methodRef.DeclaringType.FullName} for generic method {methodRef}"); TypeAnalysisContext[] genericArguments = ResolveTypeArray(methodRef.TypeGenericParams, declaringAssembly); return new GenericInstanceTypeAnalysisContext(genericType, genericArguments, declaringAssembly); } private static TypeAnalysisContext[] ResolveTypeArray(Il2CppTypeReflectionData[] array, AssemblyAnalysisContext declaringAssembly) { TypeAnalysisContext[] array2 = new TypeAnalysisContext[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = array[i].ToContext(declaringAssembly) ?? throw new Exception($"Unable to resolve generic parameter {array[i]} for generic method."); } return array2; } private static MethodAnalysisContext ResolveBaseMethod(Cpp2IlMethodRef methodRef, TypeAnalysisContext declaringType) { return declaringType.GetMethod(methodRef.BaseMethod) ?? throw new Exception($"Unable to resolve base method {methodRef.BaseMethod} for generic method {methodRef}"); } } public abstract class ContextWithDataStorage { private Dictionary _dataStorage = new Dictionary(); public void PutExtraData(string key, T value) where T : class { _dataStorage[key] = value; } public T? GetExtraData(string key) where T : class { if (!_dataStorage.TryGetValue(key, out object value)) { return null; } return value as T; } } public class EventAnalysisContext : HasCustomAttributesAndName, IEventInfoProvider { public readonly TypeAnalysisContext DeclaringType; public readonly Il2CppEventDefinition Definition; public readonly MethodAnalysisContext? Adder; public readonly MethodAnalysisContext? Remover; public readonly MethodAnalysisContext? Invoker; protected override int CustomAttributeIndex => Definition.customAttributeIndex; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringType.DeclaringAssembly; public override string DefaultName => Definition.Name; public TypeAnalysisContext EventTypeContext => DeclaringType.DeclaringAssembly.ResolveIl2CppType(Definition.RawType); public ITypeInfoProvider EventTypeInfoProvider { get { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (!Definition.RawType.ThisOrElementIsGenericParam()) { return TypeAnalysisContext.GetSndnProviderForType(AppContext, Definition.RawType); } return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(Definition.RawType.GetGenericParamName()); } } public string EventName => DefaultName; public EventAnalysisContext(Il2CppEventDefinition definition, TypeAnalysisContext parent) : base(definition.token, parent.AppContext) { Definition = definition; DeclaringType = parent; InitCustomAttributeData(); Adder = parent.GetMethod(definition.Adder); Remover = parent.GetMethod(definition.Remover); Invoker = parent.GetMethod(definition.Invoker); } public override string ToString() { return "Event: " + Definition.DeclaringType.Name + "::" + Definition.Name; } } public class FieldAnalysisContext : HasCustomAttributesAndName, IFieldInfoProvider { public readonly TypeAnalysisContext DeclaringType; public readonly Il2CppFieldReflectionData? BackingData; protected override int CustomAttributeIndex => BackingData?.Field.customAttributeIndex ?? (-1); public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringType.DeclaringAssembly; public override string DefaultName { get { Il2CppFieldReflectionData? backingData = BackingData; if (backingData == null) { return null; } return backingData.Field.Name; } } public Il2CppType? FieldType { get { Il2CppFieldReflectionData? backingData = BackingData; if (backingData == null) { return null; } return backingData.Field.RawFieldType; } } public virtual FieldAttributes Attributes => BackingData.Attributes; public bool IsStatic => Attributes.HasFlag(FieldAttributes.Static); public int Offset { get { if (BackingData != null) { return AppContext.Binary.GetFieldOffsetFromIndex(DeclaringType.Definition.TypeIndex, BackingData.IndexInParent, BackingData.Field.FieldIndex, DeclaringType.Definition.IsValueType, IsStatic); } return 0; } } public virtual TypeAnalysisContext FieldTypeContext => DeclaringType.DeclaringAssembly.ResolveIl2CppType(FieldType) ?? throw new Exception($"Field type {FieldType} could not be resolved."); public ITypeInfoProvider FieldTypeInfoProvider { get { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (!ThisOrElementIsGenericParam(FieldTypeContext)) { return TypeAnalysisContext.GetSndnProviderForType(AppContext, FieldType); } return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(GetGenericParamName(FieldTypeContext)); } } public string FieldName => base.Name; public FieldAttributes FieldAttributes => BackingData?.Attributes ?? FieldAttributes.PrivateScope; public FieldAnalysisContext(Il2CppFieldReflectionData? backingData, TypeAnalysisContext parent) : base(backingData?.Field.token ?? 0, parent.AppContext) { DeclaringType = parent; BackingData = backingData; if (BackingData != null) { InitCustomAttributeData(); } } public override string ToString() { Il2CppTypeDefinition? definition = DeclaringType.Definition; string obj = ((definition != null) ? definition.Name : null); Il2CppFieldReflectionData? backingData = BackingData; return "Field: " + obj + "::" + ((backingData != null) ? backingData.Field.Name : null); } private static bool ThisOrElementIsGenericParam(TypeAnalysisContext type) { if (!(type is GenericParameterTypeAnalysisContext)) { if (!(type is SzArrayTypeAnalysisContext szArrayTypeAnalysisContext)) { if (!(type is PointerTypeAnalysisContext pointerTypeAnalysisContext)) { if (type is ArrayTypeAnalysisContext arrayTypeAnalysisContext) { return ThisOrElementIsGenericParam(arrayTypeAnalysisContext.ElementType); } return false; } return ThisOrElementIsGenericParam(pointerTypeAnalysisContext.ElementType); } return ThisOrElementIsGenericParam(szArrayTypeAnalysisContext.ElementType); } return true; } private static string GetGenericParamName(TypeAnalysisContext type) { if (!ThisOrElementIsGenericParam(type)) { throw new Exception("Type is not a generic parameter"); } if (!(type is GenericParameterTypeAnalysisContext genericParameterTypeAnalysisContext)) { if (!(type is SzArrayTypeAnalysisContext szArrayTypeAnalysisContext)) { if (!(type is PointerTypeAnalysisContext pointerTypeAnalysisContext)) { if (type is ArrayTypeAnalysisContext arrayTypeAnalysisContext) { return GetGenericParamName(arrayTypeAnalysisContext.ElementType); } throw new Exception("Type is not a generic parameter"); } return GetGenericParamName(pointerTypeAnalysisContext.ElementType); } return GetGenericParamName(szArrayTypeAnalysisContext.ElementType); } return genericParameterTypeAnalysisContext.Name; } } public class GenericInstanceTypeAnalysisContext : ReferencedTypeAnalysisContext { public TypeAnalysisContext GenericType { get; } public List GenericArguments { get; } = new List(); public override string DefaultName => GenericType.Name + "<" + string.Join(", ", GenericArguments.Select((TypeAnalysisContext a) => a.Name)) + ">"; public override string DefaultNs => GenericType.Namespace; public sealed override Il2CppTypeEnum Type => (Il2CppTypeEnum)21; public sealed override bool IsGenericInstance => true; public sealed override int GenericParameterCount => GenericArguments.Count; public sealed override bool IsValueType => GenericType.IsValueType; public GenericInstanceTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(referencedFrom) { Il2CppGenericClass genericClass = rawType.GetGenericClass(); GenericType = AppContext.ResolveContextForType(genericClass.TypeDefinition) ?? throw new Exception("Could not resolve type " + genericClass.TypeDefinition.FullName + " for generic instance base type"); GenericArguments.AddRange(genericClass.Context.ClassInst.Types.Select(referencedFrom.ResolveIl2CppType)); } public GenericInstanceTypeAnalysisContext(TypeAnalysisContext genericType, IEnumerable genericArguments, AssemblyAnalysisContext referencedFrom) : base(referencedFrom) { GenericType = genericType; GenericArguments.AddRange(genericArguments); base.OverrideBaseType = genericType.BaseType; } public override string GetCSharpSourceString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(GenericType.GetCSharpSourceString()); stringBuilder.Append('<'); bool flag = true; foreach (TypeAnalysisContext genericArgument in GenericArguments) { if (!flag) { stringBuilder.Append(", "); } else { flag = false; } stringBuilder.Append(genericArgument.GetCSharpSourceString()); } stringBuilder.Append('>'); return stringBuilder.ToString(); } } public class GenericParameterTypeAnalysisContext : ReferencedTypeAnalysisContext { public sealed override string DefaultName { get; } public sealed override string DefaultNs => ""; public int Index { get; } public override Il2CppTypeEnum Type { get; } public GenericParameterTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : this(rawType.GetGenericParameterDef(), rawType.Type, referencedFrom) { }//IL_0008: Unknown result type (might be due to invalid IL or missing references) public GenericParameterTypeAnalysisContext(Il2CppGenericParameter genericParameter, Il2CppTypeEnum type, AssemblyAnalysisContext referencedFrom) : this(genericParameter.Name ?? "T", genericParameter.genericParameterIndexInOwner, type, referencedFrom) { }//IL_0016: Unknown result type (might be due to invalid IL or missing references) public GenericParameterTypeAnalysisContext(string name, int index, Il2CppTypeEnum type, AssemblyAnalysisContext referencedFrom) : base(referencedFrom) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_002a: Unknown result type (might be due to invalid IL or missing references) if ((int)type != 19 && (int)type != 30) { throw new ArgumentException($"Generic parameter type is not a generic parameter, but {type}", "type"); } DefaultName = name; Index = index; Type = type; } } public abstract class HasApplicationContext : ContextWithDataStorage { public ApplicationAnalysisContext AppContext; protected HasApplicationContext(ApplicationAnalysisContext appContext) { AppContext = appContext; base..ctor(); } } public abstract class HasCustomAttributes : HasToken { private bool _hasAnalyzedCustomAttributeData; public Memory RawIl2CppCustomAttributeData = Memory.Empty; public List? CustomAttributes; public Il2CppCustomAttributeTypeRange? AttributeTypeRange; public List? AttributeTypes; public AttributeGeneratorMethodAnalysisContext? CaCacheGeneratorAnalysis; protected abstract int CustomAttributeIndex { get; } public abstract AssemblyAnalysisContext CustomAttributeAssembly { get; } public abstract string CustomAttributeOwnerName { get; } public bool IsCompilerGeneratedBasedOnCustomAttributes => CustomAttributes?.Any((AnalyzedCustomAttribute a) => a.Constructor.DeclaringType.FullName.Contains("CompilerGeneratedAttribute")) ?? AttributeTypes?.Any((Il2CppType t) => (int)t.Type == 18 && t.AsClass().FullName.Contains("CompilerGeneratedAttribute")) ?? false; protected HasCustomAttributes(uint token, ApplicationAnalysisContext appContext) : base(token, appContext) { } protected void InitCustomAttributeData() { if (AppContext.MetadataVersion >= 29f) { (long, long)? v29BlobOffsets = GetV29BlobOffsets(); if (v29BlobOffsets.HasValue) { (long, long) value = v29BlobOffsets.Value; long item = value.Item1; long item2 = value.Item2; RawIl2CppCustomAttributeData = ((ClassReadingBinaryReader)AppContext.Metadata).ReadByteArrayAtRawAddress(item, (int)(item2 - item)); } return; } int num = default(int); AttributeTypeRange = AppContext.Metadata.GetCustomAttributeData(CustomAttributeAssembly.Definition.Image, CustomAttributeIndex, base.Token, ref num); if (AttributeTypeRange == null || AttributeTypeRange.count == 0) { RawIl2CppCustomAttributeData = Array.Empty(); AttributeTypes = new List(); return; } AttributeTypes = (from attrIdx in Enumerable.Range(AttributeTypeRange.start, AttributeTypeRange.count) select LibCpp2IlMain.TheMetadata.attributeTypes[attrIdx] into typeIdx select LibCpp2IlMain.Binary.GetType(typeIdx)).ToList(); ulong num2; if (AppContext.MetadataVersion < 27f) { try { num2 = AppContext.Binary.GetCustomAttributeGenerator(num); } catch (IndexOutOfRangeException) { Logger.WarnNewline("Custom attribute generator out of range for " + this, "CA Restore"); RawIl2CppCustomAttributeData = Array.Empty(); return; } } else { ulong customAttributeCacheGenerator = CustomAttributeAssembly.CodeGenModule.customAttributeCacheGenerator; int num3 = num - CustomAttributeAssembly.Definition.Image.customAttributeStart; ulong num4 = customAttributeCacheGenerator + (ulong)((long)num3 * (long)((ClassReadingBinaryReader)AppContext.Binary).PointerSize); num2 = AppContext.Binary.ReadPointerAtVirtualAddress(num4); } long num5 = default(long); if (num2 == 0L || !AppContext.Binary.TryMapVirtualAddressToRaw(num2, ref num5)) { Logger.WarnNewline("Supposedly had custom attributes (" + string.Join(", ", AttributeTypes) + "), but generator was null for " + this, "CA Restore"); RawIl2CppCustomAttributeData = Memory.Empty; } else { CaCacheGeneratorAnalysis = new AttributeGeneratorMethodAnalysisContext(num2, AppContext, this); RawIl2CppCustomAttributeData = CaCacheGeneratorAnalysis.RawBytes; } } private (long blobStart, long blobEnd)? GetV29BlobOffsets() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown Il2CppCustomAttributeDataRange item = new Il2CppCustomAttributeDataRange { token = base.Token }; int num = AppContext.Metadata.AttributeDataRanges.BinarySearch(CustomAttributeAssembly.Definition.Image.customAttributeStart, (int)CustomAttributeAssembly.Definition.Image.customAttributeCount, item, (IComparer?)new TokenComparer()); if (num < 0) { RawIl2CppCustomAttributeData = Array.Empty(); return null; } Il2CppCustomAttributeDataRange val = AppContext.Metadata.AttributeDataRanges[num]; Il2CppCustomAttributeDataRange val2 = AppContext.Metadata.AttributeDataRanges[num + 1]; long item2 = AppContext.Metadata.metadataHeader.attributeDataOffset + val.startOffset; long item3 = AppContext.Metadata.metadataHeader.attributeDataOffset + val2.startOffset; return (item2, item3); } public void AnalyzeCustomAttributeData(bool allowAnalysis = true) { if (_hasAnalyzedCustomAttributeData) { return; } _hasAnalyzedCustomAttributeData = true; CustomAttributes = new List(); if (AppContext.MetadataVersion >= 29f) { AnalyzeCustomAttributeDataV29(); } else { if (RawIl2CppCustomAttributeData.Length == 0) { return; } if (allowAnalysis) { try { CaCacheGeneratorAnalysis.Analyze(); } catch (Exception ex) { Logger.WarnNewline("Failed to analyze custom attribute cache generator for " + this?.ToString() + " because " + ex.Message, "CA Restore"); return; } } foreach (Il2CppType attributeType in AttributeTypes) { Il2CppTypeDefinition val = attributeType.AsClass(); TypeAnalysisContext typeAnalysisContext = AppContext.ResolveContextForType(val) ?? throw new Exception("Unable to find type " + val.FullName); MethodAnalysisContext methodAnalysisContext = typeAnalysisContext.Methods.FirstOrDefault((MethodAnalysisContext c) => c.MethodName == ".ctor" && c.Definition.parameterCount == 0); AnalyzedCustomAttribute item; if (methodAnalysisContext != null) { item = new AnalyzedCustomAttribute(methodAnalysisContext); } else { MethodAnalysisContext methodAnalysisContext2 = typeAnalysisContext.Methods.FirstOrDefault((MethodAnalysisContext c) => c.MethodName == ".ctor"); if (methodAnalysisContext2 == null) { continue; } item = new AnalyzedCustomAttribute(methodAnalysisContext2); } CustomAttributes.Add(item); } } } private void AnalyzeCustomAttributeDataV29() { if (RawIl2CppCustomAttributeData.Length == 0) { return; } using MemoryStream memoryStream = new MemoryStream(RawIl2CppCustomAttributeData.ToArray()); uint count = memoryStream.ReadUnityCompressedUint(); Il2CppMethodDefinition[] array = V29AttributeUtils.ReadConstructors(memoryStream, count, AppContext); long position = memoryStream.Position; Dictionary dictionary = new Dictionary(); CustomAttributes = new List(); Il2CppMethodDefinition[] array2 = array; foreach (Il2CppMethodDefinition val in array2) { dictionary[val] = memoryStream.Position; TypeAnalysisContext typeAnalysisContext = AppContext.ResolveContextForType(val.DeclaringType) ?? throw new Exception("Unable to find type " + val.DeclaringType.FullName); MethodAnalysisContext? method = typeAnalysisContext.GetMethod(val); if (method == null) { string name = val.Name; Il2CppTypeDefinition? definition = typeAnalysisContext.Definition; throw new Exception("Unable to find method " + name + " in type " + ((definition != null) ? definition.FullName : null)); } MethodAnalysisContext constructor = method; try { CustomAttributes.Add(V29AttributeUtils.ReadAttribute(memoryStream, constructor, AppContext)); } catch (Exception ex) { Logger.ErrorNewline($"Failed to read attribute data for {val}, which has parameters {string.Join(", ", val.Parameters.Select((Il2CppParameterReflectionData p) => p.Type))}", "CA Restore"); Logger.ErrorNewline($"This member ({ToString()}) has {RawIl2CppCustomAttributeData.Length} bytes of data starting at 0x{GetV29BlobOffsets().Value.blobStart:X}", "CA Restore"); Logger.ErrorNewline($"The post-constructor data started at 0x{position:X} bytes into our blob", "CA Restore"); Logger.ErrorNewline($"Data for this constructor started at 0x{dictionary[val]:X} bytes into our blob, we are now 0x{memoryStream.Position:X} bytes into the blob", "CA Restore"); Logger.ErrorNewline("The exception message was " + ex.Message, "CA Restore"); throw; } } } } public abstract class HasCustomAttributesAndName : HasCustomAttributes { public abstract string DefaultName { get; } public string? OverrideName { get; set; } public string Name => OverrideName ?? DefaultName; public sealed override string CustomAttributeOwnerName => Name; protected HasCustomAttributesAndName(uint token, ApplicationAnalysisContext appContext) : base(token, appContext) { } } public class HasToken : HasApplicationContext, IIl2CppTokenProvider { public uint Token { get; } public HasToken(uint token, ApplicationAnalysisContext appContext) { Token = token; base..ctor(appContext); } } public class InjectedFieldAnalysisContext : FieldAnalysisContext { public override TypeAnalysisContext FieldTypeContext { get; } public override FieldAttributes Attributes { get; } public InjectedFieldAnalysisContext(string name, TypeAnalysisContext type, FieldAttributes attributes, TypeAnalysisContext parent) : base(null, parent) { base.OverrideName = name; Attributes = attributes; FieldTypeContext = type; } } public class InjectedMethodAnalysisContext : MethodAnalysisContext { public override ulong UnderlyingPointer => 0uL; public override string DefaultName { get; } public override bool IsStatic { get; } public override MethodAttributes Attributes { get; } public InjectedMethodAnalysisContext(TypeAnalysisContext parent, string name, bool isStatic, TypeAnalysisContext returnType, MethodAttributes attributes, TypeAnalysisContext[] injectedParameterTypes, string[]? injectedParameterNames = null) : base(null, parent) { DefaultName = name; base.InjectedReturnType = returnType; IsStatic = isStatic; Attributes = attributes; for (int i = 0; i < injectedParameterTypes.Length; i++) { TypeAnalysisContext typeContext = injectedParameterTypes[i]; string name2 = ((injectedParameterNames != null) ? injectedParameterNames[i] : null); Parameters.Add(new InjectedParameterAnalysisContext(name2, typeContext, i, this)); } } } public class InjectedParameterAnalysisContext : ParameterAnalysisContext { public override TypeAnalysisContext ParameterTypeContext { get; } public override bool IsRef => ParameterTypeContext is ReferencedTypeAnalysisContext; public override ParameterAttributes ParameterAttributes => ParameterAttributes.None; public InjectedParameterAnalysisContext(string? name, Il2CppType type, int paramIndex, MethodAnalysisContext declaringMethod) : this(name, declaringMethod.DeclaringType.DeclaringAssembly.ResolveIl2CppType(type) ?? throw new Exception($"Type {type} could not be resolved."), paramIndex, declaringMethod) { } public InjectedParameterAnalysisContext(string? name, TypeAnalysisContext typeContext, int paramIndex, MethodAnalysisContext declaringMethod) : base(null, paramIndex, declaringMethod) { base.OverrideName = name ?? $"param_{paramIndex}"; ParameterTypeContext = typeContext; } } public class InjectedTypeAnalysisContext : TypeAnalysisContext { public override string DefaultName { get; } public override string DefaultNs { get; } public override TypeAttributes TypeAttributes { get; } public InjectedTypeAnalysisContext(AssemblyAnalysisContext containingAssembly, string name, string ns, TypeAnalysisContext? baseType, TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Sealed) : base(null, containingAssembly) { DefaultName = name; DefaultNs = ns; base.OverrideBaseType = baseType; TypeAttributes = typeAttributes; } public InjectedMethodAnalysisContext InjectMethodContext(string methodName, bool isStatic, TypeAnalysisContext returnType, MethodAttributes attributes, params TypeAnalysisContext[] args) { if (args.Any((TypeAnalysisContext a) => a.Definition == null)) { throw new Exception("Cannot inject a method using injected types as parameters, yet."); } InjectedMethodAnalysisContext injectedMethodAnalysisContext = new InjectedMethodAnalysisContext(this, methodName, isStatic, returnType, attributes, args); Methods.Add(injectedMethodAnalysisContext); return injectedMethodAnalysisContext; } public InjectedFieldAnalysisContext InjectFieldContext(string fieldName, TypeAnalysisContext fieldType, FieldAttributes attributes) { InjectedFieldAnalysisContext injectedFieldAnalysisContext = new InjectedFieldAnalysisContext(fieldName, fieldType, attributes, this); Fields.Add(injectedFieldAnalysisContext); return injectedFieldAnalysisContext; } } public class MethodAnalysisContext : HasCustomAttributesAndName, IMethodInfoProvider { public readonly Il2CppMethodDefinition? Definition; public readonly TypeAnalysisContext? DeclaringType; public Memory RawBytes; public List? ConvertedIsil; public ISILControlFlowGraph? ControlFlowGraph; public List Parameters = new List(); private static List blockProcessors = new List(2) { new MetadataProcessor(), new CallProcessor() }; public virtual ulong UnderlyingPointer => (Definition ?? throw new Exception("Subclasses of MethodAnalysisContext should override UnderlyingPointer")).MethodPointer; public ulong Rva { get { if (UnderlyingPointer != 0L && LibCpp2IlMain.Binary != null) { return LibCpp2IlMain.Binary.GetRva(UnderlyingPointer); } return 0uL; } } public virtual bool IsVoid { get { Il2CppMethodDefinition? definition = Definition; return (((definition == null) ? null : ((object)definition.ReturnType)?.ToString()) ?? throw new Exception("Subclasses of MethodAnalysisContext should override IsVoid")) == "System.Void"; } } public virtual bool IsStatic => (Definition ?? throw new Exception("Subclasses of MethodAnalysisContext should override IsStatic")).IsStatic; protected override int CustomAttributeIndex => (Definition ?? throw new Exception("Subclasses of MethodAnalysisContext should override CustomAttributeIndex if they have custom attributes")).customAttributeIndex; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringType?.DeclaringAssembly ?? throw new Exception("Subclasses of MethodAnalysisContext should override CustomAttributeAssembly if they have custom attributes"); public override string DefaultName { get { Il2CppMethodDefinition? definition = Definition; return ((definition != null) ? definition.Name : null) ?? throw new Exception("Subclasses of MethodAnalysisContext should override DefaultName"); } } public virtual MethodAttributes Attributes => (Definition ?? throw new Exception("Subclasses of MethodAnalysisContext should override Attributes")).Attributes; public TypeAnalysisContext? InjectedReturnType { get; set; } public int ParameterCount => Parameters.Count; public TypeAnalysisContext ReturnTypeContext => InjectedReturnType ?? DeclaringType.DeclaringAssembly.ResolveIl2CppType(Definition.RawReturnType); public ITypeInfoProvider ReturnType { get { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (!Definition.RawReturnType.ThisOrElementIsGenericParam()) { return TypeAnalysisContext.GetSndnProviderForType(AppContext, Definition.RawReturnType); } return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(Definition.RawReturnType.GetGenericParamName()); } } public IEnumerable ParameterInfoProviders => (IEnumerable)Parameters; public string MethodName => base.Name; public MethodAttributes MethodAttributes => Attributes; public MethodSemantics MethodSemantics { get { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (DeclaringType != null) { foreach (PropertyAnalysisContext property in DeclaringType.Properties) { if (property.Getter == this) { return (MethodSemantics)2; } if (property.Setter == this) { return (MethodSemantics)1; } } foreach (EventAnalysisContext @event in DeclaringType.Events) { if (@event.Adder == this) { return (MethodSemantics)8; } if (@event.Remover == this) { return (MethodSemantics)16; } if (@event.Invoker == this) { return (MethodSemantics)32; } } } return (MethodSemantics)0; } } public MethodAnalysisContext(Il2CppMethodDefinition? definition, TypeAnalysisContext parent) : base(definition?.token ?? 0, parent.AppContext) { DeclaringType = parent; Definition = definition; if (Definition != null) { InitCustomAttributeData(); if (Definition.MethodPointer != 0L && !Definition.Attributes.HasFlag(MethodAttributes.Abstract)) { RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, isAttributeGenerator: false); if (RawBytes.Length == 0) { Logger.VerboseNewline("\t\t\tUnexpectedly got 0-byte method body for " + this?.ToString() + $". Pointer was 0x{Definition.MethodPointer:X}", "MAC"); } } else { RawBytes = Array.Empty(); } for (int i = 0; i < Definition.InternalParameterData.Length; i++) { Il2CppParameterDefinition definition2 = Definition.InternalParameterData[i]; Parameters.Add(new ParameterAnalysisContext(definition2, i, this)); } } else { RawBytes = Array.Empty(); } } protected MethodAnalysisContext(ApplicationAnalysisContext context) : base(0u, context) { RawBytes = Array.Empty(); } [MemberNotNull("ConvertedIsil")] public void Analyze() { if (ConvertedIsil != null) { return; } if (UnderlyingPointer == 0L) { ConvertedIsil = new List(); return; } ConvertedIsil = AppContext.InstructionSet.GetIsilFromMethod(this); if (ConvertedIsil.Count == 0) { return; } ControlFlowGraph = new ISILControlFlowGraph(); ControlFlowGraph.Build(ConvertedIsil); foreach (Block block in ControlFlowGraph.Blocks) { foreach (IBlockProcessor blockProcessor in blockProcessors) { blockProcessor.Process(this, block); } } } public void ReleaseAnalysisData() { ConvertedIsil = null; ControlFlowGraph = null; } public override string ToString() { Il2CppMethodDefinition? definition = Definition; string obj = ((definition != null) ? definition.DeclaringType.Name : null); Il2CppMethodDefinition? definition2 = Definition; return "Method: " + obj + "::" + (((definition2 != null) ? definition2.Name : null) ?? "No definition"); } } public sealed class NativeMethodAnalysisContext : MethodAnalysisContext { public override ulong UnderlyingPointer { get; } public override string DefaultName { get; } public override bool IsStatic => true; public override bool IsVoid { get; } public override MethodAttributes Attributes => MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig; protected override int CustomAttributeIndex => -1; public NativeMethodAnalysisContext(TypeAnalysisContext parent, ulong address, bool voidReturn) : base(null, parent) { if (address == 0L) { throw new ArgumentOutOfRangeException("address"); } IsVoid = voidReturn; UnderlyingPointer = address; Il2CppBinary binary = LibCpp2IlMain.Binary; string text = default(string); if (binary != null && binary.TryGetExportedFunctionName(UnderlyingPointer, ref text)) { DefaultName = text; } else { DefaultName = $"NativeMethod_0x{UnderlyingPointer:X}"; } RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, isAttributeGenerator: false); } } public class ParameterAnalysisContext : HasCustomAttributesAndName, IParameterInfoProvider { public Il2CppParameterDefinition? Definition { get; } public int ParamIndex { get; } public MethodAnalysisContext DeclaringMethod { get; } public virtual Il2CppType ParameterType { get { Il2CppParameterDefinition? definition = Definition; return ((definition != null) ? definition.RawType : null) ?? throw new Exception("Subclasses of ParameterAnalysisContext must provide a parameter type"); } } protected override int CustomAttributeIndex => (Definition ?? throw new Exception("Subclasses of ParameterAnalysisContext must provide a customAttributeIndex")).customAttributeIndex; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringMethod.DeclaringType.DeclaringAssembly; public override string DefaultName { get { Il2CppParameterDefinition? definition = Definition; return ((definition != null) ? definition.Name : null) ?? throw new Exception("Subclasses of ParameterAnalysisContext must provide a default name"); } } public string ReadableTypeName => ((object)LibCpp2ILUtils.GetTypeReflectionData(ParameterType)).ToString(); public string HumanReadableSignature => ReadableTypeName + " " + base.Name; public virtual ParameterAttributes ParameterAttributes => (ParameterAttributes)ParameterType.Attrs; public virtual bool IsRef { get { if (ParameterType.Byref != 1) { return ParameterAttributes.HasFlag(ParameterAttributes.Out); } return true; } } public Il2CppParameterDefaultValue? DefaultValue { get; } public virtual TypeAnalysisContext ParameterTypeContext => DeclaringMethod.DeclaringType.DeclaringAssembly.ResolveIl2CppType(ParameterType); public ITypeInfoProvider ParameterTypeInfoProvider { get { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (!Definition.RawType.ThisOrElementIsGenericParam()) { return TypeAnalysisContext.GetSndnProviderForType(AppContext, Definition.RawType); } return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(Definition.RawType.GetGenericParamName()); } } public string ParameterName => base.Name; public ParameterAnalysisContext(Il2CppParameterDefinition? definition, int paramIndex, MethodAnalysisContext declaringMethod) : base(definition?.token ?? 0, declaringMethod.AppContext) { Definition = definition; ParamIndex = paramIndex; DeclaringMethod = declaringMethod; if (Definition != null) { InitCustomAttributeData(); if (ParameterAttributes.HasFlag(ParameterAttributes.HasDefault)) { DefaultValue = AppContext.Metadata.GetParameterDefaultValueFromIndex(declaringMethod.Definition.parameterStart + paramIndex); } } } public override string ToString() { if (!AppContext.HasFinishedInitializing) { return $"Parameter {base.Name} (ordinal {ParamIndex}) of {DeclaringMethod}"; } StringBuilder stringBuilder = new StringBuilder(); if (ParameterAttributes.HasFlag(ParameterAttributes.Out)) { stringBuilder.Append("out "); } else if (ParameterAttributes.HasFlag(ParameterAttributes.In)) { stringBuilder.Append("in "); } else if (ParameterType.Byref == 1) { stringBuilder.Append("ref "); } stringBuilder.Append(CsFileUtils.GetTypeName(ParameterTypeContext.Name)).Append(' '); if (string.IsNullOrEmpty(ParameterName)) { stringBuilder.Append("unnamed_param_").Append(ParamIndex); } else { stringBuilder.Append(ParameterName); } if (ParameterAttributes.HasFlag(ParameterAttributes.HasDefault)) { object obj = DefaultValue.ContainedDefaultValue; if (obj is string text) { obj = "\"" + text + "\""; } else if (obj is bool flag) { obj = flag.ToString().ToLowerInvariant(); } else if (obj == null) { obj = "null"; } stringBuilder.Append(" = ").Append(obj); } return stringBuilder.ToString(); } } public class PointerTypeAnalysisContext : WrappedTypeAnalysisContext { public override Il2CppTypeEnum Type => (Il2CppTypeEnum)15; public override string DefaultName => ElementType.Name + "*"; public sealed override bool IsValueType => false; public PointerTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom) { } public PointerTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : this(referencedFrom.ResolveIl2CppType(rawType.GetEncapsulatedType()), referencedFrom) { } } public class PropertyAnalysisContext : HasCustomAttributesAndName, IPropertyInfoProvider { public TypeAnalysisContext DeclaringType { get; } public Il2CppPropertyDefinition Definition { get; } public MethodAnalysisContext? Getter { get; } public MethodAnalysisContext? Setter { get; } protected override int CustomAttributeIndex => Definition.customAttributeIndex; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringType.DeclaringAssembly; public override string DefaultName => Definition.Name; public TypeAnalysisContext PropertyTypeContext => DeclaringType.DeclaringAssembly.ResolveIl2CppType(Definition.RawPropertyType); public ITypeInfoProvider PropertyTypeInfoProvider { get { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (!Definition.RawPropertyType.ThisOrElementIsGenericParam()) { return TypeAnalysisContext.GetSndnProviderForType(AppContext, Definition.RawPropertyType); } return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(Definition.RawPropertyType.GetGenericParamName()); } } public string PropertyName => base.Name; public PropertyAnalysisContext(Il2CppPropertyDefinition definition, TypeAnalysisContext parent) : base(definition.token, parent.AppContext) { DeclaringType = parent; Definition = definition; InitCustomAttributeData(); Getter = parent.GetMethod(definition.Getter); Setter = parent.GetMethod(definition.Setter); } public override string ToString() { return "Property: " + Definition.DeclaringType.Name + "::" + Definition.Name; } } public abstract class ReferencedTypeAnalysisContext : TypeAnalysisContext { public abstract Il2CppTypeEnum Type { get; } protected override int CustomAttributeIndex => -1; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly; protected ReferencedTypeAnalysisContext(AssemblyAnalysisContext referencedFrom) : base(null, referencedFrom) { } public override string ToString() { return DefaultName; } public override string GetCSharpSourceString() { return base.Name; } } public class SystemTypesContext { private ApplicationAnalysisContext _appContext; public TypeAnalysisContext SystemObjectType { get; } public TypeAnalysisContext SystemVoidType { get; } public TypeAnalysisContext SystemBooleanType { get; } public TypeAnalysisContext SystemCharType { get; } public TypeAnalysisContext SystemSByteType { get; } public TypeAnalysisContext SystemByteType { get; } public TypeAnalysisContext SystemInt16Type { get; } public TypeAnalysisContext SystemUInt16Type { get; } public TypeAnalysisContext SystemInt32Type { get; } public TypeAnalysisContext SystemUInt32Type { get; } public TypeAnalysisContext SystemInt64Type { get; } public TypeAnalysisContext SystemUInt64Type { get; } public TypeAnalysisContext SystemSingleType { get; } public TypeAnalysisContext SystemDoubleType { get; } public TypeAnalysisContext SystemIntPtrType { get; } public TypeAnalysisContext SystemUIntPtrType { get; } public TypeAnalysisContext SystemExceptionType { get; } public TypeAnalysisContext SystemStringType { get; } public TypeAnalysisContext SystemTypedReferenceType { get; } public TypeAnalysisContext SystemTypeType { get; } public TypeAnalysisContext SystemAttributeType { get; } public TypeAnalysisContext? UnmanagedCallersOnlyAttributeType { get; } public SystemTypesContext(ApplicationAnalysisContext appContext) { _appContext = appContext; AssemblyAnalysisContext assemblyAnalysisContext = _appContext.GetAssemblyByName("mscorlib") ?? throw new Exception("Could not find system assembly"); SystemObjectType = assemblyAnalysisContext.GetTypeByFullName("System.Object"); SystemVoidType = assemblyAnalysisContext.GetTypeByFullName("System.Void"); SystemBooleanType = assemblyAnalysisContext.GetTypeByFullName("System.Boolean"); SystemCharType = assemblyAnalysisContext.GetTypeByFullName("System.Char"); SystemSByteType = assemblyAnalysisContext.GetTypeByFullName("System.SByte"); SystemByteType = assemblyAnalysisContext.GetTypeByFullName("System.Byte"); SystemInt16Type = assemblyAnalysisContext.GetTypeByFullName("System.Int16"); SystemUInt16Type = assemblyAnalysisContext.GetTypeByFullName("System.UInt16"); SystemInt32Type = assemblyAnalysisContext.GetTypeByFullName("System.Int32"); SystemUInt32Type = assemblyAnalysisContext.GetTypeByFullName("System.UInt32"); SystemInt64Type = assemblyAnalysisContext.GetTypeByFullName("System.Int64"); SystemUInt64Type = assemblyAnalysisContext.GetTypeByFullName("System.UInt64"); SystemSingleType = assemblyAnalysisContext.GetTypeByFullName("System.Single"); SystemDoubleType = assemblyAnalysisContext.GetTypeByFullName("System.Double"); SystemIntPtrType = assemblyAnalysisContext.GetTypeByFullName("System.IntPtr"); SystemUIntPtrType = assemblyAnalysisContext.GetTypeByFullName("System.UIntPtr"); SystemStringType = assemblyAnalysisContext.GetTypeByFullName("System.String"); SystemTypedReferenceType = assemblyAnalysisContext.GetTypeByFullName("System.TypedReference"); SystemTypeType = assemblyAnalysisContext.GetTypeByFullName("System.Type"); SystemExceptionType = assemblyAnalysisContext.GetTypeByFullName("System.Exception"); SystemAttributeType = assemblyAnalysisContext.GetTypeByFullName("System.Attribute"); UnmanagedCallersOnlyAttributeType = assemblyAnalysisContext.GetTypeByFullName("System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute"); } } public class SzArrayTypeAnalysisContext : WrappedTypeAnalysisContext { public override Il2CppTypeEnum Type => (Il2CppTypeEnum)29; public override string DefaultName => ElementType.Name + "[]"; public sealed override bool IsValueType => false; public SzArrayTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom) { } public SzArrayTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : this(referencedFrom.ResolveIl2CppType(rawType.GetEncapsulatedType()), referencedFrom) { } } public class TypeAnalysisContext : HasCustomAttributesAndName, ITypeInfoProvider, ICSharpSourceToken { internal const TypeAttributes DefaultTypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed; public readonly AssemblyAnalysisContext DeclaringAssembly; public readonly Il2CppTypeDefinition? Definition; public readonly List Methods; public readonly List Properties; public readonly List Events; public readonly List Fields; public List NestedTypes { get; internal set; } = new List(); protected override int CustomAttributeIndex => Definition.CustomAttributeIndex; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly; public override string DefaultName { get { Il2CppTypeDefinition? definition = Definition; return ((definition != null) ? definition.Name : null) ?? throw new Exception("Subclasses of TypeAnalysisContext must override DefaultName"); } } public virtual string DefaultNs { get { Il2CppTypeDefinition? definition = Definition; return ((definition != null) ? definition.Namespace : null) ?? throw new Exception("Subclasses of TypeAnalysisContext must override DefaultNs"); } } public string? OverrideNs { get; set; } public string Namespace => OverrideNs ?? DefaultNs; public TypeAnalysisContext? OverrideBaseType { get; protected set; } public TypeAnalysisContext? DeclaringType { get; protected internal set; } public TypeAnalysisContext? BaseType { get { object obj = OverrideBaseType; if (obj == null) { if (Definition != null) { return DeclaringAssembly.ResolveIl2CppType(Definition.RawBaseType); } obj = null; } return (TypeAnalysisContext?)obj; } } public TypeAnalysisContext[] InterfaceContexts { get { Il2CppTypeDefinition? definition = Definition; return ((definition != null) ? definition.RawInterfaces.Select(DeclaringAssembly.ResolveIl2CppType).ToArray() : null) ?? Array.Empty(); } } public string FullName { get { if (DeclaringType != null) { return DeclaringType.FullName + "." + base.Name; } if (string.IsNullOrEmpty(Namespace)) { return base.Name; } return Namespace + "." + base.Name; } } public string NamespaceAsSubdirs { get { string @namespace = Namespace; if (!string.IsNullOrEmpty(@namespace)) { return Path.Combine(MiscUtils.CleanPathElement(@namespace).Split('.')); } return ""; } } public TypeAnalysisContext UltimateDeclaringType => DeclaringType ?? this; public IEnumerable Interfaces => Definition.RawInterfaces.Select((Il2CppType t) => GetSndnProviderForType(AppContext, t)); public virtual TypeAttributes TypeAttributes { get { Il2CppTypeDefinition? definition = Definition; if (definition == null) { return TypeAttributes.Public | TypeAttributes.Sealed; } return definition.Attributes; } } public virtual int GenericParameterCount => Definition.GenericContainer?.genericParameterCount ?? 0; public string OriginalTypeName => DefaultName; public string RewrittenTypeName => base.Name; public string TypeNamespace => Namespace; public virtual bool IsGenericInstance => false; public virtual bool IsValueType { get { Il2CppTypeDefinition? definition = Definition; if (definition == null) { TypeAnalysisContext baseType = BaseType; if (baseType != null && baseType.Namespace == "System") { return baseType.Name == "ValueType"; } return false; } return definition.IsValueType; } } public bool IsEnumType { get { Il2CppTypeDefinition? definition = Definition; if (definition == null) { TypeAnalysisContext baseType = BaseType; if (baseType != null && baseType.Namespace == "System") { return baseType.Name == "Enum"; } return false; } return definition.IsEnumType; } } public bool IsInterface { get { Il2CppTypeDefinition? definition = Definition; if (definition == null) { return (TypeAttributes & TypeAttributes.ClassSemanticsMask) != 0; } return definition.IsInterface; } } public IEnumerable GenericArgumentInfoProviders => Array.Empty(); public IEnumerable FieldInfoProviders => (IEnumerable)Fields; public IEnumerable MethodInfoProviders => (IEnumerable)Methods; public IEnumerable PropertyInfoProviders => (IEnumerable)Properties; public ITypeInfoProvider? DeclaringTypeInfoProvider => (ITypeInfoProvider?)(object)DeclaringType; public TypeAnalysisContext(Il2CppTypeDefinition? il2CppTypeDefinition, AssemblyAnalysisContext containingAssembly) : base(il2CppTypeDefinition?.Token ?? 0, containingAssembly.AppContext) { DeclaringAssembly = containingAssembly; Definition = il2CppTypeDefinition; if (Definition != null) { InitCustomAttributeData(); Methods = Definition.Methods.Select((Il2CppMethodDefinition m) => new MethodAnalysisContext(m, this)).ToList(); Properties = Definition.Properties.Select((Il2CppPropertyDefinition p) => new PropertyAnalysisContext(p, this)).ToList(); Events = Definition.Events.Select((Il2CppEventDefinition e) => new EventAnalysisContext(e, this)).ToList(); Fields = (from f in Definition.FieldInfos.ToList() select new FieldAnalysisContext(f, this)).ToList(); } else { Methods = new List(); Properties = new List(); Events = new List(); Fields = new List(); } } public MethodAnalysisContext? GetMethod(Il2CppMethodDefinition? methodDefinition) { Il2CppMethodDefinition methodDefinition2 = methodDefinition; if (methodDefinition2 == null) { return null; } return Methods.Find((MethodAnalysisContext m) => m.Definition == methodDefinition2); } public List GetConstructors() { return Methods.Where((MethodAnalysisContext m) => m.Definition.Name == ".ctor").ToList(); } public override string ToString() { Il2CppTypeDefinition? definition = Definition; return "Type: " + ((definition != null) ? definition.FullName : null); } public virtual string GetCSharpSourceString() { if (Definition != null) { return Definition.FullName; } StringBuilder stringBuilder = new StringBuilder(); if (OverrideNs != null) { stringBuilder.Append(OverrideNs).Append('.'); } stringBuilder.Append(base.Name); return stringBuilder.ToString(); } public ArrayTypeAnalysisContext MakeArrayType(int rank) { return new ArrayTypeAnalysisContext(this, rank, DeclaringAssembly); } public ByRefTypeAnalysisContext MakeByReferenceType() { return new ByRefTypeAnalysisContext(this, DeclaringAssembly); } public PointerTypeAnalysisContext MakePointerType() { return new PointerTypeAnalysisContext(this, DeclaringAssembly); } public SzArrayTypeAnalysisContext MakeSzArrayType() { return new SzArrayTypeAnalysisContext(this, DeclaringAssembly); } public IEnumerable GetBaseTypeHierarchy() { if (OverrideBaseType != null) { throw new Exception("Type hierarchy for injected types is not supported"); } for (Il2CppType baseType = Definition.RawBaseType; baseType != null; baseType = baseType.CoerceToUnderlyingTypeDefinition().RawBaseType) { yield return GetSndnProviderForType(AppContext, baseType); } } public static ITypeInfoProvider GetSndnProviderForType(ApplicationAnalysisContext appContext, Il2CppType type) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Invalid comparison between Unknown and I4 //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Invalid comparison between Unknown and I4 //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Invalid comparison between Unknown and I4 //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) ApplicationAnalysisContext appContext2 = appContext; if ((int)type.Type == 21) { Il2CppGenericClass genericClass = type.GetGenericClass(); TypeAnalysisContext typeAnalysisContext = appContext2.ResolveContextForType(genericClass.TypeDefinition); Il2CppType[] types = genericClass.Context.ClassInst.Types; if (types.Any(delegate(Il2CppType t) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 Il2CppTypeEnum type3 = t.Type; return ((int)type3 == 19 || (int)type3 == 30) ? true : false; })) { return (ITypeInfoProvider)(object)typeAnalysisContext; } ITypeInfoProvider[] array = types.Select((Il2CppType t) => GetSndnProviderForType(appContext2, t)).ToArray(); return (ITypeInfoProvider)new GenericInstanceTypeInfoProviderWrapper((ITypeInfoProvider)(object)typeAnalysisContext, array); } Il2CppTypeEnum type2 = type.Type; if (((int)type2 == 19 || (int)type2 == 30) ? true : false) { return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name); } type2 = type.Type; if (((int)type2 == 15 || (int)type2 == 29) ? true : false) { return GetSndnProviderForType(appContext2, type.GetEncapsulatedType()); } if ((int)type.Type == 20) { return GetSndnProviderForType(appContext2, type.GetArrayElementType()); } if (Il2CppTypeEnumExtensions.IsIl2CppPrimitive(type.Type)) { return (ITypeInfoProvider)(object)appContext2.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type]); } return (ITypeInfoProvider)(object)appContext2.ResolveContextForType(type.AsClass()); } } public abstract class WrappedTypeAnalysisContext : ReferencedTypeAnalysisContext { public virtual TypeAnalysisContext ElementType { get; } public override string DefaultNs => ElementType.Namespace; protected WrappedTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) { ElementType = elementType; base..ctor(referencedFrom); } public static WrappedTypeAnalysisContext Create(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0065: Unknown result type (might be due to invalid IL or missing references) Il2CppTypeEnum type = rawType.Type; if ((int)type <= 16) { if ((int)type == 15) { return new PointerTypeAnalysisContext(rawType, referencedFrom); } if ((int)type == 16) { return new ByRefTypeAnalysisContext(rawType, referencedFrom); } } else { if ((int)type == 20) { return new ArrayTypeAnalysisContext(rawType, referencedFrom); } if ((int)type == 29) { return new SzArrayTypeAnalysisContext(rawType, referencedFrom); } } throw new Exception($"Type {rawType.Type} is not a wrapper type"); } } } namespace Cpp2IL.Core.Logging { public class LibLogWriter : LogWriter { public override void Info(string message) { Logger.Info(message ?? "", "Library"); } public override void Warn(string message) { Logger.Warn(message ?? "", "Library"); } public override void Error(string message) { Logger.Error(message ?? "", "Library"); } public override void Verbose(string message) { Logger.Verbose(message ?? "", "Library"); } } public static class Logger { public delegate void LogEvent(string message, string source); public static event LogEvent VerboseLog; public static event LogEvent InfoLog; public static event LogEvent WarningLog; public static event LogEvent ErrorLog; public static void VerboseNewline(string message, string source = "Program") { Verbose(message + Environment.NewLine, source); } public static void Verbose(string message, string source = "Program") { Logger.VerboseLog(message, source); } public static void InfoNewline(string message, string source = "Program") { Info(message + Environment.NewLine, source); } public static void Info(string message, string source = "Program") { Logger.InfoLog(message, source); } public static void WarnNewline(string message, string source = "Program") { Warn(message + Environment.NewLine, source); } public static void Warn(string message, string source = "Program") { Logger.WarningLog(message, source); } public static void ErrorNewline(string message, string source = "Program") { Error(message + Environment.NewLine, source); } public static void Error(string message, string source = "Program") { Logger.ErrorLog(message, source); } static Logger() { Logger.VerboseLog = delegate { }; Logger.InfoLog = delegate { }; Logger.WarningLog = delegate { }; Logger.ErrorLog = delegate { }; } } public class SimpleConsoleLogger { private static bool LastNoNewline; public static bool ShowVerbose { private get; set; } public static void Initialize() { Logger.InfoLog += delegate(string message, string source) { Write("Info", source, message); }; Logger.WarningLog += delegate(string message, string source) { Write("Warn", source, message); }; Logger.ErrorLog += delegate(string message, string source) { Write("Fail", source, message); }; Logger.VerboseLog += delegate(string message, string source) { if (ShowVerbose) { Write("Verb", source, message); } }; } internal static void Write(string level, string source, string message) { if (!LastNoNewline) { WritePrelude(level, source); } LastNoNewline = !message.EndsWith("\n"); Console.Write(message); } private static void WritePrelude(string level, string source) { Console.Write($"[{level}] [{source}] "); } } } namespace Cpp2IL.Core.ISIL { public class InstructionSetIndependentInstruction : IsilOperandData { public InstructionSetIndependentOpCode OpCode; public InstructionSetIndependentOperand[] Operands; public ulong ActualAddress; public uint InstructionIndex; public IsilFlowControl FlowControl; public InstructionSetIndependentInstruction(InstructionSetIndependentOpCode opCode, ulong address, IsilFlowControl flowControl, params InstructionSetIndependentOperand[] operands) { OpCode = opCode; Operands = operands; ActualAddress = address; FlowControl = flowControl; OpCode.Validate(this); } public override string ToString() { return $"{InstructionIndex:000} {OpCode} {string.Join(", ", Operands)}"; } public void Invalidate(string reason) { OpCode = InstructionSetIndependentOpCode.Invalid; Operands = new InstructionSetIndependentOperand[1] { InstructionSetIndependentOperand.MakeImmediate(reason) }; FlowControl = IsilFlowControl.Continue; } } public class InstructionSetIndependentOpCode { public static readonly InstructionSetIndependentOpCode Move = new InstructionSetIndependentOpCode(IsilMnemonic.Move, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode LoadAddress = new InstructionSetIndependentOpCode(IsilMnemonic.LoadAddress, 2, InstructionSetIndependentOperand.OperandType.NotStack, InstructionSetIndependentOperand.OperandType.MemoryOrStack); public static readonly InstructionSetIndependentOpCode Call = new InstructionSetIndependentOpCode(IsilMnemonic.Call); public static readonly InstructionSetIndependentOpCode CallNoReturn = new InstructionSetIndependentOpCode(IsilMnemonic.CallNoReturn); public static readonly InstructionSetIndependentOpCode Exchange = new InstructionSetIndependentOpCode(IsilMnemonic.Exchange, 2, InstructionSetIndependentOperand.OperandType.NotStack, InstructionSetIndependentOperand.OperandType.NotStack); public static readonly InstructionSetIndependentOpCode Add = new InstructionSetIndependentOpCode(IsilMnemonic.Add, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Subtract = new InstructionSetIndependentOpCode(IsilMnemonic.Subtract, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Multiply = new InstructionSetIndependentOpCode(IsilMnemonic.Multiply, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Divide = new InstructionSetIndependentOpCode(IsilMnemonic.Divide, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode ShiftLeft = new InstructionSetIndependentOpCode(IsilMnemonic.ShiftLeft, 2, InstructionSetIndependentOperand.OperandType.NotStack, InstructionSetIndependentOperand.OperandType.NotStack); public static readonly InstructionSetIndependentOpCode ShiftRight = new InstructionSetIndependentOpCode(IsilMnemonic.ShiftRight, 2, InstructionSetIndependentOperand.OperandType.NotStack, InstructionSetIndependentOperand.OperandType.NotStack); public static readonly InstructionSetIndependentOpCode And = new InstructionSetIndependentOpCode(IsilMnemonic.And, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Or = new InstructionSetIndependentOpCode(IsilMnemonic.Or, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Xor = new InstructionSetIndependentOpCode(IsilMnemonic.Xor, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Not = new InstructionSetIndependentOpCode(IsilMnemonic.Not, 1, InstructionSetIndependentOperand.OperandType.NotStack); public static readonly InstructionSetIndependentOpCode Compare = new InstructionSetIndependentOpCode(IsilMnemonic.Compare, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode ShiftStack = new InstructionSetIndependentOpCode(IsilMnemonic.ShiftStack, 1, InstructionSetIndependentOperand.OperandType.Immediate); public static readonly InstructionSetIndependentOpCode Push = new InstructionSetIndependentOpCode(IsilMnemonic.Push, 2, InstructionSetIndependentOperand.OperandType.Register, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Pop = new InstructionSetIndependentOpCode(IsilMnemonic.Pop, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Register); public static readonly InstructionSetIndependentOpCode Return = new InstructionSetIndependentOpCode(IsilMnemonic.Return, 1, InstructionSetIndependentOperand.OperandType.NotStack); public static readonly InstructionSetIndependentOpCode Goto = new InstructionSetIndependentOpCode(IsilMnemonic.Goto, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfEqual = new InstructionSetIndependentOpCode(IsilMnemonic.JumpIfEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfNotEqual = new InstructionSetIndependentOpCode(IsilMnemonic.JumpIfNotEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfGreater = new InstructionSetIndependentOpCode(IsilMnemonic.JumpIfGreater, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfLess = new InstructionSetIndependentOpCode(IsilMnemonic.JumpIfLess, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfGreaterOrEqual = new InstructionSetIndependentOpCode(IsilMnemonic.JumpIfGreaterOrEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfLessOrEqual = new InstructionSetIndependentOpCode(IsilMnemonic.JumpIfLessOrEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode Interrupt = new InstructionSetIndependentOpCode(IsilMnemonic.Interrupt, 0); public static readonly InstructionSetIndependentOpCode Nop = new InstructionSetIndependentOpCode(IsilMnemonic.Nop, 0); public static readonly InstructionSetIndependentOpCode NotImplemented = new InstructionSetIndependentOpCode(IsilMnemonic.NotImplemented, 1, InstructionSetIndependentOperand.OperandType.Immediate); public static readonly InstructionSetIndependentOpCode Invalid = new InstructionSetIndependentOpCode(IsilMnemonic.Invalid, 1, InstructionSetIndependentOperand.OperandType.Immediate); public readonly IsilMnemonic Mnemonic; public readonly InstructionSetIndependentOperand.OperandType[] PermittedOperandTypes; public readonly int MaxOperands; public InstructionSetIndependentOpCode(IsilMnemonic mnemonic) { Mnemonic = mnemonic; MaxOperands = int.MaxValue; PermittedOperandTypes = Array.Empty(); } public InstructionSetIndependentOpCode(IsilMnemonic mnemonic, int maxOperands) { Mnemonic = mnemonic; MaxOperands = maxOperands; PermittedOperandTypes = InstructionSetIndependentOperand.OperandType.Any.Repeat(maxOperands).ToArray(); } private InstructionSetIndependentOpCode(IsilMnemonic mnemonic, int maxOperands, params InstructionSetIndependentOperand.OperandType[] permittedOperandTypes) { Mnemonic = mnemonic; PermittedOperandTypes = permittedOperandTypes; MaxOperands = maxOperands; } public void Validate(InstructionSetIndependentInstruction instruction) { InstructionSetIndependentOperand[] operands = instruction.Operands; if (operands.Length > MaxOperands) { instruction.Invalidate($"Too many operands! We have {operands.Length} but we only allow {MaxOperands}"); } else { if (PermittedOperandTypes.Length == 0) { return; } for (int i = 0; i < operands.Length; i++) { if ((operands[i].Type & PermittedOperandTypes[i]) == 0) { instruction.Invalidate($"Operand {operands[i]} at index {i} (0-based) is of type {operands[i].Type}, which is not permitted for this index of a {Mnemonic} instruction"); break; } } } } public override string ToString() { return Mnemonic.ToString(); } } public readonly struct InstructionSetIndependentOperand { [Flags] public enum OperandType { Immediate = 1, StackOffset = 2, Register = 4, Memory = 8, Instruction = 0x10, TypeMetadataUsage = 0x20, MethodReference = 0x40, MemoryOrStack = 0xA, NotStack = 0x7D, Any = 0x6F } public readonly OperandType Type; public readonly IsilOperandData Data; public static InstructionSetIndependentOperand MakeRegister(string registerName) { return new InstructionSetIndependentOperand(OperandType.Register, new IsilRegisterOperand(registerName)); } public static InstructionSetIndependentOperand MakeMemory(IsilMemoryOperand memory) { return new InstructionSetIndependentOperand(OperandType.Memory, memory); } public static InstructionSetIndependentOperand MakeImmediate(IConvertible value) { return new InstructionSetIndependentOperand(OperandType.Immediate, new IsilImmediateOperand(value)); } public static InstructionSetIndependentOperand MakeStack(int value) { return new InstructionSetIndependentOperand(OperandType.StackOffset, new IsilStackOperand(value)); } public static InstructionSetIndependentOperand MakeInstruction(InstructionSetIndependentInstruction instruction) { return new InstructionSetIndependentOperand(OperandType.Instruction, instruction); } public static InstructionSetIndependentOperand MakeVectorElement(string registerName, IsilVectorRegisterElementOperand.VectorElementWidth width, int index) { return new InstructionSetIndependentOperand(OperandType.Register, new IsilVectorRegisterElementOperand(registerName, width, index)); } public static InstructionSetIndependentOperand MakeTypeMetadataUsage(TypeAnalysisContext value) { return new InstructionSetIndependentOperand(OperandType.TypeMetadataUsage, new IsilTypeMetadataUsageOperand(value)); } public static InstructionSetIndependentOperand MakeMethodReference(MethodAnalysisContext value) { return new InstructionSetIndependentOperand(OperandType.MethodReference, new IsilMethodOperand(value)); } private InstructionSetIndependentOperand(OperandType type, IsilOperandData data) { Type = type; Data = data; } public override string? ToString() { if (Data is InstructionSetIndependentInstruction instructionSetIndependentInstruction) { return "{" + instructionSetIndependentInstruction.InstructionIndex + "}"; } return Data.ToString(); } } public class IsilBuilder { public List BackingStatementList; public Dictionary> InstructionAddressMap; private readonly List<(InstructionSetIndependentInstruction, ulong)> _jumpsToFix; public IsilBuilder() { BackingStatementList = new List(); InstructionAddressMap = new Dictionary>(); _jumpsToFix = new List<(InstructionSetIndependentInstruction, ulong)>(); } public IsilBuilder(List backingStatementList) { BackingStatementList = backingStatementList; InstructionAddressMap = new Dictionary>(); _jumpsToFix = new List<(InstructionSetIndependentInstruction, ulong)>(); } private void AddInstruction(InstructionSetIndependentInstruction instruction) { if (InstructionAddressMap.TryGetValue(instruction.ActualAddress, out List value)) { value.Add(instruction); } else { InstructionAddressMap[instruction.ActualAddress] = new List(1) { instruction }; } BackingStatementList.Add(instruction); instruction.InstructionIndex = (uint)BackingStatementList.Count; } public void FixJumps() { foreach (var item in _jumpsToFix) { if (InstructionAddressMap.TryGetValue(item.Item2, out List value)) { InstructionSetIndependentInstruction instructionSetIndependentInstruction = value.First(); if (instructionSetIndependentInstruction.Equals(item.Item1)) { item.Item1.Invalidate("Invalid jump target for instruction: Instruction can't jump to itself"); continue; } item.Item1.Operands = new InstructionSetIndependentOperand[1] { InstructionSetIndependentOperand.MakeInstruction(instructionSetIndependentInstruction) }; } else { item.Item1.Invalidate("Jump target not found in method."); } } } public void Move(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand src) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Move, instructionAddress, IsilFlowControl.Continue, dest, src)); } public void LoadAddress(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand src) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.LoadAddress, instructionAddress, IsilFlowControl.Continue, dest, src)); } public void ShiftStack(ulong instructionAddress, int amount) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.ShiftStack, instructionAddress, IsilFlowControl.Continue, InstructionSetIndependentOperand.MakeImmediate(amount))); } public void Push(ulong instructionAddress, InstructionSetIndependentOperand stackPointerRegister, InstructionSetIndependentOperand operand) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Push, instructionAddress, IsilFlowControl.Continue, stackPointerRegister, operand)); } public void Pop(ulong instructionAddress, InstructionSetIndependentOperand stackPointerRegister, InstructionSetIndependentOperand operand) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Pop, instructionAddress, IsilFlowControl.Continue, operand, stackPointerRegister)); } public void Exchange(ulong instructionAddress, InstructionSetIndependentOperand place1, InstructionSetIndependentOperand place2) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Exchange, instructionAddress, IsilFlowControl.Continue, place1, place2)); } public void Subtract(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Subtract, instructionAddress, IsilFlowControl.Continue, dest, left, right)); } public void Add(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Add, instructionAddress, IsilFlowControl.Continue, dest, left, right)); } public void Xor(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Xor, instructionAddress, IsilFlowControl.Continue, dest, left, right)); } public void ShiftLeft(ulong instructionAddress, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.ShiftLeft, instructionAddress, IsilFlowControl.Continue, left, right)); } public void ShiftRight(ulong instructionAddress, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.ShiftRight, instructionAddress, IsilFlowControl.Continue, left, right)); } public void And(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.And, instructionAddress, IsilFlowControl.Continue, dest, left, right)); } public void Or(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Or, instructionAddress, IsilFlowControl.Continue, dest, left, right)); } public void Not(ulong instructionAddress, InstructionSetIndependentOperand src) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Not, instructionAddress, IsilFlowControl.Continue, src)); } public void Multiply(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand src1, InstructionSetIndependentOperand src2) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Multiply, instructionAddress, IsilFlowControl.Continue, dest, src1, src2)); } public void Call(ulong instructionAddress, ulong dest, params InstructionSetIndependentOperand[] args) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Call, instructionAddress, IsilFlowControl.MethodCall, PrepareCallOperands(dest, args))); } public void CallRegister(ulong instructionAddress, InstructionSetIndependentOperand dest, bool noReturn = false) { AddInstruction(new InstructionSetIndependentInstruction(noReturn ? InstructionSetIndependentOpCode.CallNoReturn : InstructionSetIndependentOpCode.Call, instructionAddress, IsilFlowControl.MethodCall, dest)); } public void Return(ulong instructionAddress, InstructionSetIndependentOperand? returnValue = null) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Return, instructionAddress, IsilFlowControl.MethodReturn, (!returnValue.HasValue) ? Array.Empty() : new InstructionSetIndependentOperand[1] { returnValue.Value })); } public void Goto(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.Goto, IsilFlowControl.UnconditionalJump); } public void JumpIfEqual(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfEqual, IsilFlowControl.ConditionalJump); } public void JumpIfNotEqual(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfNotEqual, IsilFlowControl.ConditionalJump); } public void JumpIfGreater(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfGreater, IsilFlowControl.ConditionalJump); } public void JumpIfLess(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfLess, IsilFlowControl.ConditionalJump); } public void JumpIfGreaterOrEqual(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfGreaterOrEqual, IsilFlowControl.ConditionalJump); } public void JumpIfLessOrEqual(ulong instructionAddress, ulong target) { CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfLessOrEqual, IsilFlowControl.ConditionalJump); } private void CreateJump(ulong instructionAddress, ulong target, InstructionSetIndependentOpCode independentOpCode, IsilFlowControl flowControl) { InstructionSetIndependentInstruction instructionSetIndependentInstruction = new InstructionSetIndependentInstruction(independentOpCode, instructionAddress, flowControl); AddInstruction(instructionSetIndependentInstruction); _jumpsToFix.Add((instructionSetIndependentInstruction, target)); } public void Compare(ulong instructionAddress, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Compare, instructionAddress, IsilFlowControl.Continue, left, right)); } public void NotImplemented(ulong instructionAddress, string text) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.NotImplemented, instructionAddress, IsilFlowControl.Continue, InstructionSetIndependentOperand.MakeImmediate(text))); } public void Invalid(ulong instructionAddress, string text) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Invalid, instructionAddress, IsilFlowControl.Continue, InstructionSetIndependentOperand.MakeImmediate(text))); } public void Interrupt(ulong instructionAddress) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Interrupt, instructionAddress, IsilFlowControl.Interrupt)); } public void Nop(ulong instructionAddress) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Nop, instructionAddress, IsilFlowControl.Continue)); } private InstructionSetIndependentOperand[] PrepareCallOperands(ulong dest, InstructionSetIndependentOperand[] args) { InstructionSetIndependentOperand[] array = new InstructionSetIndependentOperand[args.Length + 1]; array[0] = InstructionSetIndependentOperand.MakeImmediate(dest); Array.Copy(args, 0, array, 1, args.Length); return array; } } public class IsilCondition { public InstructionSetIndependentOperand Left; public InstructionSetIndependentOperand Right; public InstructionSetIndependentOpCode OpCode; public bool IsAnd; public IsilCondition(InstructionSetIndependentOperand left, InstructionSetIndependentOperand right, InstructionSetIndependentOpCode opCode) { Left = left; Right = right; OpCode = opCode; base..ctor(); } public IsilCondition MarkAsAnd() { IsAnd = true; return this; } public override string ToString() { return $"{OpCode} {Left},{Right}"; } } public enum IsilFlowControl { UnconditionalJump, ConditionalJump, IndexedJump, MethodCall, MethodReturn, Interrupt, Continue } public readonly struct IsilImmediateOperand : IsilOperandData { public readonly IConvertible Value; public IsilImmediateOperand(IConvertible value) { Value = value; } public override string ToString() { if (Value is string) { return "\"" + Value?.ToString() + "\""; } try { IConvertible value = Value; if ((!(value is ulong) || (ulong)(object)value < long.MaxValue) && Convert.ToInt64(Value) > 4096) { return $"0x{Value:X}"; } } catch { } return Value.ToString(CultureInfo.InvariantCulture); } } public struct IsilInstructionStatement : IsilStatement { public readonly InstructionSetIndependentInstruction Instruction; public IsilInstructionStatement(InstructionSetIndependentInstruction instruction) { Instruction = instruction; } public override string ToString() { return Instruction.ToString(); } } public readonly struct IsilMemoryOperand : IsilOperandData { public readonly InstructionSetIndependentOperand? Base; public readonly InstructionSetIndependentOperand? Index; public readonly long Addend; public readonly int Scale; public IsilMemoryOperand(long addend) { Base = null; Index = null; Addend = 0L; Scale = 0; Addend = addend; } public IsilMemoryOperand(InstructionSetIndependentOperand @base) { Base = null; Index = null; Addend = 0L; Scale = 0; Base = @base; } public IsilMemoryOperand(InstructionSetIndependentOperand @base, long addend) { Base = null; Index = null; Addend = 0L; Scale = 0; Base = @base; Addend = addend; } public IsilMemoryOperand(InstructionSetIndependentOperand @base, InstructionSetIndependentOperand index, int scale) { Base = null; Index = null; Addend = 0L; Scale = 0; Base = @base; Index = index; Scale = scale; } public IsilMemoryOperand(InstructionSetIndependentOperand @base, InstructionSetIndependentOperand index, long addend, int scale) { Base = null; Index = null; Addend = 0L; Scale = 0; Base = @base; Index = index; Addend = addend; Scale = scale; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder("["); bool flag = false; if (Base.HasValue) { stringBuilder.Append(Base); flag = true; } if (Addend != 0L) { if (flag) { stringBuilder.Append((Addend > 0) ? '+' : '-'); } if (Addend > 65536) { stringBuilder.AppendFormat("0x{0:X}", Math.Abs(Addend)); } else { stringBuilder.Append(Math.Abs(Addend)); } flag = true; } if (Index.HasValue) { if (flag) { stringBuilder.Append("+"); } stringBuilder.Append(Index); if (Scale > 1) { stringBuilder.Append("*"); stringBuilder.Append(Scale); } } stringBuilder.Append(']'); return stringBuilder.ToString(); } } public readonly struct IsilMethodOperand : IsilOperandData { public MethodAnalysisContext Method { get; } public IsilMethodOperand(MethodAnalysisContext method) { Method = method; } public override string ToString() { return Method.DeclaringType?.Name + "." + Method.Name; } } public enum IsilMnemonic { Move, LoadAddress, Call, CallNoReturn, Exchange, Add, Subtract, Multiply, Divide, ShiftLeft, ShiftRight, And, Or, Xor, Not, Compare, ShiftStack, Push, Pop, Return, Goto, JumpIfEqual, JumpIfNotEqual, JumpIfGreater, JumpIfGreaterOrEqual, JumpIfLess, JumpIfLessOrEqual, SignExtend, Interrupt, Nop, NotImplemented, Invalid } public interface IsilOperandData { } public readonly struct IsilRegisterOperand : IsilOperandData { public readonly string RegisterName; public IsilRegisterOperand(string registerName) { RegisterName = registerName; } public override string ToString() { return RegisterName; } } public readonly struct IsilStackOperand : IsilOperandData { public readonly int Offset; public IsilStackOperand(int offset) { Offset = offset; } public override string ToString() { return $"stack:0x{Offset:X}"; } } public interface IsilStatement { } public readonly struct IsilTypeMetadataUsageOperand : IsilOperandData { public readonly TypeAnalysisContext TypeAnalysisContext; public IsilTypeMetadataUsageOperand(TypeAnalysisContext typeAnalysisContext) { TypeAnalysisContext = typeAnalysisContext; } public override string ToString() { return "typeof(" + TypeAnalysisContext.FullName + ")"; } } public readonly struct IsilVectorRegisterElementOperand : IsilOperandData { public enum VectorElementWidth { B, H, S, D } public readonly string RegisterName; public readonly VectorElementWidth Width; public readonly int Index; public IsilVectorRegisterElementOperand(string registerName, VectorElementWidth width, int index) { RegisterName = registerName; Width = width; Index = index; } public override string ToString() { return $"{RegisterName}.{Width}[{Index}]"; } } } namespace Cpp2IL.Core.InstructionSets { public class Arm64InstructionSet : Cpp2IlInstructionSet { public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { int num = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer) - 1; int num2 = (int)context.UnderlyingPointer; int length = num - num2; if (num > 0) { return LibCpp2IlMain.Binary.GetRawBinaryContent().AsMemory(num2, length); } return Arm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer).SelectMany((Arm64Instruction i) => ((Instruction)(object)i).Bytes).ToArray(); } public override List GetIsilFromMethod(MethodAnalysisContext context) { return new List(); } public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() { return new Arm64KeyFunctionAddresses(); } public override string PrintAssembly(MethodAnalysisContext context) { StringBuilder stringBuilder = new StringBuilder(); List arm64MethodBodyAtVirtualAddress = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); bool flag = true; foreach (Arm64Instruction item in arm64MethodBodyAtVirtualAddress) { if (!flag) { stringBuilder.AppendLine(); } flag = false; stringBuilder.Append("0x").Append(((Instruction)(object)item).Address.ToString("X")).Append(" ") .Append(((Instruction)(object)item).Mnemonic) .Append(" ") .Append(((Instruction)(object)item).Operand); } return stringBuilder.ToString(); } } public class ArmV7InstructionSet : Cpp2IlInstructionSet { public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { byte[] array = ArmV7Utils.TryGetMethodBodyBytesFast(context.UnderlyingPointer, context is AttributeGeneratorMethodAnalysisContext); if (array != null) { return array; } return ArmV7Utils.GetArmV7MethodBodyAtVirtualAddress(context.UnderlyingPointer).SelectMany((ArmInstruction i) => ((Instruction)(object)i).Bytes).ToArray(); } public override List GetIsilFromMethod(MethodAnalysisContext context) { return new List(); } public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() { return new Arm64KeyFunctionAddresses(); } public override string PrintAssembly(MethodAnalysisContext context) { StringBuilder stringBuilder = new StringBuilder(); List armV7MethodBodyAtVirtualAddress = ArmV7Utils.GetArmV7MethodBodyAtVirtualAddress(context.UnderlyingPointer); bool flag = true; foreach (ArmInstruction item in armV7MethodBodyAtVirtualAddress) { if (!flag) { stringBuilder.AppendLine(); } flag = false; stringBuilder.Append("0x").Append(((Instruction)(object)item).Address.ToString("X")).Append(" ") .Append(((Instruction)(object)item).Mnemonic) .Append(" ") .Append(((Instruction)(object)item).Operand); } return stringBuilder.ToString(); } } public class NewArmV8InstructionSet : Cpp2IlInstructionSet { public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!(context is ConcreteGenericMethodAnalysisContext)) { int num = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer); int num2 = (int)context.UnderlyingPointer; int length = num - num2; if (num > 0) { return LibCpp2IlMain.Binary.GetRawBinaryContent().AsMemory(num2, length); } } Arm64Instruction val = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer).LastValid(); ulong num3 = ((Arm64Instruction)(ref val)).Address + 4; int num4 = (int)context.AppContext.Binary.MapVirtualAddressToRaw(context.UnderlyingPointer, true); int num5 = (int)context.AppContext.Binary.MapVirtualAddressToRaw(num3, true); if (num4 < 0 || num5 < 0 || num4 >= context.AppContext.Binary.RawLength || num5 >= context.AppContext.Binary.RawLength) { throw new Exception($"Failed to map virtual address 0x{context.UnderlyingPointer:X} to raw address for method {context.DeclaringType?.FullName}/{context.Name} - start: 0x{num4:X}, end: 0x{num5:X} are out of bounds for length {context.AppContext.Binary.RawLength}."); } return context.AppContext.Binary.GetRawBinaryContent().AsMemory(num4, num5 - num4); } public override List GetIsilFromMethod(MethodAnalysisContext context) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) List arm64MethodBodyAtVirtualAddress = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); IsilBuilder isilBuilder = new IsilBuilder(); foreach (Arm64Instruction item in arm64MethodBodyAtVirtualAddress) { ConvertInstructionStatement(item, isilBuilder, context); } isilBuilder.FixJumps(); return isilBuilder.BackingStatementList; } private void ConvertInstructionStatement(Arm64Instruction instruction, IsilBuilder builder, MethodAnalysisContext context) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Invalid comparison between Unknown and I4 //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected I4, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Invalid comparison between Unknown and I4 //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected I4, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Invalid comparison between Unknown and I4 //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected I4, but got Unknown //IL_07e3: Unknown result type (might be due to invalid IL or missing references) //IL_07eb: Unknown result type (might be due to invalid IL or missing references) //IL_07f3: Unknown result type (might be due to invalid IL or missing references) //IL_0894: Unknown result type (might be due to invalid IL or missing references) //IL_06bb: Unknown result type (might be due to invalid IL or missing references) //IL_06fb: Unknown result type (might be due to invalid IL or missing references) //IL_0705: Invalid comparison between Unknown and I4 //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Invalid comparison between Unknown and I4 //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected I4, but got Unknown //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0797: Unknown result type (might be due to invalid IL or missing references) //IL_079f: Unknown result type (might be due to invalid IL or missing references) //IL_07a7: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Invalid comparison between Unknown and I4 //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Invalid comparison between Unknown and I4 //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Invalid comparison between Unknown and I4 //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Invalid comparison between Unknown and I4 //IL_07bd: Unknown result type (might be due to invalid IL or missing references) //IL_07c5: Unknown result type (might be due to invalid IL or missing references) //IL_07cd: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0809: Unknown result type (might be due to invalid IL or missing references) //IL_0811: Unknown result type (might be due to invalid IL or missing references) //IL_0819: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected I4, but got Unknown //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_0728: Unknown result type (might be due to invalid IL or missing references) //IL_073c: Unknown result type (might be due to invalid IL or missing references) //IL_0753: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_082f: Unknown result type (might be due to invalid IL or missing references) //IL_0837: Unknown result type (might be due to invalid IL or missing references) //IL_083f: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Invalid comparison between Unknown and I4 //IL_0855: Unknown result type (might be due to invalid IL or missing references) //IL_085d: Unknown result type (might be due to invalid IL or missing references) //IL_0865: Unknown result type (might be due to invalid IL or missing references) //IL_061a: Unknown result type (might be due to invalid IL or missing references) //IL_0642: Unknown result type (might be due to invalid IL or missing references) //IL_065b: Unknown result type (might be due to invalid IL or missing references) //IL_0662: Invalid comparison between Unknown and I4 //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_048e: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Invalid comparison between Unknown and I4 //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Invalid comparison between Unknown and I4 //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_04d4: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Invalid comparison between Unknown and I4 //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Invalid comparison between Unknown and I4 //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Invalid comparison between Unknown and I4 //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Invalid comparison between Unknown and I4 //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_04ef: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) Arm64Mnemonic mnemonic = ((Arm64Instruction)(ref instruction)).Mnemonic; if ((int)mnemonic <= 94) { if ((int)mnemonic <= 48) { if ((int)mnemonic <= 22) { switch (mnemonic - 2) { case 6: builder.Move(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; case 10: { ulong branchTarget = ((Arm64Instruction)(ref instruction)).BranchTarget; if (branchTarget < context.UnderlyingPointer || branchTarget > (ulong)((long)context.UnderlyingPointer + (long)context.RawBytes.Length)) { builder.Call(((Arm64Instruction)(ref instruction)).Address, ((Arm64Instruction)(ref instruction)).BranchTarget, GetArgumentOperandsForCall(context, ((Arm64Instruction)(ref instruction)).BranchTarget).ToArray()); builder.Return(((Arm64Instruction)(ref instruction)).Address, GetReturnRegisterForContext(context)); } return; } case 0: case 4: goto IL_07b4; case 7: case 8: builder.And(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; case 1: case 2: case 3: case 5: case 9: goto IL_0872; } switch (mnemonic - 17) { case 0: builder.Call(((Arm64Instruction)(ref instruction)).Address, ((Arm64Instruction)(ref instruction)).BranchTarget, GetArgumentOperandsForCall(context, ((Arm64Instruction)(ref instruction)).BranchTarget).ToArray()); return; case 2: builder.CallRegister(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), noReturn: true); return; case 4: case 5: { ulong target = ((Arm64Instruction)(ref instruction)).Address + (ulong)((Arm64Instruction)(ref instruction)).Op1Imm; builder.Compare(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(0)); if ((int)((Arm64Instruction)(ref instruction)).Mnemonic == 22) { builder.JumpIfEqual(((Arm64Instruction)(ref instruction)).Address, target); } else { builder.JumpIfNotEqual(((Arm64Instruction)(ref instruction)).Address, target); } return; } } } else if ((int)mnemonic != 28 && (int)mnemonic == 48) { builder.Xor(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; } } else if ((int)mnemonic <= 75) { if ((int)mnemonic == 52) { goto IL_07b4; } if ((int)mnemonic == 75) { goto IL_01a5; } } else { if ((int)mnemonic == 76) { goto IL_078e; } if ((int)mnemonic == 94) { goto IL_07da; } } goto IL_0872; } if ((int)mnemonic <= 128) { if ((int)mnemonic <= 103) { if ((int)mnemonic != 100) { if (mnemonic - 102 <= 1) { goto IL_01a5; } } else if ((int)((Arm64Instruction)(ref instruction)).Op2Kind == 6) { Arm64Register op0Reg = ((Arm64Instruction)(ref instruction)).Op0Reg; int num; if ((int)op0Reg >= 65) { if ((int)op0Reg <= 160) { num = (((int)op0Reg <= 96) ? 16 : (((int)op0Reg > 128) ? 4 : 8)); } else { if ((int)op0Reg > 192) { goto IL_04ba; } num = 2; } } else { if ((int)op0Reg < 1) { goto IL_04ba; } num = (((int)op0Reg > 32) ? 8 : 4); } int num2 = num; InstructionSetIndependentOperand dest = ConvertOperand(instruction, 0); InstructionSetIndependentOperand dest2 = ConvertOperand(instruction, 1); InstructionSetIndependentOperand src = ConvertOperand(instruction, 2); IsilMemoryOperand? isilMemoryOperand = src.Data as IsilMemoryOperand?; IsilMemoryOperand memory = new IsilMemoryOperand(isilMemoryOperand.Value.Base.Value, isilMemoryOperand.Value.Addend + num2); builder.Move(((Arm64Instruction)(ref instruction)).Address, dest, src); builder.Move(((Arm64Instruction)(ref instruction)).Address, dest2, InstructionSetIndependentOperand.MakeMemory(memory)); return; } goto IL_0872; } switch (mnemonic - 118) { default: if ((int)mnemonic != 128) { goto IL_0872; } builder.Or(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; case 0: case 4: break; case 3: { InstructionSetIndependentOperand instructionSetIndependentOperand = InstructionSetIndependentOperand.MakeRegister("TEMP"); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand, ConvertOperand(instruction, 1)); builder.Not(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand); builder.Move(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), instructionSetIndependentOperand); return; } case 6: goto IL_078e; case 1: case 2: case 5: goto IL_0872; } } else { if ((int)mnemonic <= 196) { if ((int)mnemonic != 139) { switch (mnemonic - 189) { case 1: case 2: case 4: builder.Move(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 1), ConvertOperand(instruction, 0)); return; case 0: break; case 7: goto IL_07da; default: goto IL_0872; } InstructionSetIndependentOperand instructionSetIndependentOperand2 = ConvertOperand(instruction, 2); IsilOperandData data = instructionSetIndependentOperand2.Data; if (data is IsilRegisterOperand && ((IsilRegisterOperand)(object)data).RegisterName == "X31") { builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, ConvertOperand(instruction, 0)); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, ConvertOperand(instruction, 1)); } else if (instructionSetIndependentOperand2.Data is IsilMemoryOperand isilMemoryOperand2) { InstructionSetIndependentOperand src2 = ConvertOperand(instruction, 0); long num3 = ((((IsilRegisterOperand)src2.Data).RegisterName[0] == 'W') ? 4 : 8); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, src2); IsilMemoryOperand memory2 = new IsilMemoryOperand(isilMemoryOperand2.Base.Value, isilMemoryOperand2.Addend + num3); instructionSetIndependentOperand2 = InstructionSetIndependentOperand.MakeMemory(memory2); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, ConvertOperand(instruction, 1)); } else { InstructionSetIndependentOperand src3 = ConvertOperand(instruction, 0); long num4 = ((((IsilRegisterOperand)src3.Data).RegisterName[0] == 'W') ? 4 : 8); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, src3); builder.Add(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, instructionSetIndependentOperand2, InstructionSetIndependentOperand.MakeImmediate(num4)); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand2, ConvertOperand(instruction, 1)); } } else { builder.Return(((Arm64Instruction)(ref instruction)).Address, GetReturnRegisterForContext(context)); } return; } switch (mnemonic - 201) { default: { if ((int)mnemonic != 217) { goto IL_0872; } InstructionSetIndependentOperand instructionSetIndependentOperand3 = ConvertOperand(instruction, 0); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand3, ConvertOperand(instruction, 1)); builder.ShiftRight(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand3, ConvertOperand(instruction, 2)); int num5 = (int)((Arm64Instruction)(ref instruction)).Op3Imm; builder.And(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand3, instructionSetIndependentOperand3, InstructionSetIndependentOperand.MakeImmediate((1 << num5) - 1)); return; } case 4: break; case 5: case 6: goto IL_0684; case 0: goto IL_07da; case 1: case 2: case 3: goto IL_0872; } } goto IL_01a5; IL_0872: builder.NotImplemented(((Arm64Instruction)(ref instruction)).Address, $"Instruction {((Arm64Instruction)(ref instruction)).Mnemonic} not yet implemented."); return; IL_07da: builder.Subtract(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; IL_078e: builder.Multiply(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; IL_01a5: if (((Arm64Instruction)(ref instruction)).MemIsPreIndexed && ConvertOperand(instruction, 1).Data is IsilMemoryOperand isilMemoryOperand3) { InstructionSetIndependentOperand value = isilMemoryOperand3.Base.Value; builder.Add(((Arm64Instruction)(ref instruction)).Address, value, value, InstructionSetIndependentOperand.MakeImmediate(isilMemoryOperand3.Addend)); builder.Move(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(InstructionSetIndependentOperand.MakeRegister(value.ToString().ToUpperInvariant()), 0L))); } else { builder.Move(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); } return; IL_04ba: throw new Exception($"Unknown register size for LDP: {((Arm64Instruction)(ref instruction)).Op0Reg}"); IL_07b4: builder.Add(((Arm64Instruction)(ref instruction)).Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; IL_0684: ulong target2 = ((Arm64Instruction)(ref instruction)).Address + (ulong)((Arm64Instruction)(ref instruction)).Op2Imm; InstructionSetIndependentOperand right = InstructionSetIndependentOperand.MakeImmediate(1 << (int)((Arm64Instruction)(ref instruction)).Op1Imm); InstructionSetIndependentOperand instructionSetIndependentOperand4 = InstructionSetIndependentOperand.MakeRegister("TEMP"); InstructionSetIndependentOperand src4 = ConvertOperand(instruction, 0); builder.Move(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand4, src4); builder.And(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand4, instructionSetIndependentOperand4, right); builder.Compare(((Arm64Instruction)(ref instruction)).Address, instructionSetIndependentOperand4, right); if ((int)((Arm64Instruction)(ref instruction)).Mnemonic == 206) { builder.JumpIfEqual(((Arm64Instruction)(ref instruction)).Address, target2); } else { builder.JumpIfNotEqual(((Arm64Instruction)(ref instruction)).Address, target2); } } private InstructionSetIndependentOperand ConvertOperand(Arm64Instruction instruction, int operand) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Invalid comparison between Unknown and I4 //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Invalid comparison between Unknown and I4 //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Invalid comparison between Unknown and I4 //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Invalid comparison between Unknown and I4 //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Invalid comparison between Unknown and I4 //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Expected I4, but got Unknown //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) Arm64OperandKind val = (Arm64OperandKind)(operand switch { 0 => ((Arm64Instruction)(ref instruction)).Op0Kind, 1 => ((Arm64Instruction)(ref instruction)).Op1Kind, 2 => ((Arm64Instruction)(ref instruction)).Op2Kind, 3 => ((Arm64Instruction)(ref instruction)).Op3Kind, _ => throw new ArgumentOutOfRangeException("operand", $"Operand must be between 0 and 3, inclusive. Got {operand}"), }); if (val - 3 <= 1) { long num = operand switch { 0 => ((Arm64Instruction)(ref instruction)).Op0Imm, 1 => ((Arm64Instruction)(ref instruction)).Op1Imm, 2 => ((Arm64Instruction)(ref instruction)).Op2Imm, 3 => ((Arm64Instruction)(ref instruction)).Op3Imm, _ => throw new ArgumentOutOfRangeException("operand", $"Operand must be between 0 and 3, inclusive. Got {operand}"), }; if ((int)val == 4) { num += (long)(((Arm64Instruction)(ref instruction)).Address + 4); } return InstructionSetIndependentOperand.MakeImmediate(num); } if ((int)val == 5) { return InstructionSetIndependentOperand.MakeImmediate(operand switch { 0 => ((Arm64Instruction)(ref instruction)).Op0FpImm, 1 => ((Arm64Instruction)(ref instruction)).Op1FpImm, 2 => ((Arm64Instruction)(ref instruction)).Op2FpImm, 3 => ((Arm64Instruction)(ref instruction)).Op3FpImm, _ => throw new ArgumentOutOfRangeException("operand", $"Operand must be between 0 and 3, inclusive. Got {operand}"), }); } if ((int)val == 1) { Arm64Register val2 = (Arm64Register)(operand switch { 0 => ((Arm64Instruction)(ref instruction)).Op0Reg, 1 => ((Arm64Instruction)(ref instruction)).Op1Reg, 2 => ((Arm64Instruction)(ref instruction)).Op2Reg, 3 => ((Arm64Instruction)(ref instruction)).Op3Reg, _ => throw new ArgumentOutOfRangeException("operand", $"Operand must be between 0 and 3, inclusive. Got {operand}"), }); return InstructionSetIndependentOperand.MakeRegister(((object)(Arm64Register)(ref val2)).ToString().ToUpperInvariant()); } if ((int)val == 6) { Arm64Register memBase = ((Arm64Instruction)(ref instruction)).MemBase; long memOffset = ((Arm64Instruction)(ref instruction)).MemOffset; _ = ((Arm64Instruction)(ref instruction)).MemIsPreIndexed; if ((int)memBase == 0) { return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(memOffset)); } return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(InstructionSetIndependentOperand.MakeRegister(((object)(Arm64Register)(ref memBase)).ToString().ToUpperInvariant()), memOffset)); } if ((int)val == 2) { Arm64Register val3 = (Arm64Register)(operand switch { 0 => ((Arm64Instruction)(ref instruction)).Op0Reg, 1 => ((Arm64Instruction)(ref instruction)).Op1Reg, 2 => ((Arm64Instruction)(ref instruction)).Op2Reg, 3 => ((Arm64Instruction)(ref instruction)).Op3Reg, _ => throw new ArgumentOutOfRangeException("operand", $"Operand must be between 0 and 3, inclusive. Got {operand}"), }); Arm64VectorElement val4 = (Arm64VectorElement)(operand switch { 0 => ((Arm64Instruction)(ref instruction)).Op0VectorElement, 1 => ((Arm64Instruction)(ref instruction)).Op1VectorElement, 2 => ((Arm64Instruction)(ref instruction)).Op2VectorElement, 3 => ((Arm64Instruction)(ref instruction)).Op3VectorElement, _ => throw new ArgumentOutOfRangeException("operand", $"Operand must be between 0 and 3, inclusive. Got {operand}"), }); Arm64VectorElementWidth width = val4.Width; IsilVectorRegisterElementOperand.VectorElementWidth width2 = (int)width switch { 0 => IsilVectorRegisterElementOperand.VectorElementWidth.B, 1 => IsilVectorRegisterElementOperand.VectorElementWidth.H, 2 => IsilVectorRegisterElementOperand.VectorElementWidth.S, 3 => IsilVectorRegisterElementOperand.VectorElementWidth.D, _ => throw new ArgumentOutOfRangeException("Width", $"Unknown vector element width {val4.Width}"), }; return InstructionSetIndependentOperand.MakeVectorElement(((object)(Arm64Register)(ref val3)).ToString().ToUpperInvariant(), width2, val4.Index); } return InstructionSetIndependentOperand.MakeImmediate($""); } public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() { return new NewArm64KeyFunctionAddresses(); } public override string PrintAssembly(MethodAnalysisContext context) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (context.RawBytes.Span.Length > 0) { return string.Join("\n", Disassembler.Disassemble((ReadOnlySpan)context.RawBytes.Span, context.UnderlyingPointer, (Options?)new Options(true, true, false)).ToList()); } return ""; } private InstructionSetIndependentOperand? GetReturnRegisterForContext(MethodAnalysisContext context) { TypeAnalysisContext returnTypeContext = context.ReturnTypeContext; if (returnTypeContext.Namespace == "System") { return returnTypeContext.Name switch { "Void" => null, "Double" => InstructionSetIndependentOperand.MakeRegister("V0"), "Single" => InstructionSetIndependentOperand.MakeRegister("V0"), _ => InstructionSetIndependentOperand.MakeRegister("X0"), }; } return InstructionSetIndependentOperand.MakeRegister("X0"); } private List GetArgumentOperandsForCall(MethodAnalysisContext contextBeingAnalyzed, ulong callAddr) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (!contextBeingAnalyzed.AppContext.MethodsByAddress.TryGetValue(callAddr, out List value)) { return new List(); } MethodAnalysisContext methodAnalysisContext = value.First(); int num = 0; int num2 = 0; List list = new List(); if (!methodAnalysisContext.IsStatic) { list.Add(InstructionSetIndependentOperand.MakeRegister("X0")); num2++; } foreach (ParameterAnalysisContext parameter in methodAnalysisContext.Parameters) { TypeAnalysisContext parameterTypeContext = parameter.ParameterTypeContext; Arm64Register val; if (parameterTypeContext.Namespace == "System") { string name = parameterTypeContext.Name; if (name == "Single" || name == "Double") { val = (Arm64Register)(65 + num++); list.Add(InstructionSetIndependentOperand.MakeRegister(((object)(Arm64Register)(ref val)).ToString().ToUpperInvariant())); } else { val = (Arm64Register)(33 + num2++); list.Add(InstructionSetIndependentOperand.MakeRegister(((object)(Arm64Register)(ref val)).ToString().ToUpperInvariant())); } } else { val = (Arm64Register)(33 + num2++); list.Add(InstructionSetIndependentOperand.MakeRegister(((object)(Arm64Register)(ref val)).ToString().ToUpperInvariant())); } } return list; } } public class WasmInstructionSet : Cpp2IlInstructionSet { public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { Il2CppMethodDefinition definition = context.Definition; if (definition != null) { WasmFunctionDefinition val = WasmUtils.TryGetWasmDefinition(definition); if (val == null) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(103, 3); defaultInterpolatedStringHandler.AppendLiteral("Could not find WASM definition for method "); Il2CppTypeDefinition declaringType = definition.DeclaringType; defaultInterpolatedStringHandler.AppendFormatted((declaringType != null) ? declaringType.FullName : null); defaultInterpolatedStringHandler.AppendLiteral("::"); defaultInterpolatedStringHandler.AppendFormatted(definition.Name); defaultInterpolatedStringHandler.AppendLiteral(", probably incorrect signature calculation (signature was "); defaultInterpolatedStringHandler.AppendFormatted(WasmUtils.BuildSignature(definition)); defaultInterpolatedStringHandler.AppendLiteral(")"); Logger.WarnNewline(defaultInterpolatedStringHandler.ToStringAndClear(), "WasmInstructionSet"); return Array.Empty(); } if (val.AssociatedFunctionBody == null) { throw new Exception($"WASM definition {val}, resolved from MethodAnalysisContext {context} has no associated function body"); } return val.AssociatedFunctionBody.Instructions; } return Array.Empty(); } public override List GetIsilFromMethod(MethodAnalysisContext context) { return new List(); } public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() { return new WasmKeyFunctionAddresses(); } public override string PrintAssembly(MethodAnalysisContext context) { Il2CppMethodDefinition definition = context.Definition; if (definition == null) { return string.Empty; } List values = Disassembler.Disassemble(WasmUtils.GetWasmDefinition(definition).AssociatedFunctionBody.Instructions, (uint)context.UnderlyingPointer); return string.Join("\n", values); } } public class X86InstructionSet : Cpp2IlInstructionSet { private static readonly MasmFormatter Formatter = new MasmFormatter(); private static readonly StringOutput Output = new StringOutput(); private static string FormatInstructionInternal(Instruction instruction) { ((Formatter)Formatter).Format(ref instruction, (FormatterOutput)(object)Output); return Output.ToStringAndReset(); } public static string FormatInstruction(Instruction instruction) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) lock (Formatter) { return FormatInstructionInternal(instruction); } } public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { return X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, isAttributeGenerator); } public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() { return new X86KeyFunctionAddresses(); } public override string PrintAssembly(MethodAnalysisContext context) { lock (Formatter) { IEnumerable source = X86Utils.Iterate(X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, isCaGen: false), context.UnderlyingPointer); return string.Join("\n", source.Select(FormatInstructionInternal)); } } public override List GetIsilFromMethod(MethodAnalysisContext context) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) IsilBuilder isilBuilder = new IsilBuilder(); foreach (Instruction item in X86Utils.Iterate(context.RawBytes, context.UnderlyingPointer)) { ConvertInstructionStatement(item, isilBuilder, context); } isilBuilder.FixJumps(); return isilBuilder.BackingStatementList; } private void ConvertInstructionStatement(Instruction instruction, IsilBuilder builder, MethodAnalysisContext context) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Invalid comparison between Unknown and I4 //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Invalid comparison between Unknown and I4 //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Invalid comparison between Unknown and I4 //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Invalid comparison between Unknown and I4 //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Invalid comparison between Unknown and I4 //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Invalid comparison between Unknown and I4 //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Invalid comparison between Unknown and I4 //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Invalid comparison between Unknown and I4 //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Invalid comparison between Unknown and I4 //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Invalid comparison between Unknown and I4 //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Invalid comparison between Unknown and I4 //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Expected I4, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Invalid comparison between Unknown and I4 //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Invalid comparison between Unknown and I4 //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected I4, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected I4, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Invalid comparison between Unknown and I4 //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Invalid comparison between Unknown and I4 //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Invalid comparison between Unknown and I4 //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Invalid comparison between Unknown and I4 //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Invalid comparison between Unknown and I4 //IL_0588: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Invalid comparison between Unknown and I4 //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_0ab3: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Invalid comparison between Unknown and I4 //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Invalid comparison between Unknown and I4 //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Invalid comparison between Unknown and I4 //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Invalid comparison between Unknown and I4 //IL_09e5: Unknown result type (might be due to invalid IL or missing references) //IL_0a2f: Unknown result type (might be due to invalid IL or missing references) //IL_0a0a: Unknown result type (might be due to invalid IL or missing references) //IL_0a51: Unknown result type (might be due to invalid IL or missing references) //IL_099b: Unknown result type (might be due to invalid IL or missing references) //IL_0946: Unknown result type (might be due to invalid IL or missing references) //IL_09c0: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Invalid comparison between Unknown and I4 //IL_06b9: Unknown result type (might be due to invalid IL or missing references) //IL_06c3: Invalid comparison between Unknown and I4 //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Invalid comparison between Unknown and I4 //IL_092f: Unknown result type (might be due to invalid IL or missing references) //IL_0937: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_05b7: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Invalid comparison between Unknown and I4 //IL_05c6: Unknown result type (might be due to invalid IL or missing references) //IL_05cd: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Invalid comparison between Unknown and I4 //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0a7a: Unknown result type (might be due to invalid IL or missing references) //IL_0a82: Unknown result type (might be due to invalid IL or missing references) //IL_0642: Unknown result type (might be due to invalid IL or missing references) //IL_064b: Unknown result type (might be due to invalid IL or missing references) //IL_0655: Unknown result type (might be due to invalid IL or missing references) //IL_08e5: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Invalid comparison between Unknown and I4 //IL_05a8: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Invalid comparison between Unknown and I4 //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_06fd: Unknown result type (might be due to invalid IL or missing references) //IL_0705: Unknown result type (might be due to invalid IL or missing references) //IL_06dd: Unknown result type (might be due to invalid IL or missing references) //IL_06e5: Unknown result type (might be due to invalid IL or missing references) //IL_0601: Unknown result type (might be due to invalid IL or missing references) //IL_060a: Unknown result type (might be due to invalid IL or missing references) //IL_05d1: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_051b: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_066e: Unknown result type (might be due to invalid IL or missing references) //IL_067a: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_068f: Invalid comparison between Unknown and I4 //IL_08ee: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_08f7: Unknown result type (might be due to invalid IL or missing references) //IL_08fe: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_041c: Unknown result type (might be due to invalid IL or missing references) //IL_090e: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) Mnemonic mnemonic = ((Instruction)(ref instruction)).Mnemonic; if ((int)mnemonic <= 441) { if ((int)mnemonic <= 110) { if ((int)mnemonic <= 26) { if ((int)mnemonic <= 11) { if ((int)mnemonic == 7) { goto IL_05b5; } if ((int)mnemonic == 11) { goto IL_0637; } } else if ((int)mnemonic == 21 || (int)mnemonic == 26) { builder.And(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } } else if ((int)mnemonic <= 93) { if ((int)mnemonic == 59) { goto IL_0714; } if ((int)mnemonic == 93) { goto IL_0926; } } else { if ((int)mnemonic == 105) { goto IL_0926; } if ((int)mnemonic == 110) { goto IL_02c4; } } } else if ((int)mnemonic <= 287) { if ((int)mnemonic <= 277) { if ((int)mnemonic == 137) { goto IL_06b7; } if ((int)mnemonic == 277) { if (((Instruction)(ref instruction)).OpCount != 1) { if (((Instruction)(ref instruction)).OpCount == 3) { builder.Multiply(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); } else { builder.Multiply(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); } return; } switch (((int)((Instruction)(ref instruction)).Op0Kind == 0) ? RegisterExtensions.GetSize(((Instruction)(ref instruction)).Op0Register) : MemorySizeExtensions.GetSize(((Instruction)(ref instruction)).MemorySize)) { case 1: builder.Multiply(((Instruction)(ref instruction)).IP, ((Register)21).MakeIndependent(), ConvertOperand(instruction, 0), ((Register)1).MakeIndependent()); return; } } } else { if ((int)mnemonic == 279) { goto IL_06b7; } if ((int)mnemonic == 287) { goto IL_0a8f; } } } else { if ((int)mnemonic > 374) { switch (mnemonic - 414) { default: if ((int)mnemonic == 423 || (int)mnemonic == 441) { break; } goto IL_0aab; case 0: case 2: case 4: break; case 1: case 3: goto IL_0aab; } goto IL_02c4; } switch (mnemonic - 297) { default: if ((int)mnemonic != 374) { goto IL_0aab; } builder.LoadAddress(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; case 11: break; case 5: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget2 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfEqual(((Instruction)(ref instruction)).IP, nearBranchTarget2); return; } goto IL_0aab; case 13: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget4 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfNotEqual(((Instruction)(ref instruction)).IP, nearBranchTarget4); return; } goto IL_0aab; case 0: case 7: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget6 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfGreater(((Instruction)(ref instruction)).IP, nearBranchTarget6); return; } goto IL_0aab; case 2: case 9: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget5 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfLess(((Instruction)(ref instruction)).IP, nearBranchTarget5); return; } goto IL_0aab; case 1: case 8: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget3 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfGreaterOrEqual(((Instruction)(ref instruction)).IP, nearBranchTarget3); return; } goto IL_0aab; case 3: case 10: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfLessOrEqual(((Instruction)(ref instruction)).IP, nearBranchTarget); return; } goto IL_0aab; case 4: case 6: case 12: goto IL_0aab; } if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget7 = ((Instruction)(ref instruction)).NearBranchTarget; ulong num = ((Instruction)(ref instruction)).IP + (ulong)context.RawBytes.Length; ulong underlyingPointer = context.UnderlyingPointer; if (nearBranchTarget7 >= underlyingPointer && nearBranchTarget7 <= num) { builder.Goto(((Instruction)(ref instruction)).IP, nearBranchTarget7); return; } goto IL_0714; } } } else if ((int)mnemonic <= 712) { if ((int)mnemonic <= 460) { if ((int)mnemonic <= 448) { if ((int)mnemonic == 444 || (int)mnemonic == 448) { goto IL_02c4; } } else { if (mnemonic - 453 <= 1) { goto IL_02c4; } if ((int)mnemonic == 460) { goto IL_04d5; } } } else if ((int)mnemonic <= 590) { switch (mnemonic - 465) { default: if ((int)mnemonic != 590) { break; } builder.Pop(((Instruction)(ref instruction)).IP, InstructionSetIndependentOperand.MakeRegister("rsp"), ConvertOperand(instruction, 0)); return; case 2: case 4: builder.Or(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; case 1: builder.Not(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0)); return; case 0: builder.Nop(((Instruction)(ref instruction)).IP); return; case 3: break; } } else { if ((int)mnemonic == 640) { builder.Push(((Instruction)(ref instruction)).IP, InstructionSetIndependentOperand.MakeRegister("rsp"), ConvertOperand(instruction, 0)); return; } if ((int)mnemonic == 662) { if (context.IsVoid) { builder.Return(((Instruction)(ref instruction)).IP); } else { builder.Return(((Instruction)(ref instruction)).IP, InstructionSetIndependentOperand.MakeRegister("rax")); } return; } if ((int)mnemonic == 712) { builder.ShiftLeft(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } } } else if ((int)mnemonic <= 751) { if ((int)mnemonic <= 740) { if ((int)mnemonic == 715) { builder.ShiftRight(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } if ((int)mnemonic == 740) { goto IL_05b5; } } else { if ((int)mnemonic == 744) { goto IL_0637; } if ((int)mnemonic == 751) { if ((int)((Instruction)(ref instruction)).Op0Kind == 0 && (int)((Instruction)(ref instruction)).Op1Kind == 0 && ((Instruction)(ref instruction)).Op0Register == ((Instruction)(ref instruction)).Op1Register) { builder.Compare(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(0)); return; } goto IL_0926; } } } else if ((int)mnemonic <= 1509) { if ((int)mnemonic == 1076) { goto IL_04d5; } if ((int)mnemonic == 1509) { builder.Exchange(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } } else { if ((int)mnemonic == 1518 || (int)mnemonic == 1520) { if ((int)((Instruction)(ref instruction)).Op0Kind == 0 && (int)((Instruction)(ref instruction)).Op1Kind == 0 && ((Instruction)(ref instruction)).Op0Register == ((Instruction)(ref instruction)).Op1Register) { builder.Move(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(0)); } else { builder.Xor(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); } return; } if ((int)mnemonic == 1620) { goto IL_0a8f; } } goto IL_0aab; IL_04d5: if (((Instruction)(ref instruction)).OpCount == 3) { builder.Multiply(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); return; } if (((Instruction)(ref instruction)).OpCount == 2) { builder.Multiply(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } goto IL_0aab; IL_0637: InstructionSetIndependentOperand instructionSetIndependentOperand; InstructionSetIndependentOperand left; InstructionSetIndependentOperand right; if (((Instruction)(ref instruction)).OpCount == 3) { instructionSetIndependentOperand = ConvertOperand(instruction, 0); left = ConvertOperand(instruction, 1); right = ConvertOperand(instruction, 2); } else { if (((Instruction)(ref instruction)).OpCount != 2) { goto IL_0aab; } instructionSetIndependentOperand = ConvertOperand(instruction, 0); left = instructionSetIndependentOperand; right = ConvertOperand(instruction, 1); } if ((int)((Instruction)(ref instruction)).Mnemonic == 744) { builder.Subtract(((Instruction)(ref instruction)).IP, instructionSetIndependentOperand, left, right); } else { builder.Add(((Instruction)(ref instruction)).IP, instructionSetIndependentOperand, left, right); } return; IL_0714: ulong nearBranchTarget8 = ((Instruction)(ref instruction)).NearBranchTarget; if (context.AppContext.MethodsByAddress.ContainsKey(nearBranchTarget8)) { int num2 = context.AppContext.MethodsByAddress[nearBranchTarget8].Select(delegate(MethodAnalysisContext p) { int num5 = p.Parameters.Count; if (!p.IsStatic) { num5++; } return num5 + 1; }).Max(); List list = new string[4] { "rcx", "rdx", "r8", "r9" }.Select(InstructionSetIndependentOperand.MakeRegister).ToList(); if (num2 <= list.Count) { builder.Call(((Instruction)(ref instruction)).IP, nearBranchTarget8, list.GetRange(0, num2).ToArray()); return; } num2 -= list.Count; int ptrSize = (int)((ClassReadingBinaryReader)context.AppContext.Binary).PointerSize; list = list.Concat((from p in Enumerable.Range(0, num2) select p * ptrSize).Select(InstructionSetIndependentOperand.MakeStack)).ToList(); builder.Call(((Instruction)(ref instruction)).IP, nearBranchTarget8, list.ToArray()); builder.ShiftStack(((Instruction)(ref instruction)).IP, -num2 * 8); } else { InstructionSetIndependentOperand[] args = new string[4] { "rcx", "rdx", "r8", "r9" }.Select(InstructionSetIndependentOperand.MakeRegister).ToArray(); builder.Call(((Instruction)(ref instruction)).IP, nearBranchTarget8, args); } return; IL_0aab: builder.NotImplemented(((Instruction)(ref instruction)).IP, FormatInstruction(instruction)); return; IL_0926: builder.Compare(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; IL_06b7: bool num3 = (int)((Instruction)(ref instruction)).Mnemonic == 137; InstructionSetIndependentOperand right2 = InstructionSetIndependentOperand.MakeImmediate(1); if (num3) { builder.Subtract(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), right2); } else { builder.Add(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), right2); } return; IL_0a8f: builder.Interrupt(((Instruction)(ref instruction)).IP); return; IL_05b5: bool flag = (int)((Instruction)(ref instruction)).Mnemonic == 740; if ((int)((Instruction)(ref instruction)).Op0Register == 57 && ((Instruction)(ref instruction)).Op1Kind.IsImmediate()) { int num4 = (int)((Instruction)(ref instruction)).GetImmediate(1); builder.ShiftStack(((Instruction)(ref instruction)).IP, flag ? (-num4) : num4); return; } InstructionSetIndependentOperand instructionSetIndependentOperand2 = ConvertOperand(instruction, 0); InstructionSetIndependentOperand right3 = ConvertOperand(instruction, 1); if (flag) { builder.Subtract(((Instruction)(ref instruction)).IP, instructionSetIndependentOperand2, instructionSetIndependentOperand2, right3); } else { builder.Add(((Instruction)(ref instruction)).IP, instructionSetIndependentOperand2, instructionSetIndependentOperand2, right3); } return; IL_02c4: builder.Move(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); } private InstructionSetIndependentOperand ConvertOperand(Instruction instruction, int operand) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) OpKind opKind = ((Instruction)(ref instruction)).GetOpKind(operand); if ((int)opKind == 0) { return InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).GetOpRegister(operand))); } if (opKind.IsImmediate()) { return InstructionSetIndependentOperand.MakeImmediate(((Instruction)(ref instruction)).GetImmediate(operand)); } if ((int)opKind == 24 && (int)((Instruction)(ref instruction)).MemoryBase == 57) { return InstructionSetIndependentOperand.MakeStack((int)((Instruction)(ref instruction)).MemoryDisplacement32); } if (((Instruction)(ref instruction)).IsIPRelativeMemoryOperand) { return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand((long)((Instruction)(ref instruction)).IPRelativeMemoryAddress)); } if ((int)((Instruction)(ref instruction)).MemoryIndex != 0 && (int)((Instruction)(ref instruction)).MemoryBase != 0 && ((Instruction)(ref instruction)).MemoryDisplacement64 != 0L) { InstructionSetIndependentOperand @base = InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).MemoryBase)); InstructionSetIndependentOperand index = InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).MemoryIndex)); return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(@base, index, ((Instruction)(ref instruction)).MemoryDisplacement32, ((Instruction)(ref instruction)).MemoryIndexScale)); } if ((int)((Instruction)(ref instruction)).MemoryIndex != 0 && (int)((Instruction)(ref instruction)).MemoryBase != 0) { InstructionSetIndependentOperand base2 = InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).MemoryBase)); InstructionSetIndependentOperand index2 = InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).MemoryIndex)); return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(base2, index2, ((Instruction)(ref instruction)).MemoryIndexScale)); } if ((int)((Instruction)(ref instruction)).MemoryBase != 0 && ((Instruction)(ref instruction)).MemoryDisplacement64 != 0) { return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).MemoryBase)), (long)((Instruction)(ref instruction)).MemoryDisplacement64)); } if ((int)((Instruction)(ref instruction)).MemoryBase != 0) { return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(((Instruction)(ref instruction)).MemoryBase)))); } return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand((long)((Instruction)(ref instruction)).MemoryDisplacement64)); } } } namespace Cpp2IL.Core.Il2CppApiFunctions { public class Arm64KeyFunctionAddresses : BaseKeyFunctionAddresses { private List _allInstructions = new List(); protected override void Init(ApplicationAnalysisContext context) { CapstoneArm64Disassembler val = CapstoneDisassembler.CreateArm64Disassembler((Arm64DisassembleMode)(((EndianAwareBinaryReader)context.Binary).IsBigEndian ? int.MinValue : 0)); ((CapstoneDisassembler)val).EnableInstructionDetails = true; ((CapstoneDisassembler)(object)val).DisassembleSyntax = (DisassembleSyntax)1; ((CapstoneDisassembler)val).EnableSkipDataMode = true; byte[] array = context.Binary.GetEntirePrimaryExecutableSection(); ulong num = context.Binary.GetVirtualAddressOfPrimaryExecutableSection(); ulong num2 = num + (ulong)array.Length; Logger.InfoNewline("\tRunning entire .text section through Arm64 disassembler, this might take up to several minutes for large games, and may fail on large games if you have <16GB ram..."); Logger.VerboseNewline($"\tPrimary executable section is {array.Length} bytes, starting at 0x{num:X} and extending to 0x{num2:X}"); List list = SharedState.AttributeGeneratorStarts.ToList(); Extensions.SortByExtractedKey(list, (Func)((ulong a) => a)); if (list.Count > 0) { if (!(context.Binary is NsoFile)) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(85, 1); defaultInterpolatedStringHandler.AppendLiteral("\tLast attribute generator function is at address 0x"); defaultInterpolatedStringHandler.AppendFormatted(list[list.Count - 1], "X"); defaultInterpolatedStringHandler.AppendLiteral(". Skipping everything before that."); Logger.VerboseNewline(defaultInterpolatedStringHandler.ToStringAndClear()); int num3 = array.Length; int num4 = (int)(list[list.Count - 1] - num); array = array.Skip(num4).ToArray(); num = list[list.Count - 1]; Logger.VerboseNewline($"\tBy trimming out attribute generator functions, reduced decompilation work by {num4} of {num3} bytes (a {(float)(num4 * 100) / (float)num3:f1}% saving)"); List list2 = new List(); Extensions.SortByExtractedKey(list2, (Func)((ulong a) => a)); if (list2[0] < num2 && context.Binary.GetVirtualAddressOfExportedFunctionByName("il2cpp_object_new") != 0L) { ulong[] source = (from a in ((IEnumerable)new string[9] { "il2cpp_object_new", "il2cpp_value_box", "il2cpp_runtime_class_init", "il2cpp_array_new_specific", "il2cpp_type_get_object", "il2cpp_resolve_icall", "il2cpp_string_new", "il2cpp_string_new_wrapper", "il2cpp_raise_exception" }).Select((Func)context.Binary.GetVirtualAddressOfExportedFunctionByName) where a != 0 select a).ToArray(); ulong value = source.Max(); ulong num5 = source.Min(); defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(271, 4); defaultInterpolatedStringHandler.AppendLiteral("\tDetected that the il2cpp-ified managed methods are in the .text section and api functions are available. Attempting to trim out managed methods for KFA scanning - the first managed method is at 0x"); defaultInterpolatedStringHandler.AppendFormatted(list2[0], "X"); defaultInterpolatedStringHandler.AppendLiteral(" and the last at 0x"); defaultInterpolatedStringHandler.AppendFormatted(list2[list2.Count - 1], "X"); defaultInterpolatedStringHandler.AppendLiteral(", "); defaultInterpolatedStringHandler.AppendLiteral("the first export function is at 0x"); defaultInterpolatedStringHandler.AppendFormatted(num5, "X"); defaultInterpolatedStringHandler.AppendLiteral(" and the last at 0x"); defaultInterpolatedStringHandler.AppendFormatted(value, "X"); Logger.VerboseNewline(defaultInterpolatedStringHandler.ToStringAndClear()); ulong num6 = Math.Min(num5, list2[list2.Count - 1]); if (num6 > 16777216) { num6 -= 1048576; } Logger.VerboseNewline($"\tTrimming everything before 0x{num6:X}."); num3 = array.Length; num4 = (int)(num6 - num); array = array.Skip(num4).ToArray(); num = num6; Logger.VerboseNewline($"\tBy trimming out most of the il2cpp-ified managed methods, reduced decompilation work by {num4} of {num3} bytes (a {(float)((long)num4 * 100L) / (float)num3:f1}% saving)"); } else if (list2[0] < num2) { defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(238, 2); defaultInterpolatedStringHandler.AppendLiteral("\tDetected that the il2cpp-ified managed methods are in the .text section, but api functions are not available. Attempting to (conservatively) trim out managed methods for KFA scanning - the first managed method is at 0x"); defaultInterpolatedStringHandler.AppendFormatted(list2[0], "X"); defaultInterpolatedStringHandler.AppendLiteral(" and the last at 0x"); defaultInterpolatedStringHandler.AppendFormatted(list2[list2.Count - 1], "X"); Logger.VerboseNewline(defaultInterpolatedStringHandler.ToStringAndClear()); ulong num7 = list2[list2.Count - 1]; if (num7 > 16777216) { num7 -= 1048576; } Logger.VerboseNewline($"\tTrimming everything before 0x{num7:X}."); num3 = array.Length; num4 = (int)(num7 - num); array = array.Skip(num4).ToArray(); num = num7; Logger.VerboseNewline($"\tBy trimming out most of the il2cpp-ified managed methods, reduced decompilation work by {num4} of {num3} bytes (a {(float)((long)num4 * 100L) / (float)num3:f1}% saving)"); } } else { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(89, 1); defaultInterpolatedStringHandler.AppendLiteral("\tNSO: Last attribute generator function is at address 0x"); defaultInterpolatedStringHandler.AppendFormatted(list[list.Count - 1], "X"); defaultInterpolatedStringHandler.AppendLiteral(". Skipping everything after that."); Logger.VerboseNewline(defaultInterpolatedStringHandler.ToStringAndClear()); int num8 = array.Length; int num9 = (int)(list[list.Count - 1] - num); array = array.SubArray(..num9); Logger.VerboseNewline($"\tBy trimming out everything after and including attribute generator functions, reduced decompilation work by {num8 - num9} of {num8} bytes (a {(float)((long)(num8 - num9) * 100L) / (float)num8:f1}% saving)"); } } _allInstructions = ((CapstoneDisassembler)(object)val).Disassemble(array, (long)num).ToList(); } protected override IEnumerable FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0u, params ulong[] addressesToIgnore) { List list = (from i in _allInstructions.Where(delegate(Arm64Instruction i) { string mnemonic2 = ((Instruction)(object)i).Mnemonic; return (mnemonic2 == "b" || mnemonic2 == "bl") ? true : false; }) where ((Instruction)(object)i).Details.Operands[0].IsImmediate() && ((Instruction)(object)i).Details.Operands[0].Immediate == (long)addr select i).ToList(); foreach (Arm64Instruction item in list) { if (addressesToIgnore.Contains((ulong)((Instruction)(object)item).Address)) { continue; } int num = 0; int num2 = _allInstructions.IndexOf(item); do { if (num2 - num > 0) { Arm64Instruction val = _allInstructions[num2 - num - 1]; if (addressesToIgnore.Contains((ulong)((Instruction)(object)val).Address)) { num++; continue; } if (((Instruction)(object)val).IsSkippedData && ((Instruction)(object)val).Bytes.All((byte b) => b == 0)) { yield return (ulong)(((Instruction)(object)item).Address - num * 4); break; } string mnemonic = ((Instruction)(object)val).Mnemonic; if ((mnemonic == "adrp" || mnemonic == "str") ? true : false) { break; } mnemonic = ((Instruction)(object)val).Mnemonic; if ((mnemonic == "b" || mnemonic == "bl") ? true : false) { yield return (ulong)(((Instruction)(object)item).Address - num * 4); break; } if (((Instruction)(object)val).Mnemonic == "ret") { yield return (ulong)(((Instruction)(object)item).Address - num * 4); break; } } num++; } while (num * 4 < maxBytesBack); } } protected override ulong GetObjectIsInstFromSystemType() { Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst..."); Il2CppTypeDefinition type = LibCpp2IlReflection.GetType("Type", "System"); Il2CppMethodDefinition val = ((type == null) ? null : type.Methods?.FirstOrDefault((Func)((Il2CppMethodDefinition m) => m.Name == "IsInstanceOfType"))); if (val == null) { Logger.VerboseNewline("Type or method not found, aborting."); return 0uL; } Logger.Verbose($"IsInstanceOfType found at 0x{val.MethodPointer:X}..."); Arm64Instruction val2 = ((IEnumerable)Arm64Utils.GetArm64MethodBodyAtVirtualAddress(val.MethodPointer, managed: false)).LastOrDefault((Func)((Arm64Instruction i) => ((Instruction)(object)i).Mnemonic == "bl")); if (val2 == null) { Logger.VerboseNewline("Method does not match expected signature. Aborting."); return 0uL; } Logger.VerboseNewline($"Success. IsInst found at 0x{((Instruction)(object)val2).Details.Operands[0].Immediate:X}"); return (ulong)((Instruction)(object)val2).Details.Operands[0].Immediate; } protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false) { int num = _allInstructions.FindIndex((Arm64Instruction i) => ((Instruction)(object)i).Address == (long)thunkPtr); if (num < 0) { return 0uL; } string mnemonic = ((Instruction)(object)_allInstructions[num]).Mnemonic; if ((mnemonic == "b" || mnemonic == "bl") ? true : false) { return (ulong)((Instruction)(object)_allInstructions[num]).Details.Operands[0].Immediate; } for (int j = 0; j <= 12; j++) { num++; mnemonic = ((Instruction)(object)_allInstructions[num]).Mnemonic; if ((mnemonic == "b" || mnemonic == "bl") ? true : false) { return (ulong)((Instruction)(object)_allInstructions[num]).Details.Operands[0].Immediate; } } return 0uL; } protected override int GetCallerCount(ulong toWhere) { return _allInstructions.Where(delegate(Arm64Instruction i) { string mnemonic = ((Instruction)(object)i).Mnemonic; return (mnemonic == "b" || mnemonic == "bl") ? true : false; }).Count((Arm64Instruction i) => ((Instruction)(object)i).Details.Operands[0].IsImmediate() && ((Instruction)(object)i).Details.Operands[0].Immediate == (long)toWhere); } protected override void AttemptInstructionAnalysisToFillGaps() { if (il2cpp_object_new != 0L) { return; } Logger.Verbose("\tAttempting to use Array GetEnumerator to find il2cpp_codegen_object_new..."); Il2CppTypeDefinition type = LibCpp2IlReflection.GetType("Array", "System"); if (type != null) { Il2CppMethodDefinition val = ((IEnumerable)type.Methods).FirstOrDefault((Func)((Il2CppMethodDefinition m) => m.Name == "GetEnumerator")); if (val != null) { List arm64MethodBodyAtVirtualAddress = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(val.MethodPointer); long num = 0L; int num2 = 0; for (int i = 0; i < arm64MethodBodyAtVirtualAddress.Count - 4; i++) { if (!(((Instruction)(object)arm64MethodBodyAtVirtualAddress[i]).Mnemonic != "adrp") && !(((Instruction)(object)arm64MethodBodyAtVirtualAddress[i + 1]).Mnemonic != "ldr") && !(((Instruction)(object)arm64MethodBodyAtVirtualAddress[i + 2]).Mnemonic != "ldr") && !(((Instruction)(object)arm64MethodBodyAtVirtualAddress[i + 3]).Mnemonic != "bl") && num2++ < 2) { num = ((Instruction)(object)arm64MethodBodyAtVirtualAddress[i + 3]).Details.Operands[0].Immediate; } } if (num > 0) { Logger.Verbose($"Probably found at 0x{num:X}..."); ulong num3 = FindFunctionThisIsAThunkOf((ulong)num); long addr = ((num3 == 0) ? num : ((long)num3)); List list = FindAllThunkFunctions((ulong)addr, 16u, (ulong)num).ToList(); Extensions.SortByExtractedKey(list, (Func)GetCallerCount); list.Reverse(); il2cpp_object_new = list.FirstOrDefault(); Logger.VerboseNewline($"Leaving il2cpp_object_new at 0x{il2cpp_object_new:X}"); } else { Logger.VerboseNewline("Couldn't find a matching instruction, can't be used."); } } else { Logger.VerboseNewline("Method stripped, can't be used."); } } else { Logger.VerboseNewline("Type stripped, can't be used."); } } } public abstract class BaseKeyFunctionAddresses { public ulong il2cpp_codegen_initialize_method; public ulong il2cpp_codegen_initialize_runtime_metadata; public ulong il2cpp_vm_metadatacache_initializemethodmetadata; public ulong il2cpp_runtime_class_init_export; public ulong il2cpp_runtime_class_init_actual; public ulong il2cpp_object_new; public ulong il2cpp_vm_object_new; public ulong il2cpp_codegen_object_new; public ulong il2cpp_array_new_specific; public ulong il2cpp_vm_array_new_specific; public ulong SzArrayNew; public ulong il2cpp_type_get_object; public ulong il2cpp_vm_reflection_get_type_object; public ulong il2cpp_resolve_icall; public ulong InternalCalls_Resolve; public ulong il2cpp_string_new; public ulong il2cpp_vm_string_new; public ulong il2cpp_string_new_wrapper; public ulong il2cpp_vm_string_newWrapper; public ulong il2cpp_codegen_string_new_wrapper; public ulong il2cpp_value_box; public ulong il2cpp_vm_object_box; public ulong il2cpp_object_unbox; public ulong il2cpp_vm_object_unbox; public ulong il2cpp_raise_exception; public ulong il2cpp_vm_exception_raise; public ulong il2cpp_codegen_raise_exception; public ulong il2cpp_vm_object_is_inst; public ulong AddrPInvokeLookup; private ApplicationAnalysisContext _appContext; private readonly HashSet resolvedAddresses = new HashSet(); public bool IsKeyFunctionAddress(ulong address) { if (address != 0L) { return resolvedAddresses.Contains(address); } return false; } private void FindExport(string name, out ulong ptr) { Logger.Verbose("\tLooking for Exported " + name + " function..."); ptr = _appContext.Binary.GetVirtualAddressOfExportedFunctionByName(name); Logger.VerboseNewline((ptr == 0L) ? "Not found" : $"Found at 0x{ptr:X}"); } public virtual void Find(ApplicationAnalysisContext applicationAnalysisContext) { _appContext = applicationAnalysisContext; Init(applicationAnalysisContext); if (applicationAnalysisContext.Binary.InstructionSetId == DefaultInstructionSets.X86_32 || applicationAnalysisContext.Binary.InstructionSetId == DefaultInstructionSets.X86_64) { TryGetInitMetadataFromException(); } FindExport("il2cpp_object_new", out il2cpp_object_new); FindExport("il2cpp_type_get_object", out il2cpp_type_get_object); FindExport("il2cpp_resolve_icall", out il2cpp_resolve_icall); FindExport("il2cpp_string_new", out il2cpp_string_new); FindExport("il2cpp_string_new_wrapper", out il2cpp_string_new_wrapper); FindExport("il2cpp_value_box", out il2cpp_value_box); FindExport("il2cpp_object_unbox", out il2cpp_object_unbox); FindExport("il2cpp_raise_exception", out il2cpp_raise_exception); FindExport("il2cpp_runtime_class_init", out il2cpp_runtime_class_init_export); FindExport("il2cpp_array_new_specific", out il2cpp_array_new_specific); il2cpp_vm_object_is_inst = GetObjectIsInstFromSystemType(); AttemptInstructionAnalysisToFillGaps(); FindThunks(); InitializeResolvedAddresses(); } protected void TryGetInitMetadataFromException() { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) Logger.VerboseNewline("\tLooking for Type System.Exception, Method get_Message..."); Il2CppTypeDefinition type = LibCpp2IlReflection.GetType("Exception", "System"); Logger.VerboseNewline("\t\tType Located. Ensuring method exists..."); Il2CppMethodDefinition val = ((IEnumerable)type.Methods).FirstOrDefault((Func)((Il2CppMethodDefinition m) => m.Name == "get_Message")); if (val != null) { Logger.VerboseNewline($"\t\tTarget Method Located at {val.MethodPointer}. Taking first CALL as the (version-specific) metadata initialization function..."); List list = ((IEnumerable)X86Utils.GetMethodBodyAtVirtAddressNew(val.MethodPointer, peek: false)).Where((Instruction i) => (int)((Instruction)(ref i)).Mnemonic == 59).ToList(); Instruction val2; if (list.Count == 0) { Logger.WarnNewline("Couldn't find any call instructions in the method body. This is not expected. Will not have metadata initialization function."); } else if (_appContext.MetadataVersion < 27f) { val2 = list.First(); il2cpp_codegen_initialize_method = ((Instruction)(ref val2)).NearBranchTarget; Logger.VerboseNewline($"\t\til2cpp_codegen_initialize_method => 0x{il2cpp_codegen_initialize_method:X}"); } else { val2 = list.First(); il2cpp_codegen_initialize_runtime_metadata = ((Instruction)(ref val2)).NearBranchTarget; Logger.VerboseNewline($"\t\til2cpp_codegen_initialize_runtime_metadata => 0x{il2cpp_codegen_initialize_runtime_metadata:X}"); } } } protected virtual void AttemptInstructionAnalysisToFillGaps() { } private void FindThunks() { if (il2cpp_object_new != 0L) { Logger.Verbose("\t\tMapping il2cpp_object_new to vm::Object::New..."); il2cpp_vm_object_new = FindFunctionThisIsAThunkOf(il2cpp_object_new, prioritiseCall: true); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_object_new:X}"); } if (il2cpp_vm_object_new != 0L) { Logger.Verbose("\t\tLooking for il2cpp_codegen_object_new as a thunk of vm::Object::New..."); List<(ulong, int)> list = (from ptr in FindAllThunkFunctions(il2cpp_vm_object_new, 16u) select (ptr, GetCallerCount(ptr))).ToList(); Extensions.SortByExtractedKey<(ulong, int), int>(list, (Func<(ulong, int), int>)(((ulong ptr, int count) pair) => pair.count)); list.Reverse(); il2cpp_codegen_object_new = list.FirstOrDefault().Item1; Logger.VerboseNewline($"Found at 0x{il2cpp_codegen_object_new:X}"); } if (il2cpp_type_get_object != 0L) { Logger.Verbose("\t\tMapping il2cpp_resolve_icall to Reflection::GetTypeObject..."); il2cpp_vm_reflection_get_type_object = FindFunctionThisIsAThunkOf(il2cpp_type_get_object); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_reflection_get_type_object:X}"); } if (il2cpp_resolve_icall != 0L) { Logger.Verbose("\t\tMapping il2cpp_resolve_icall to InternalCalls::Resolve..."); InternalCalls_Resolve = FindFunctionThisIsAThunkOf(il2cpp_resolve_icall); Logger.VerboseNewline($"Found at 0x{InternalCalls_Resolve:X}"); } if (il2cpp_string_new != 0L) { Logger.Verbose("\t\tMapping il2cpp_string_new to String::New..."); il2cpp_vm_string_new = FindFunctionThisIsAThunkOf(il2cpp_string_new); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_string_new:X}"); } if (il2cpp_string_new_wrapper != 0L) { Logger.Verbose("\t\tMapping il2cpp_string_new_wrapper to String::NewWrapper..."); il2cpp_vm_string_newWrapper = FindFunctionThisIsAThunkOf(il2cpp_string_new_wrapper); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_string_newWrapper:X}"); } if (il2cpp_vm_string_newWrapper != 0L) { Logger.Verbose("\t\tMapping String::NewWrapper to il2cpp_codegen_string_new_wrapper..."); il2cpp_codegen_string_new_wrapper = FindAllThunkFunctions(il2cpp_vm_string_newWrapper, 0u, il2cpp_string_new_wrapper).FirstOrDefault(); Logger.VerboseNewline($"Found at 0x{il2cpp_codegen_string_new_wrapper:X}"); } if (il2cpp_value_box != 0L) { Logger.Verbose("\t\tMapping il2cpp_value_box to Object::Box..."); il2cpp_vm_object_box = FindFunctionThisIsAThunkOf(il2cpp_value_box); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_object_box:X}"); } if (il2cpp_object_unbox != 0L) { Logger.Verbose("\t\tMapping il2cpp_object_unbox to Object::Unbox..."); il2cpp_vm_object_unbox = FindFunctionThisIsAThunkOf(il2cpp_object_unbox); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_object_unbox:X}"); } if (il2cpp_raise_exception != 0L) { Logger.Verbose("\t\tMapping il2cpp_raise_exception to il2cpp::vm::Exception::Raise..."); il2cpp_vm_exception_raise = FindFunctionThisIsAThunkOf(il2cpp_raise_exception, prioritiseCall: true); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_exception_raise:X}"); } if (il2cpp_vm_exception_raise != 0L) { Logger.Verbose("\t\tMapping il2cpp::vm::Exception::Raise to il2cpp_codegen_raise_exception..."); il2cpp_codegen_raise_exception = FindAllThunkFunctions(il2cpp_vm_exception_raise, 4u, il2cpp_raise_exception).FirstOrDefault(); Logger.VerboseNewline($"Found at 0x{il2cpp_codegen_raise_exception:X}"); } if (il2cpp_runtime_class_init_export != 0L) { Logger.Verbose("\t\tMapping il2cpp_runtime_class_init to il2cpp:vm::Runtime::ClassInit..."); il2cpp_runtime_class_init_actual = FindFunctionThisIsAThunkOf(il2cpp_runtime_class_init_export); Logger.VerboseNewline($"Found at 0x{il2cpp_runtime_class_init_actual:X}"); } if (il2cpp_array_new_specific != 0L) { Logger.Verbose("\t\tMapping il2cpp_array_new_specific to vm::Array::NewSpecific..."); il2cpp_vm_array_new_specific = FindFunctionThisIsAThunkOf(il2cpp_array_new_specific); Logger.VerboseNewline($"Found at 0x{il2cpp_vm_array_new_specific:X}"); } if (il2cpp_vm_array_new_specific != 0L) { Logger.Verbose("\t\tLooking for SzArrayNew as a thunk function proxying Array::NewSpecific..."); SzArrayNew = FindAllThunkFunctions(il2cpp_vm_array_new_specific, 4u, il2cpp_array_new_specific).FirstOrDefault(); Logger.VerboseNewline($"Found at 0x{SzArrayNew:X}"); } } protected abstract ulong GetObjectIsInstFromSystemType(); protected abstract IEnumerable FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0u, params ulong[] addressesToIgnore); protected abstract ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false); protected abstract int GetCallerCount(ulong toWhere); protected virtual void Init(ApplicationAnalysisContext context) { } private void InitializeResolvedAddresses() { resolvedAddresses.Clear(); resolvedAddresses.Add(il2cpp_codegen_initialize_method); resolvedAddresses.Add(il2cpp_codegen_initialize_runtime_metadata); resolvedAddresses.Add(il2cpp_vm_metadatacache_initializemethodmetadata); resolvedAddresses.Add(il2cpp_runtime_class_init_export); resolvedAddresses.Add(il2cpp_runtime_class_init_actual); resolvedAddresses.Add(il2cpp_object_new); resolvedAddresses.Add(il2cpp_vm_object_new); resolvedAddresses.Add(il2cpp_codegen_object_new); resolvedAddresses.Add(il2cpp_array_new_specific); resolvedAddresses.Add(il2cpp_vm_array_new_specific); resolvedAddresses.Add(SzArrayNew); resolvedAddresses.Add(il2cpp_type_get_object); resolvedAddresses.Add(il2cpp_vm_reflection_get_type_object); resolvedAddresses.Add(il2cpp_resolve_icall); resolvedAddresses.Add(InternalCalls_Resolve); resolvedAddresses.Add(il2cpp_string_new); resolvedAddresses.Add(il2cpp_vm_string_new); resolvedAddresses.Add(il2cpp_string_new_wrapper); resolvedAddresses.Add(il2cpp_vm_string_newWrapper); resolvedAddresses.Add(il2cpp_codegen_string_new_wrapper); resolvedAddresses.Add(il2cpp_value_box); resolvedAddresses.Add(il2cpp_vm_object_box); resolvedAddresses.Add(il2cpp_object_unbox); resolvedAddresses.Add(il2cpp_vm_object_unbox); resolvedAddresses.Add(il2cpp_raise_exception); resolvedAddresses.Add(il2cpp_vm_exception_raise); resolvedAddresses.Add(il2cpp_codegen_raise_exception); resolvedAddresses.Add(il2cpp_vm_object_is_inst); resolvedAddresses.Add(AddrPInvokeLookup); } } public class Il2CppApiFunction { public enum ApiFunctionType { Exported, WrapperOf, WrappedBy } public enum ParameterType { Standard, Float } public string Name; public ParameterType[] ParametersTypes = Array.Empty(); public ParameterType ReturnType; } public class NewArm64KeyFunctionAddresses : BaseKeyFunctionAddresses { private List? _cachedDisassembledBytes; private List DisassembleTextSection() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (_cachedDisassembledBytes == null) { byte[] entirePrimaryExecutableSection = LibCpp2IlMain.Binary.GetEntirePrimaryExecutableSection(); _cachedDisassembledBytes = Disassembler.Disassemble(entirePrimaryExecutableSection, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection(), (Options?)new Options(true, true, false)).ToList(); } return _cachedDisassembledBytes; } protected override IEnumerable FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0u, params ulong[] addressesToIgnore) { List list = DisassembleTextSection().Where(delegate(Arm64Instruction i) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 Arm64Mnemonic mnemonic = ((Arm64Instruction)(ref i)).Mnemonic; return (((int)mnemonic == 12 || (int)mnemonic == 17) ? true : false) && ((Arm64Instruction)(ref i)).BranchTarget == addr; }).ToList(); foreach (Arm64Instruction item in list) { Arm64Instruction current = item; if (Enumerable.Contains(addressesToIgnore, ((Arm64Instruction)(ref current)).Address)) { continue; } ulong num = (ulong)LibCpp2IlMain.Binary.MapVirtualAddressToRaw(((Arm64Instruction)(ref current)).Address, true); if (num == 0L || num == (ulong)(LibCpp2IlMain.Binary.RawLength - 1)) { continue; } byte byteAtRawAddress = LibCpp2IlMain.Binary.GetByteAtRawAddress(num - 1); byte byteAtRawAddress2 = LibCpp2IlMain.Binary.GetByteAtRawAddress(num + 4); if (byteAtRawAddress == 204 && byteAtRawAddress2 == 204) { yield return ((Arm64Instruction)(ref current)).Address; } else { if (byteAtRawAddress2 != 204 || maxBytesBack == 0) { continue; } for (ulong num2 = 1uL; num2 < maxBytesBack && num - num2 != 0 && !Enumerable.Contains(addressesToIgnore, ((Arm64Instruction)(ref current)).Address - (num2 - 1)); num2++) { if (LibCpp2IlMain.Binary.GetByteAtRawAddress(num - num2) == 204) { yield return ((Arm64Instruction)(ref current)).Address - (num2 - 1); break; } } } } } protected override ulong GetObjectIsInstFromSystemType() { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst..."); Il2CppTypeDefinition type = LibCpp2IlReflection.GetType("Type", "System"); Il2CppMethodDefinition val = ((type == null) ? null : type.Methods?.FirstOrDefault((Func)((Il2CppMethodDefinition m) => m.Name == "IsInstanceOfType"))); if (val == null) { Logger.VerboseNewline("Type or method not found, aborting."); return 0uL; } Logger.Verbose($"IsInstanceOfType found at 0x{val.MethodPointer:X}..."); Arm64Instruction val2 = ((IEnumerable)NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(val.MethodPointer)).LastOrDefault((Func)((Arm64Instruction i) => (int)((Arm64Instruction)(ref i)).Mnemonic == 17)); if ((int)((Arm64Instruction)(ref val2)).Mnemonic == 0) { Logger.VerboseNewline("Method does not match expected signature. Aborting."); return 0uL; } Logger.VerboseNewline($"Success. IsInst found at 0x{((Arm64Instruction)(ref val2)).BranchTarget:X}"); return ((Arm64Instruction)(ref val2)).BranchTarget; } protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) List arm64MethodBodyAtVirtualAddress = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(thunkPtr); try { Arm64Mnemonic target = (Arm64Mnemonic)(prioritiseCall ? 17 : 12); Arm64Instruction val = ((IEnumerable)arm64MethodBodyAtVirtualAddress).FirstOrDefault((Func)((Arm64Instruction i) => ((Arm64Instruction)(ref i)).Mnemonic == target)); if ((int)((Arm64Instruction)(ref val)).Mnemonic == 0) { target = (Arm64Mnemonic)(((int)target == 17) ? 12 : 17); val = arm64MethodBodyAtVirtualAddress.First((Arm64Instruction i) => ((Arm64Instruction)(ref i)).Mnemonic == target); } return ((Arm64Instruction)(ref val)).BranchTarget; } catch (Exception) { return 0uL; } } protected override int GetCallerCount(ulong toWhere) { return DisassembleTextSection().Count(delegate(Arm64Instruction i) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 Arm64Mnemonic mnemonic = ((Arm64Instruction)(ref i)).Mnemonic; return (((int)mnemonic == 12 || (int)mnemonic == 17) ? true : false) && ((Arm64Instruction)(ref i)).BranchTarget == toWhere; }); } } public class WasmKeyFunctionAddresses : BaseKeyFunctionAddresses { protected override ulong GetObjectIsInstFromSystemType() { return 0uL; } protected override IEnumerable FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0u, params ulong[] addressesToIgnore) { yield break; } protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false) { return 0uL; } protected override int GetCallerCount(ulong toWhere) { return 0; } } public class X86KeyFunctionAddresses : BaseKeyFunctionAddresses { private InstructionList? _cachedDisassembledBytes; private InstructionList DisassembleTextSection() { if (_cachedDisassembledBytes == null) { byte[] entirePrimaryExecutableSection = LibCpp2IlMain.Binary.GetEntirePrimaryExecutableSection(); _cachedDisassembledBytes = X86Utils.Disassemble(entirePrimaryExecutableSection, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection()); } return _cachedDisassembledBytes; } public override void Find(ApplicationAnalysisContext applicationAnalysisContext) { base.Find(applicationAnalysisContext); _cachedDisassembledBytes = null; } protected override IEnumerable FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0u, params ulong[] addressesToIgnore) { List list = ((IEnumerable)DisassembleTextSection()).Where(delegate(Instruction i) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 Mnemonic mnemonic = ((Instruction)(ref i)).Mnemonic; return (((int)mnemonic == 59 || (int)mnemonic == 308) ? true : false) && ((Instruction)(ref i)).NearBranchTarget == addr; }).ToList(); foreach (Instruction item in list) { Instruction current = item; if (Enumerable.Contains(addressesToIgnore, ((Instruction)(ref current)).IP)) { continue; } ulong num = (ulong)LibCpp2IlMain.Binary.MapVirtualAddressToRaw(((Instruction)(ref current)).IP, true); if (num == 0L || num == (ulong)(LibCpp2IlMain.Binary.RawLength - 1)) { continue; } byte byteAtRawAddress = LibCpp2IlMain.Binary.GetByteAtRawAddress(num - 1); byte byteAtRawAddress2 = LibCpp2IlMain.Binary.GetByteAtRawAddress(num + (ulong)((Instruction)(ref current)).Length); if (byteAtRawAddress == 204 && byteAtRawAddress2 == 204) { yield return ((Instruction)(ref current)).IP; } else { if (byteAtRawAddress2 != 204 || maxBytesBack == 0) { continue; } for (ulong num2 = 1uL; num2 < maxBytesBack && num - num2 != 0 && !Enumerable.Contains(addressesToIgnore, ((Instruction)(ref current)).IP - (num2 - 1)); num2++) { if (LibCpp2IlMain.Binary.GetByteAtRawAddress(num - num2) == 204) { yield return ((Instruction)(ref current)).IP - (num2 - 1); break; } } } } } protected override ulong GetObjectIsInstFromSystemType() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst..."); Il2CppTypeDefinition type = LibCpp2IlReflection.GetType("Type", "System"); Il2CppMethodDefinition val = ((type == null) ? null : type.Methods?.FirstOrDefault((Func)((Il2CppMethodDefinition m) => m.Name == "IsInstanceOfType"))); if (val == null) { Logger.VerboseNewline("Type or method not found, aborting."); return 0uL; } Logger.Verbose($"IsInstanceOfType found at 0x{val.MethodPointer:X}..."); Instruction val2 = ((IEnumerable)X86Utils.GetMethodBodyAtVirtAddressNew(val.MethodPointer, peek: true)).LastOrDefault((Func)((Instruction i) => (int)((Instruction)(ref i)).Mnemonic == 59)); if ((int)((Instruction)(ref val2)).Mnemonic == 0) { Logger.VerboseNewline("Method does not match expected signature. Aborting."); return 0uL; } Logger.VerboseNewline($"Success. IsInst found at 0x{((Instruction)(ref val2)).NearBranchTarget:X}"); return ((Instruction)(ref val2)).NearBranchTarget; } protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) InstructionList methodBodyAtVirtAddressNew = X86Utils.GetMethodBodyAtVirtAddressNew(thunkPtr, peek: true); try { Mnemonic target = (Mnemonic)(prioritiseCall ? 59 : 308); Instruction val = ((IEnumerable)methodBodyAtVirtAddressNew).FirstOrDefault((Func)((Instruction i) => ((Instruction)(ref i)).Mnemonic == target)); if ((int)((Instruction)(ref val)).Mnemonic == 0) { target = (Mnemonic)(((int)target == 59) ? 308 : 59); val = ((IEnumerable)methodBodyAtVirtAddressNew).First((Instruction i) => ((Instruction)(ref i)).Mnemonic == target); } return ((Instruction)(ref val)).NearBranchTarget; } catch (Exception) { return 0uL; } } protected override int GetCallerCount(ulong toWhere) { return ((IEnumerable)DisassembleTextSection()).Count((Instruction i) => (int)((Instruction)(ref i)).Mnemonic == 308 || ((int)((Instruction)(ref i)).Mnemonic == 59 && ((Instruction)(ref i)).NearBranchTarget == toWhere)); } } } namespace Cpp2IL.Core.Graphs { public class Block { public List Predecessors = new List(); public List Successors = new List(); public List isilInstructions = new List(); public bool Visited; public BlockType BlockType { get; set; } = BlockType.Unknown; public int ID { get; set; } = -1; public bool Dirty { get; set; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Type: " + BlockType); stringBuilder.AppendLine(); foreach (InstructionSetIndependentInstruction isilInstruction in isilInstructions) { stringBuilder.AppendLine(isilInstruction.ToString()); } return stringBuilder.ToString(); } public void AddInstruction(InstructionSetIndependentInstruction instruction) { isilInstructions.Add(instruction); } public void CaculateBlockType() { if (isilInstructions.Count > 0) { switch (isilInstructions.Last().FlowControl) { case IsilFlowControl.UnconditionalJump: BlockType = BlockType.OneWay; break; case IsilFlowControl.ConditionalJump: BlockType = BlockType.TwoWay; break; case IsilFlowControl.IndexedJump: BlockType = BlockType.NWay; break; case IsilFlowControl.MethodCall: BlockType = BlockType.Call; break; case IsilFlowControl.MethodReturn: BlockType = BlockType.Return; break; case IsilFlowControl.Interrupt: BlockType = BlockType.Interrupt; break; case IsilFlowControl.Continue: BlockType = BlockType.Fall; break; default: BlockType = BlockType.Unknown; break; } } } } public enum BlockType : byte { OneWay, TwoWay, NWay, Call, Return, Fall, Unknown, Interrupt, Entry, Exit } public class ISILControlFlowGraph { private int idCounter; private Collection blockSet; private Block exitBlock; private Block entryBlock; public Block EntryBlock => entryBlock; public Block ExitBlock => exitBlock; public int Count => blockSet.Count; public Collection Blocks => blockSet; public ISILControlFlowGraph() { entryBlock = new Block { ID = idCounter++ }; entryBlock.BlockType = BlockType.Entry; exitBlock = new Block { ID = idCounter++ }; exitBlock.BlockType = BlockType.Exit; blockSet = new Collection { entryBlock, exitBlock }; } private bool TryGetTargetJumpInstructionIndex(InstructionSetIndependentInstruction instruction, out uint jumpInstructionIndex) { jumpInstructionIndex = 0u; try { jumpInstructionIndex = ((InstructionSetIndependentInstruction)instruction.Operands[0].Data).InstructionIndex; return true; } catch { } return false; } public void Build(List instructions) { if (instructions == null) { throw new ArgumentNullException("instructions"); } Block block = new Block { ID = idCounter++ }; AddNode(block); AddDirectedEdge(entryBlock, block); for (int i = 0; i < instructions.Count; i++) { bool flag = i == instructions.Count - 1; switch (instructions[i].FlowControl) { case IsilFlowControl.UnconditionalJump: block.AddInstruction(instructions[i]); if (!flag) { Block block4 = new Block { ID = idCounter++ }; AddNode(block4); if (TryGetTargetJumpInstructionIndex(instructions[i], out var _)) { block.Dirty = true; } else { AddDirectedEdge(block, exitBlock); } block.CaculateBlockType(); block = block4; } else { AddDirectedEdge(block, exitBlock); block.Dirty = true; } break; case IsilFlowControl.MethodCall: block.AddInstruction(instructions[i]); if (!flag) { Block block6 = new Block { ID = idCounter++ }; AddNode(block6); AddDirectedEdge(block, block6); block.CaculateBlockType(); block = block6; } else { AddDirectedEdge(block, exitBlock); block.CaculateBlockType(); } break; case IsilFlowControl.Continue: block.AddInstruction(instructions[i]); if (!flag) { } break; case IsilFlowControl.MethodReturn: block.AddInstruction(instructions[i]); if (!flag) { Block block5 = new Block { ID = idCounter++ }; AddNode(block5); AddDirectedEdge(block, exitBlock); block.CaculateBlockType(); block = block5; } else { AddDirectedEdge(block, exitBlock); block.CaculateBlockType(); } break; case IsilFlowControl.ConditionalJump: block.AddInstruction(instructions[i]); if (!flag) { Block block3 = new Block { ID = idCounter++ }; AddNode(block3); AddDirectedEdge(block, block3); block.CaculateBlockType(); block.Dirty = true; block = block3; } else { AddDirectedEdge(block, exitBlock); } break; case IsilFlowControl.Interrupt: { block.AddInstruction(instructions[i]); Block block2 = new Block { ID = idCounter++ }; AddNode(block2); AddDirectedEdge(block, exitBlock); block.CaculateBlockType(); block = block2; break; } case IsilFlowControl.IndexedJump: throw new NotImplementedException("Indirect branch not implemented currently"); default: throw new NotImplementedException($"{instructions[i]} {instructions[i].FlowControl}"); } } for (int j = 0; j < blockSet.Count; j++) { Block block7 = blockSet[j]; if (block7.Dirty) { FixBlock(block7); } } } public void CalculateDominations() { using IEnumerator enumerator = blockSet.GetEnumerator(); if (enumerator.MoveNext()) { _ = enumerator.Current; throw new NotImplementedException(); } } private void FixBlock(Block block, bool removeJmp = false) { if (block.BlockType == BlockType.Fall) { return; } InstructionSetIndependentInstruction instructionSetIndependentInstruction = block.isilInstructions.Last(); InstructionSetIndependentInstruction targetInstruction = instructionSetIndependentInstruction.Operands[0].Data as InstructionSetIndependentInstruction; Block block2 = FindNodeByInstruction(targetInstruction); if (block2 == null) { block.BlockType = BlockType.Call; return; } int index = block2.isilInstructions.FindIndex((InstructionSetIndependentInstruction instruction) => instruction == targetInstruction); Block to = SplitAndCreate(block2, index); AddDirectedEdge(block, to); block.Dirty = false; if (removeJmp) { block.isilInstructions.Remove(instructionSetIndependentInstruction); } } protected Block? FindNodeByInstruction(InstructionSetIndependentInstruction? instruction) { if (instruction == null) { return null; } for (int i = 0; i < blockSet.Count; i++) { Block block = blockSet[i]; for (int j = 0; j < block.isilInstructions.Count; j++) { if (block.isilInstructions[j] == instruction) { return block; } } } return null; } private Block SplitAndCreate(Block target, int index) { if (index < 0 || index >= target.isilInstructions.Count) { throw new ArgumentOutOfRangeException("index"); } if (index == 0) { return target; } Block block = new Block { ID = idCounter++ }; List range = target.isilInstructions.GetRange(index, target.isilInstructions.Count - index); target.isilInstructions.RemoveRange(index, target.isilInstructions.Count - index); block.isilInstructions.AddRange(range); block.BlockType = target.BlockType; target.BlockType = BlockType.Fall; block.Successors = target.Successors; if (target.Dirty) { block.Dirty = true; } target.Dirty = false; target.Successors = new List(); foreach (Block successor in block.Successors) { for (int i = 0; i < successor.Predecessors.Count; i++) { if (successor.Predecessors[i].ID == target.ID) { successor.Predecessors[i] = block; } } } AddNode(block); AddDirectedEdge(target, block); return block; } private void AddDirectedEdge(Block from, Block to) { from.Successors.Add(to); to.Predecessors.Add(from); } protected void AddNode(Block block) { blockSet.Add(block); } } } namespace Cpp2IL.Core.Graphs.Processors { internal class CallProcessor : IBlockProcessor { public void Process(MethodAnalysisContext methodAnalysisContext, Block block) { if (block.BlockType != BlockType.Call) { return; } List isilInstructions = block.isilInstructions; InstructionSetIndependentInstruction instructionSetIndependentInstruction = isilInstructions[isilInstructions.Count - 1]; if (instructionSetIndependentInstruction == null || instructionSetIndependentInstruction.OpCode != InstructionSetIndependentOpCode.Call || instructionSetIndependentInstruction.Operands.Length == 0) { return; } InstructionSetIndependentOperand instructionSetIndependentOperand = instructionSetIndependentInstruction.Operands[0]; if (instructionSetIndependentOperand.Type != InstructionSetIndependentOperand.OperandType.Immediate) { return; } ulong num = (ulong)(object)((IsilImmediateOperand)instructionSetIndependentOperand.Data).Value; BaseKeyFunctionAddresses orCreateKeyFunctionAddresses = methodAnalysisContext.AppContext.GetOrCreateKeyFunctionAddresses(); List value; if (orCreateKeyFunctionAddresses.IsKeyFunctionAddress(num)) { HandleKeyFunction(methodAnalysisContext.AppContext, instructionSetIndependentInstruction, num, orCreateKeyFunctionAddresses); } else if (methodAnalysisContext.AppContext.MethodsByAddress.TryGetValue(num, out value) && value != null && value.Count == 1) { MethodAnalysisContext methodAnalysisContext2 = value[0]; if (methodAnalysisContext2 != null) { instructionSetIndependentInstruction.Operands[0] = InstructionSetIndependentOperand.MakeMethodReference(methodAnalysisContext2); } } } private void HandleKeyFunction(ApplicationAnalysisContext appContext, InstructionSetIndependentInstruction instruction, ulong target, BaseKeyFunctionAddresses kFA) { string text = ""; if (target == kFA.il2cpp_codegen_initialize_method || target == kFA.il2cpp_codegen_initialize_runtime_metadata) { text = ((!(appContext.MetadataVersion < 27f)) ? "il2cpp_codegen_initialize_runtime_metadata" : "il2cpp_codegen_initialize_method"); } else if (target == kFA.il2cpp_vm_metadatacache_initializemethodmetadata) { text = "il2cpp_vm_metadatacache_initializemethodmetadata"; } else if (target == kFA.il2cpp_runtime_class_init_export) { text = "il2cpp_runtime_class_init_export"; } else if (target == kFA.il2cpp_runtime_class_init_actual) { text = "il2cpp_runtime_class_init_actual"; } else if (target == kFA.il2cpp_object_new) { text = "il2cpp_vm_object_new"; } else if (target == kFA.il2cpp_codegen_object_new) { text = "il2cpp_codegen_object_new"; } else if (target == kFA.il2cpp_array_new_specific) { text = "il2cpp_array_new_specific"; } else if (target == kFA.il2cpp_vm_array_new_specific) { text = "il2cpp_vm_array_new_specific"; } else if (target == kFA.SzArrayNew) { text = "SzArrayNew"; } else if (target == kFA.il2cpp_type_get_object) { text = "il2cpp_type_get_object"; } else if (target == kFA.il2cpp_vm_reflection_get_type_object) { text = "il2cpp_vm_reflection_get_type_object"; } else if (target == kFA.il2cpp_resolve_icall) { text = "il2cpp_resolve_icall"; } else if (target == kFA.InternalCalls_Resolve) { text = "InternalCalls_Resolve"; } else if (target == kFA.il2cpp_string_new) { text = "il2cpp_string_new"; } else if (target == kFA.il2cpp_vm_string_new) { text = "il2cpp_vm_string_new"; } else if (target == kFA.il2cpp_string_new_wrapper) { text = "il2cpp_string_new_wrapper"; } else if (target == kFA.il2cpp_vm_string_newWrapper) { text = "il2cpp_vm_string_newWrapper"; } else if (target == kFA.il2cpp_codegen_string_new_wrapper) { text = "il2cpp_codegen_string_new_wrapper"; } else if (target == kFA.il2cpp_value_box) { text = "il2cpp_value_box"; } else if (target == kFA.il2cpp_vm_object_box) { text = "il2cpp_vm_object_box"; } else if (target == kFA.il2cpp_object_unbox) { text = "il2cpp_object_unbox"; } else if (target == kFA.il2cpp_vm_object_unbox) { text = "il2cpp_vm_object_unbox"; } else if (target == kFA.il2cpp_raise_exception) { text = "il2cpp_raise_exception"; } else if (target == kFA.il2cpp_vm_exception_raise) { text = "il2cpp_vm_exception_raise"; } else if (target == kFA.il2cpp_codegen_raise_exception) { text = "il2cpp_codegen_raise_exception"; } else if (target == kFA.il2cpp_vm_object_is_inst) { text = "il2cpp_vm_object_is_inst"; } else if (target == kFA.AddrPInvokeLookup) { text = "AddrPInvokeLookup"; } if (text != "") { instruction.Operands[0] = InstructionSetIndependentOperand.MakeImmediate(text); } } } internal interface IBlockProcessor { void Process(MethodAnalysisContext methodAnalysisContext, Block block); } internal class MetadataProcessor : IBlockProcessor { public void Process(MethodAnalysisContext methodAnalysisContext, Block block) { foreach (InstructionSetIndependentInstruction isilInstruction in block.isilInstructions) { if (isilInstruction.OpCode != InstructionSetIndependentOpCode.Move || isilInstruction.Operands[0].Type != InstructionSetIndependentOperand.OperandType.Register || isilInstruction.Operands[1].Type != InstructionSetIndependentOperand.OperandType.Memory) { continue; } IsilMemoryOperand isilMemoryOperand = (IsilMemoryOperand)(object)isilInstruction.Operands[1].Data; if (isilMemoryOperand.Base.HasValue || isilMemoryOperand.Index.HasValue || isilMemoryOperand.Scale != 0) { continue; } string literalByAddress = LibCpp2IlMain.GetLiteralByAddress((ulong)isilMemoryOperand.Addend); if (literalByAddress == null) { Il2CppTypeReflectionData typeGlobalByAddress = LibCpp2IlMain.GetTypeGlobalByAddress((ulong)isilMemoryOperand.Addend); if (typeGlobalByAddress != null && methodAnalysisContext.DeclaringType != null) { TypeAnalysisContext typeAnalysisContext = typeGlobalByAddress.ToContext(methodAnalysisContext.DeclaringType.DeclaringAssembly); if (typeAnalysisContext != null) { isilInstruction.Operands[1] = InstructionSetIndependentOperand.MakeTypeMetadataUsage(typeAnalysisContext); } } } else { isilInstruction.Operands[1] = InstructionSetIndependentOperand.MakeImmediate(literalByAddress); } } } } } namespace Cpp2IL.Core.Extensions { internal static class AccessibilityExtensions { public static bool IsAccessibleTo(this TypeAnalysisContext referenceType, TypeAnalysisContext referencingType) { TypeAnalysisContext referencingType2 = referencingType; if (referenceType == referencingType2) { return true; } TypeAnalysisContext[] array = referenceType.GetTypeAndDeclaringTypes().ToArray(); int num = array.IndexOf((TypeAnalysisContext t) => referencingType2.IsAssignableTo(t)); int num2 = Array.IndexOf(array, referencingType2); if (referenceType.DeclaringAssembly == referencingType2.DeclaringAssembly) { for (int i = 0; i < array.Length; i++) { if (i == num2 - 1) { continue; } if (i == num - 1) { if (array[i].GetVisibility() == TypeAttributes.NestedPrivate) { return false; } continue; } TypeAttributes visibility = array[i].GetVisibility(); if (((uint)(visibility - 3) <= 1u || visibility == TypeAttributes.NestedFamANDAssem) ? true : false) { return false; } } return true; } if (referenceType.DeclaringAssembly.Definition.IsDependencyOf(referencingType2.DeclaringAssembly.Definition)) { for (int j = 0; j < array.Length; j++) { if (j == num2 - 1) { continue; } if (j == num - 1) { bool flag; switch (array[j].GetVisibility()) { case TypeAttributes.NotPublic: case TypeAttributes.NestedPrivate: case TypeAttributes.NestedAssembly: case TypeAttributes.NestedFamANDAssem: flag = true; break; default: flag = false; break; } if (flag) { return false; } } else { TypeAttributes visibility = array[j].GetVisibility(); if ((visibility == TypeAttributes.NotPublic || (uint)(visibility - 3) <= 4u) ? true : false) { return false; } } } return true; } return false; } public static bool IsAssignableTo(this TypeAnalysisContext derivedType, TypeAnalysisContext baseType) { if (baseType.IsInterface) { return derivedType.IsAssignableToInterface(baseType); } return derivedType.InheritsFrom(baseType); } private static int IndexOf(this IEnumerable enumerable, Func selector) { int num = 0; foreach (T item in enumerable) { if (selector(item)) { return num; } num++; } return -1; } private static IEnumerable GetTypeAndDeclaringTypes(this TypeAnalysisContext type) { for (TypeAnalysisContext current = type; current != null; current = current.DeclaringType) { yield return current; } } private static TypeAttributes GetVisibility(this TypeAnalysisContext type) { return type.TypeAttributes & TypeAttributes.VisibilityMask; } private static bool InheritsFrom(this TypeAnalysisContext derivedType, TypeAnalysisContext baseType) { for (TypeAnalysisContext typeAnalysisContext = derivedType; typeAnalysisContext != null; typeAnalysisContext = typeAnalysisContext.BaseType) { if (typeAnalysisContext == baseType) { return true; } } return false; } private static bool IsAssignableToInterface(this TypeAnalysisContext derivedType, TypeAnalysisContext baseInterface) { if (derivedType == baseInterface) { return true; } TypeAnalysisContext[] interfaceContexts = derivedType.InterfaceContexts; for (int i = 0; i < interfaceContexts.Length; i++) { if (interfaceContexts[i].IsAssignableToInterface(baseInterface)) { return true; } } return false; } private static bool IsDependencyOf(this Il2CppAssemblyDefinition referencedAssembly, Il2CppAssemblyDefinition referencingAssembly) { if (Array.IndexOf(referencingAssembly.ReferencedAssemblies, referencedAssembly) >= 0) { return true; } if (Array.IndexOf(referencedAssembly.ReferencedAssemblies, referencingAssembly) >= 0) { return false; } return referencingAssembly.CollectAllDependencies().Contains(referencedAssembly); } private static HashSet CollectAllDependencies(this Il2CppAssemblyDefinition referencingAssembly) { HashSet hashSet = new HashSet { referencingAssembly }; referencingAssembly.CollectAllDependencies(hashSet); return hashSet; } private static void CollectAllDependencies(this Il2CppAssemblyDefinition referencingAssembly, HashSet dependencies) { Il2CppAssemblyDefinition[] referencedAssemblies = referencingAssembly.ReferencedAssemblies; foreach (Il2CppAssemblyDefinition val in referencedAssemblies) { if (dependencies.Add(val)) { val.CollectAllDependencies(dependencies); } } } } internal static class ArrayExtensions { public static bool Contains(this T[] array, T item) { return Array.IndexOf(array, item) >= 0; } } internal static class EnumerableExtensions { public class MemoryEnumerable : IEnumerable, IEnumerable { [CompilerGenerated] private Memory P; public MemoryEnumerable(Memory memory) { P = memory; base..ctor(); } public IEnumerator GetEnumerator() { return new MemoryEnumerator(P); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class MemoryEnumerator : IEnumerator, IEnumerator, IDisposable { [CompilerGenerated] private Memory P; private int _index; public T Current => P.Span[_index]; object? IEnumerator.Current => Current; public MemoryEnumerator(Memory memory) { P = memory; _index = -1; base..ctor(); } public bool MoveNext() { _index++; return _index < P.Length; } public void Reset() { _index = -1; } public void Dispose() { } } public static IEnumerable MaybeAppend(this IEnumerable enumerable, T? item) where T : struct { if (item.HasValue) { return enumerable.Append(item.Value); } return enumerable; } public static MemoryEnumerable AsEnumerable(this Memory memory) { return new MemoryEnumerable(memory); } public static MemoryEnumerator GetEnumerator(this Memory memory) { return new MemoryEnumerator(memory); } } public static class MiscExtensions { public static InstructionSetIndependentOperand MakeIndependent(this Register reg) { return InstructionSetIndependentOperand.MakeRegister(((object)(Register)(ref reg)).ToString().ToLower()); } public static ulong GetImmediateSafe(this Instruction instruction, int op) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) if (!((Instruction)(ref instruction)).GetOpKind(op).IsImmediate()) { return 0uL; } return ((Instruction)(ref instruction)).GetImmediate(op); } public static bool IsJump(this Mnemonic mnemonic) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)mnemonic >= 297) { if ((int)mnemonic <= 317) { goto IL_0017; } } else if ((int)mnemonic == 59) { goto IL_0017; } return false; IL_0017: return true; } public static bool IsConditionalJump(this Mnemonic mnemonic) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 if (mnemonic.IsJump() && (int)mnemonic != 308) { return (int)mnemonic != 59; } return false; } public static ArmRegister? RegisterSafe(this ArmOperand operand) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)operand.Type == 1) { return operand.Register; } return null; } public static bool IsImmediate(this ArmOperand operand) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 ArmOperandType type = operand.Type; if ((int)type == 2 || type - 64 <= 1) { return true; } return false; } public static int ImmediateSafe(this ArmOperand operand) { if (!operand.IsImmediate()) { return 0; } return operand.Immediate; } private static ArmOperand? MemoryOperand(ArmInstruction instruction) { return ((IEnumerable)((Instruction)(object)instruction).Details.Operands).FirstOrDefault((Func)((ArmOperand a) => (int)a.Type == 3)); } public static ArmRegister? MemoryBase(this ArmInstruction instruction) { ArmOperand? obj = MemoryOperand(instruction); if (obj == null) { return null; } return obj.Memory.Base; } public static ArmRegister? MemoryIndex(this ArmInstruction instruction) { ArmOperand? obj = MemoryOperand(instruction); if (obj == null) { return null; } return obj.Memory.Index; } public static int MemoryOffset(this ArmInstruction instruction) { ArmOperand? obj = MemoryOperand(instruction); if (obj == null) { return 0; } return obj.Memory.Displacement; } public static Arm64Register? RegisterSafe(this Arm64Operand operand) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)operand.Type == 1) { return operand.Register; } return null; } public static bool IsImmediate(this Arm64Operand operand) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 Arm64OperandType type = operand.Type; if ((int)type == 2 || (int)type == 64) { return true; } return false; } public static long ImmediateSafe(this Arm64Operand operand) { if (!operand.IsImmediate()) { return 0L; } return operand.Immediate; } internal static Arm64Operand? MemoryOperand(this Arm64Instruction instruction) { return ((IEnumerable)((Instruction)(object)instruction).Details.Operands).FirstOrDefault((Func)((Arm64Operand a) => (int)a.Type == 3)); } public static Arm64Register? MemoryBase(this Arm64Instruction instruction) { Arm64Operand? obj = instruction.MemoryOperand(); if (obj == null) { return null; } return obj.Memory.Base; } public static Arm64Register? MemoryIndex(this Arm64Instruction instruction) { Arm64Operand? obj = instruction.MemoryOperand(); if (obj == null) { return null; } return obj.Memory.Index; } public static int MemoryOffset(this Arm64Instruction instruction) { Arm64Operand? obj = instruction.MemoryOperand(); if (obj == null) { return 0; } return obj.Memory.Displacement; } public static bool IsConditionalMove(this Instruction instruction) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown Mnemonic mnemonic = ((Instruction)(ref instruction)).Mnemonic; switch (mnemonic - 77) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 12: case 15: return true; default: return false; } } public static Stack Clone(this Stack original) { T[] array = new T[original.Count]; original.CopyTo(array, 0); Array.Reverse(array); return new Stack(array); } public static List Clone(this List original) { T[] array = new T[original.Count]; original.CopyTo(array, 0); T[] array2 = array; List list = new List(array2.Length); list.AddRange(array2); return list; } public static Dictionary Clone(this Dictionary original) where T1 : notnull { return new Dictionary(original); } public static T[] SubArray(this T[] data, int index, int length) { return data.SubArray(index..(index + length)); } public static T RemoveAndReturn(this List data, int index) { T result = data[index]; data.RemoveAt(index); return result; } public static IEnumerable Repeat(this T t, int count) { for (int i = 0; i < count; i++) { yield return t; } } public static string Repeat(this string source, int count) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < count; i++) { stringBuilder.Append(source); } return stringBuilder.ToString(); } internal static T[] SubArray(this T[] source, Range range) { if (!range.Start.IsFromEnd && !range.End.IsFromEnd && range.Start.Value > range.End.Value) { throw new Exception($"Range {range} - Start must be less than end, when both are fixed offsets"); } (int Offset, int Length) offsetAndLength = range.GetOffsetAndLength(source.Length); int item = offsetAndLength.Offset; int item2 = offsetAndLength.Length; T[] array = new T[item2]; Array.Copy(source, item, array, 0, item2); return array; } public static T? GetValueSafely(this T[] arr, int i) where T : class { if (i >= arr.Length) { return null; } return arr[i]; } public static bool IsImmediate(this OpKind opKind) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)opKind >= 6) { return (int)opKind <= 14; } return false; } public static void TrimEndWhile(this List instructions, Func predicate) { int num = instructions.Count - 1; while (num >= 0 && predicate(instructions[num])) { num--; } int num2 = instructions.Count - 1 - num; if (num2 > 0) { instructions.RemoveRange(num, num2); } } public static IEnumerable Peek(this IEnumerable enumerable, Action action) { Action action2 = action; return enumerable.Select(delegate(T t) { action2(t); return t; }); } public unsafe static uint ReadUInt(this Span span, int start) { if (start >= span.Length) { throw new ArgumentOutOfRangeException("start", $"start=[{start}], mem.Length=[{span.Length}]"); } fixed (byte* ptr = &span[start]) { return *(uint*)ptr; } } public static bool BitsAreEqual(this BitArray first, BitArray second) { if (first.Count != second.Count) { return false; } bool flag = false; for (int i = 0; i < first.Count; i++) { if (flag) { break; } flag = first.Get(i) != second.Get(i); } return !flag; } } public static class StreamExtensions { public static uint ReadUnityCompressedUint(this Stream stream) { if (stream.Position == stream.Length) { throw new EndOfStreamException(); } int num = stream.ReadByte(); if (num < 128) { return (uint)num; } switch (num) { case 240: { byte[] array = new byte[4]; stream.Read(array, 0, 4); return BitConverter.ToUInt32(array, 0); } case 255: return uint.MaxValue; case 254: return 4294967294u; default: if ((num & 0xC0) == 192) { return (uint)(((num & 0xFFFFFF3Fu) << 24) | (uint)(stream.ReadByte() << 16) | (uint)(stream.ReadByte() << 8) | (uint)stream.ReadByte()); } if ((num & 0x80) == 128) { return (uint)(((num & 0xFFFFFF7Fu) << 8) | (uint)stream.ReadByte()); } throw new Exception($"How did we even get here? Invalid compressed int first byte {num}"); } } public static int ReadUnityCompressedInt(this Stream stream) { uint num = stream.ReadUnityCompressedUint(); if (num == uint.MaxValue) { return int.MinValue; } bool num2 = (num & 1) == 1; num >>= 1; if (num2) { return (int)(0 - (num + 1)); } return (int)num; } public static string ReadUnicodeString(this BinaryReader reader) { List list = new List(); bool flag = true; bool flag2 = false; while (flag) { byte b = reader.ReadByte(); if (b == 0 && flag2) { flag = false; } flag2 = b == 0; list.Add(b); } list.Add(reader.ReadByte()); return Encoding.Unicode.GetString(list.ToArray()).TrimEnd('\0'); } public static byte[] ReadBytes(this Stream stream) { using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } public static byte[] ReadBytes(this ZipArchiveEntry entry) { return entry.Open().ReadBytes(); } } public static class StringExtensions { public static string EscapeString(this string str) { return str.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r") .Replace("\t", "\\t") .Replace("\0", "\\0"); } } } namespace Cpp2IL.Core.Exceptions { public class DllSaveException : Exception { public string FullPath { get; } public Exception Cause { get; } public DllSaveException(string fullPath, Exception cause) { FullPath = fullPath; Cause = cause; base..ctor("Fatal Exception writing DLL " + fullPath, cause); } } public class InstructionSetHandlerNotRegisteredException : Exception { public InstructionSetHandlerNotRegisteredException(InstructionSetId instructionSetId) : base("Instruction set handler not registered for instruction set " + instructionSetId.Name + ". Please register an instruction set handler using InstructionSetRegistry.RegisterInstructionSet(id)") { } } public class LibCpp2ILInitializationException : Exception { public LibCpp2ILInitializationException(string message, Exception innerException) : base(message, innerException) { } } public class LibraryNotInitializedException : Exception { public override string Message => "This function requires LibCpp2IL to be initialized - there is a function to do this in Cpp2IlApi."; } public class NodeConditionCalculationException : Exception { public NodeConditionCalculationException(string message) : base(message) { } } public class UnsupportedInstructionSetException : Exception { public override string Message => $"This action is not supported on the {LibCpp2IlMain.Binary?.InstructionSetId} instruction set yet. If running the CLI, try adding the --skip-analysis argument."; } } namespace Cpp2IL.Core.Attributes { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterCpp2IlPluginAttribute : Attribute { [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] public Type PluginType { get; } public RegisterCpp2IlPluginAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type pluginType) { if (!typeof(Cpp2IlPlugin).IsAssignableFrom(pluginType)) { throw new ArgumentException("Plugin type to register must extend Cpp2IlPlugin", "pluginType"); } if ((object)pluginType.GetConstructor(Type.EmptyTypes) == null) { throw new ArgumentException("Plugin type to register must have a public, zero-argument constructor.", "pluginType"); } PluginType = pluginType; } } } namespace Cpp2IL.Core.Api { public abstract class Cpp2IlInstructionSet { public abstract Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator); public virtual ulong GetPointerForMethod(MethodAnalysisContext context) { return context.UnderlyingPointer; } public abstract List GetIsilFromMethod(MethodAnalysisContext context); public abstract BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance(); public abstract string PrintAssembly(MethodAnalysisContext context); } public abstract class Cpp2IlOutputFormat { public abstract string OutputFormatId { get; } public abstract string OutputFormatName { get; } public virtual void OnOutputFormatSelected() { } public abstract void DoOutput(ApplicationAnalysisContext context, string outputRoot); } public abstract class Cpp2IlPlugin { protected readonly PluginLogger Logger; private readonly List temporaryFilePaths = new List(); public abstract string Name { get; } public abstract string Description { get; } protected Cpp2IlPlugin() { Logger = new PluginLogger(this); } public string GetTemporaryFilePath() { string tempFileName = Path.GetTempFileName(); File.Delete(tempFileName); temporaryFilePaths.Add(tempFileName); return tempFileName; } public abstract void OnLoad(); protected void RegisterBinaryFormat(string name, Func isValid, Func factory) where T : Il2CppBinary { LibCpp2IlBinaryRegistry.Register(name, Name, isValid, factory); } protected void RegisterBinaryRegistrationFuncFallbackHandler(RegistrationStructLocationFailureHandler handler) { Il2CppBinary.OnRegistrationStructLocationFailure += handler; } public virtual bool HandleGamePath(string gamePath, ref Cpp2IlRuntimeArgs args) { return false; } internal void CallOnFinish() { foreach (string temporaryFilePath in temporaryFilePaths) { File.Delete(temporaryFilePath); } OnFinish(); } protected virtual void OnFinish() { } } public abstract class Cpp2IlProcessingLayer { public abstract string Name { get; } public abstract string Id { get; } public virtual void PreProcess(ApplicationAnalysisContext context, List layers) { } public abstract void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null); } public interface ICSharpSourceToken { string GetCSharpSourceString(); } public static class InstructionSetRegistry { private static Dictionary _registeredSets = new Dictionary(); public static void RegisterInstructionSet(InstructionSetId forId) where T : Cpp2IlInstructionSet, new() { _registeredSets.Add(forId, new T()); } public static Cpp2IlInstructionSet GetInstructionSet(InstructionSetId forId) { return _registeredSets[forId]; } } public static class OutputFormatRegistry { private static readonly Dictionary _formatsById = new Dictionary(); public static IReadOnlyList AllOutputFormats => _formatsById.Values.ToList(); public static void Register() where T : Cpp2IlOutputFormat, new() { T val = new T(); _formatsById.Add(val.OutputFormatId, val); } public static Cpp2IlOutputFormat GetFormat(string formatId) { if (!_formatsById.TryGetValue(formatId, out Cpp2IlOutputFormat value)) { throw new ArgumentException("No output format registered with id '" + formatId + "'"); } return value; } } public sealed class PluginLogger { private readonly Cpp2IlPlugin _plugin; private readonly string _name; internal PluginLogger(Cpp2IlPlugin plugin) { _plugin = plugin; _name = "Plugin: " + plugin.Name; } public void VerboseNewline(string message, string source = "Program") { Logger.VerboseNewline(message ?? "", _name); } public void Verbose(string message, string source = "Program") { Logger.Verbose(message ?? "", _name); } public void InfoNewline(string message, string source = "Program") { Logger.InfoNewline(message ?? "", _name); } public void Info(string message, string source = "Program") { Logger.Info(message ?? "", _name); } public void WarnNewline(string message, string source = "Program") { Logger.WarnNewline(message ?? "", _name); } public void Warn(string message, string source = "Program") { Logger.Warn(message ?? "", _name); } public void ErrorNewline(string message, string source = "Program") { Logger.ErrorNewline(message ?? "", _name); } public void Error(string message, string source = "Program") { Logger.Error(message ?? "", _name); } } public static class ProcessingLayerRegistry { private static readonly Dictionary _processingLayersById = new Dictionary(); public static IReadOnlyList AllProcessingLayers => _processingLayersById.Values.ToList(); public static void Register() where T : Cpp2IlProcessingLayer, new() { T val = new T(); _processingLayersById.Add(val.Id, val); } public static Cpp2IlProcessingLayer GetById(string id) { if (!_processingLayersById.TryGetValue(id, out Cpp2IlProcessingLayer value)) { throw new ArgumentException("No processing layer with id " + id + " registered"); } return value; } } } internal sealed class <>z__ReadOnlyArray : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => _items.Length; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Length; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object? value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object? value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object? value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object? value) { throw new NotSupportedException(); } void IList.Remove(object? value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return ((ICollection)_items).Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { ((ICollection)_items).CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return ((IList)_items).IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } }