using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; 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.DotNet.Signatures.Types; using AsmResolver.PE; using AsmResolver.PE.Builder; using AsmResolver.PE.DotNet.Builder; using AsmResolver.PE.DotNet.Cil; using AsmResolver.PE.DotNet.Metadata.Tables.Rows; using AssetRipper.VersionUtilities; 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.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 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: RegisterCpp2IlPlugin(typeof(Cpp2IlCorePlugin))] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [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-development.866+f87ccd1.f87ccd188ec032cbba27763bf10ba43bb25eb4e8")] [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] 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; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] 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)] internal sealed class RequiredMemberAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] 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)] internal sealed class UnscopedRefAttribute : Attribute { } } namespace Cpp2IL.Core { public static class Cpp2IlApi { public static ApplicationAnalysisContext? CurrentAppContext; 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); } private 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"); } private static void ResetInternalState() { SharedState.Clear(); MiscUtils.Reset(); LibCpp2IlMain.Reset(); } private static bool IsLibInitialized() { if (LibCpp2IlMain.Binary != null) { return LibCpp2IlMain.TheMetadata != null; } return false; } } public class Cpp2IlCorePlugin : Cpp2IlPlugin { 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_NEW_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(); Logger.VerboseNewline("\tRegistering built-in processing layers", "Core Plugin"); 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(); 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 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; } } public static uint FirstItemOffset = (((ClassReadingBinaryReader)LibCpp2IlMain.Binary).is32Bit ? 16u : 32u); public static readonly List UsefulOffsets = new List { 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; } } 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 { 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; } } public const int X86_SLOT_OFFSET = 0; public const int X86_64_SLOT_OFFSET = 72; public static readonly List UsefulOffsets = new List { 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; } } public const int X86_KLASS_OFFSET = 0; public const int X86_64_KLASS_OFFSET = 24; public static readonly List UsefulOffsets = new List { 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 AccessibilityUtils { 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 (visibility == TypeAttributes.NestedPrivate || visibility == TypeAttributes.NestedFamily || visibility == TypeAttributes.NestedFamANDAssem) { 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) { TypeAttributes visibility = array[j].GetVisibility(); if (visibility == TypeAttributes.NotPublic || visibility == TypeAttributes.NestedPrivate || visibility == TypeAttributes.NestedAssembly || visibility == TypeAttributes.NestedFamANDAssem) { return false; } } else { TypeAttributes visibility = array[j].GetVisibility(); if (visibility == TypeAttributes.NotPublic || visibility == TypeAttributes.NestedPrivate || visibility == TypeAttributes.NestedFamily || visibility == TypeAttributes.NestedAssembly || visibility == TypeAttributes.NestedFamANDAssem || visibility == TypeAttributes.VisibilityMask) { 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); } } } } 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: Invalid comparison between Unknown and I4 //IL_00c1: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Invalid comparison between Unknown and I4 //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Invalid comparison between Unknown and I4 //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Invalid comparison between Unknown and I4 //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Invalid comparison between Unknown and I4 //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Invalid comparison between Unknown and I4 //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Invalid comparison between Unknown and I4 //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: 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_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Invalid comparison between Unknown and I4 //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Invalid comparison between Unknown and I4 //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Invalid comparison between Unknown and I4 //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Invalid comparison between Unknown and I4 //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected I4, but got Unknown //IL_018d: 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_014f: Invalid comparison between Unknown and I4 //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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) 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 ((int)registerId == 6 || (int)registerId == 7) { 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"; }) && (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"; }) && (count == -1 || list.Count < count)) { list.AddRange(((CapstoneDisassembler)(object)_armDisassembler).Iterate(rawBinaryContent.SubArray(num3..(num3 + 4)), (long)virtAddress)); virtAddress += 4; num3 += 4; } return list; } } internal static class AttributeInjectionUtils { internal 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); } internal 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])); } internal 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])); } internal 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])); } 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); } } internal static void AddZeroParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor) { AnalyzedCustomAttribute item = new AnalyzedCustomAttribute(constructor); customAttributeHolder.CustomAttributes.Add(item); } internal static void AddOneParameterAttribute(HasCustomAttributes customAttributeHolder, (MethodAnalysisContext, FieldAnalysisContext) attributeInfo, object fieldValue) { AddOneParameterAttribute(customAttributeHolder, attributeInfo.Item1, attributeInfo.Item2, fieldValue); } internal 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); } internal static void AddTwoParameterAttribute(HasCustomAttributes customAttributeHolder, (MethodAnalysisContext, FieldAnalysisContext, FieldAnalysisContext) attributeInfo, object fieldValue1, object fieldValue2) { AddTwoParameterAttribute(customAttributeHolder, attributeInfo.Item1, attributeInfo.Item2, fieldValue1, attributeInfo.Item3, fieldValue2); } internal 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); } 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) { Il2CppType val = (Il2CppType)((fieldValue is Il2CppType) ? fieldValue : null); if (val == null) { if (!(fieldValue is TypeAnalysisContext type)) { if (fieldValue is IConvertible value) { return new CustomAttributePrimitiveParameter(value, owner, CustomAttributeParameterKind.Field, index); } throw new NotSupportedException(); } return new InjectedCustomAttributeTypeParameter(type, owner, CustomAttributeParameterKind.Field, index); } return new CustomAttributeTypeParameter(val, owner, CustomAttributeParameterKind.Field, 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) { StringBuilder stringBuilder = new StringBuilder(); MethodAttributes attributes = method.Definition.Attributes; 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 (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); } stringBuilder.AppendLine(customAttribute.ToString()); } } return stringBuilder.ToString(); } public static string GetTypeName(string originalName) { if (originalName.Contains("`")) { return originalName.Remove(originalName.IndexOf('`'), 2); } 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 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_002a: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_001e: 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: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 //IL_007e: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Invalid comparison between Unknown and I4 //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 if (type == null) { return null; } if (Il2CppTypeEnumExtensions.IsIl2CppPrimitive(type.Type)) { return context.AppContext.SystemTypes.GetPrimitive(type.Type); } Il2CppTypeEnum type2 = type.Type; if ((int)type2 == 18 || (int)type2 == 17) { return context.AppContext.ResolveContextForType(type.AsClass()) ?? throw new Exception("Could not resolve type context for type " + type.AsClass().FullName); } if ((int)type.Type == 21) { return new GenericInstanceTypeAnalysisContext(type, context); } type2 = type.Type; if ((int)type2 == 16 || (int)type2 == 15 || (int)type2 == 29 || (int)type2 == 20) { return new WrappedTypeAnalysisContext(type, context); } return new GenericParameterTypeAnalysisContext(type, context); } } public static class MiscUtils { private static List? _allKnownFunctionStarts; private static Dictionary _primitiveSizes = new Dictionary(); public static readonly List InvalidPathChars = new List { '<', '>', ':', '"', '/', '\\', '|', '?', '*' }; 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; } public static IConvertible ReinterpretBytes(IConvertible original, Type desired) { if ((object)desired == null) { throw new ArgumentNullException("desired", "Destination type is null"); } byte[] array = RawBytes(original); if (!typeof(IConvertible).IsAssignableFrom(desired)) { throw new Exception($"ReinterpretBytes: Desired type, {desired}, does not implement IConvertible"); } int num = LibCpp2ILUtils.VersionAwareSizeOf(desired, false, true); if (num > array.Length) { array = ((byte)0).Repeat(num - array.Length).Concat(array).ToArray(); } if (desired == typeof(bool)) { return BitConverter.ToBoolean(array, 0); } if (desired == typeof(byte)) { return array[0]; } if (desired == typeof(char)) { return BitConverter.ToChar(array, 0); } if (desired == typeof(sbyte)) { return (sbyte)array[0]; } if (desired == typeof(ushort)) { return BitConverter.ToUInt16(array, 0); } if (desired == typeof(short)) { return BitConverter.ToInt16(array, 0); } if (desired == typeof(uint)) { return BitConverter.ToUInt32(array, 0); } if (desired == typeof(int)) { return BitConverter.ToInt32(array, 0); } if (desired == typeof(ulong)) { return BitConverter.ToUInt64(array, 0); } if (desired == typeof(long)) { return BitConverter.ToInt64(array, 0); } if (desired == typeof(float)) { return BitConverter.ToSingle(array, 0); } if (desired == typeof(double)) { return BitConverter.ToDouble(array, 0); } throw new Exception($"ReinterpretBytes: Cannot convert byte array back to a type of {desired}"); } 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; } return num3; } 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 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 Arm64DisassemblyResult GetArm64MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) { //IL_00b5: 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_0059: 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_008c: 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) 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); Arm64DisassemblyResult val = default(Arm64DisassemblyResult); ((Arm64DisassemblyResult)(ref val))..ctor(); while ((count == -1 || val.Instructions.Count < count) && !val.Instructions.Any((Arm64Instruction i) => (int)((Arm64Instruction)(ref i)).Mnemonic == 12)) { val = Disassemble(bytes, virtAddress); bytes = rawBinaryContent.AsSpan(start, bytes.Length + 4); } return val; } private static Arm64DisassemblyResult Disassemble(Span bytes, ulong virtAddress) { //IL_000a: 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_0059: Unknown result type (might be due to invalid IL or missing references) try { return Disassembler.Disassemble((ReadOnlySpan)bytes, virtAddress, true, false, true); } 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 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 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 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; 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++; } 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 void ConfigureHierarchy(AssemblyAnalysisContext asmCtx) { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown foreach (TypeAnalysisContext type in asmCtx.Types) { if (type.Name == "") { 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown object obj; if (!(e is CustomAttributePrimitiveParameter customAttributePrimitiveParameter)) { if (!(e is CustomAttributeEnumParameter customAttributeEnumParameter)) { if (!(e is BaseCustomAttributeTypeParameter baseCustomAttributeTypeParameter)) { throw new Exception("Not supported array element type: " + e.GetType().FullName); } obj = baseCustomAttributeTypeParameter.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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown Il2CppType il2CppType = (Il2CppType)(arrayParameter.Kind switch { CustomAttributeParameterKind.ConstructorParam => arrayParameter.Owner.Constructor.Parameters[arrayParameter.Index].ParameterType, CustomAttributeParameterKind.Property => arrayParameter.Owner.Properties[arrayParameter.Index].Property.Definition.RawPropertyType, CustomAttributeParameterKind.Field => arrayParameter.Owner.Fields[arrayParameter.Index].Field.FieldType, 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), }); return new CustomAttributeArgument(AsmResolverUtils.GetTypeSignatureFromIl2CppType(parentAssembly.ManifestModule, il2CppType)) { 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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.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 (type.Name == "") { 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 (!(type.Name == "")) { 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown foreach (FieldAnalysisContext field in typeContext.Fields) { Il2CppFieldReflectionData backingData = field.BackingData; TypeSignature val = importer.ImportTypeSignature(AsmResolverUtils.GetTypeSignatureFromIl2CppType(importer.TargetModule, field.FieldType)); 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_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: 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)); ParameterDefinition[] array = Array.Empty(); List parameters = method.Parameters; TypeSignature[] array2 = (TypeSignature[])(object)new TypeSignature[parameters.Count]; array = (ParameterDefinition[])(object)new ParameterDefinition[parameters.Count]; foreach (ParameterAnalysisContext parameter in method.Parameters) { int paramIndex = parameter.ParamIndex; array2[paramIndex] = importer2.ImportTypeSignature(AsmResolverUtils.GetTypeSignatureFromIl2CppType(importer2.TargetModule, parameter.ParameterType)); ushort num = (ushort)(paramIndex + 1); array[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) { array[paramIndex].Constant = AsmResolverConstants.GetOrCreateConstant(obj); } else if (defaultValue != null && defaultValue.dataIndex == -1) { array[paramIndex].Constant = AsmResolverConstants.Null; } } } MethodSignature val2 = (method.IsStatic ? MethodSignature.CreateStatic(val, array2) : MethodSignature.CreateInstance(val, array2)); MethodDefinition managedMethod = new MethodDefinition(Utf8String.op_Implicit(method.MethodName), (MethodAttributes)(ushort)method.Attributes, val2); if (method.Definition != null) { managedMethod.ImplAttributes = (MethodImplAttributes)method.Definition.iflags; } ParameterDefinition[] array3 = array; 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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 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)); } 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; } } internal static class AsmResolverMethodFiller { public static void FillManagedMethodBodies(AssemblyAnalysisContext asmContext) { foreach (TypeAnalysisContext type in asmContext.Types) { if (type.Name == "") { 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 val = extraData; if (val.IsManagedMethodWithBody()) { FillMethodBodyWithStub(val); } } } 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 val2 = extraData2; DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(54, 4); defaultInterpolatedStringHandler.AppendLiteral("Failed to process type "); defaultInterpolatedStringHandler.AppendFormatted(val2.FullName); defaultInterpolatedStringHandler.AppendLiteral(" (module "); ModuleDefinition module = val2.Module; defaultInterpolatedStringHandler.AppendFormatted((module != null) ? module.Name : null); defaultInterpolatedStringHandler.AppendLiteral(", declaring type "); TypeDefinition declaringType = val2.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 FillMethodBodyWithStub(MethodDefinition methodDefinition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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) methodDefinition.CilMethodBody = new CilMethodBody(methodDefinition); CilInstructionCollection instructions = methodDefinition.CilMethodBody.Instructions; if (methodDefinition.IsConstructor && !methodDefinition.IsStatic && !methodDefinition.DeclaringType.IsValueType) { MethodDefinition val = TryGetBaseConstructor(methodDefinition); if (val != null) { instructions.Add(CilOpCodes.Ldarg_0); foreach (Parameter parameter in val.Parameters) { TypeSignature type = methodDefinition.DeclaringType.Module.DefaultImporter.ImportTypeSignature(parameter.ParameterType); instructions.AddDefaultValueForType(type); } instructions.Add(CilOpCodes.Call, (IMethodDescriptor)(object)methodDefinition.DeclaringType.Module.DefaultImporter.ImportMethod((IMethodDefOrRef)(object)val)); } } foreach (Parameter parameter2 in methodDefinition.Parameters) { if (parameter2.IsOutParameter(out TypeSignature parameterType)) { if (parameterType.IsValueTypeOrGenericParameter()) { instructions.Add(CilOpCodes.Ldarg, parameter2); instructions.Add(CilOpCodes.Initobj, parameterType.ToTypeDefOrRef()); } else { instructions.Add(CilOpCodes.Ldarg, parameter2); instructions.Add(CilOpCodes.Ldnull); instructions.Add(CilOpCodes.Stind_Ref); } } } instructions.AddDefaultValueForType(((MethodSignatureBase)methodDefinition.Signature).ReturnType); instructions.Add(CilOpCodes.Ret); instructions.OptimizeMacros(); } private static bool IsOutParameter(this Parameter parameter, [NotNullWhen(true)] out TypeSignature? parameterType) { ParameterDefinition definition = parameter.Definition; if (definition != null && definition.IsOut) { TypeSignature parameterType2 = parameter.ParameterType; ByReferenceTypeSignature val = (ByReferenceTypeSignature)(object)((parameterType2 is ByReferenceTypeSignature) ? parameterType2 : null); if (val != null) { parameterType = ((TypeSpecificationSignature)val).BaseType; return true; } } parameterType = null; return false; } private static MethodDefinition? TryGetBaseConstructor(MethodDefinition methodDefinition) { TypeDefinition declaringType = methodDefinition.DeclaringType; ITypeDefOrRef baseType = declaringType.BaseType; TypeDefinition val = ((baseType != null) ? ((ITypeDescriptor)baseType).Resolve() : null); if (val == null) { return null; } if (declaringType.Module == val.Module) { return ((IEnumerable)val.Methods).FirstOrDefault((Func)((MethodDefinition m) => m.IsConstructor && !m.IsStatic && !m.IsPrivate)); } return ((IEnumerable)val.Methods).FirstOrDefault((Func)((MethodDefinition m) => m.IsConstructor && !m.IsStatic && (m.IsFamily || m.IsPublic))); } } 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; } } internal static class CilInstructionCollectionExtensions { public static CilLocalVariable AddLocalVariable(this CilInstructionCollection instructions, TypeSignature variableType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown CilLocalVariable val = new CilLocalVariable(variableType); ((Collection)(object)instructions.Owner.LocalVariables).Add(val); return val; } public static void AddDefaultValueForType(this CilInstructionCollection instructions, TypeSignature type) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) CorLibTypeSignature val = (CorLibTypeSignature)(object)((type is CorLibTypeSignature) ? type : null); if (val != null && ((TypeSignature)val).IsValueType) { instructions.AddDefaultPrimitiveValue(val); } else if (type is ByReferenceTypeSignature) { instructions.AddNullRef(); } else if (type.IsValueTypeOrGenericParameter()) { instructions.AddDefaultValueForUnknownType(type); } else { instructions.Add(CilOpCodes.Ldnull); } } private static void AddNullRef(this CilInstructionCollection instructions) { //IL_0001: 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) instructions.Add(CilOpCodes.Ldc_I4_0); instructions.Add(CilOpCodes.Conv_U); } private static void AddDefaultValueForUnknownType(this CilInstructionCollection instructions, TypeSignature type) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) CilLocalVariable val = instructions.AddLocalVariable(type); instructions.Add(CilOpCodes.Ldloca, val); instructions.Add(CilOpCodes.Initobj, type.ToTypeDefOrRef()); instructions.Add(CilOpCodes.Ldloc, val); } private static void AddDefaultPrimitiveValue(this CilInstructionCollection instructions, CorLibTypeSignature type) { //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_007f: Expected I4, but got Unknown //IL_0085: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) ElementType elementType = ((TypeSignature)type).ElementType; switch (elementType - 1) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: instructions.Add(CilOpCodes.Ldc_I4_0); break; case 9: instructions.Add(CilOpCodes.Ldc_I4_0); instructions.Add(CilOpCodes.Conv_I8); break; case 10: instructions.Add(CilOpCodes.Ldc_I4_0); instructions.Add(CilOpCodes.Conv_U8); break; case 23: instructions.Add(CilOpCodes.Ldc_I4_0); instructions.Add(CilOpCodes.Conv_I); break; case 24: instructions.Add(CilOpCodes.Ldc_I4_0); instructions.Add(CilOpCodes.Conv_U); break; case 11: instructions.Add(CilOpCodes.Ldc_R4, 0f); break; case 12: instructions.Add(CilOpCodes.Ldc_R8, 0.0); break; case 13: case 27: instructions.Add(CilOpCodes.Ldnull); break; case 21: instructions.AddDefaultValueForUnknownType((TypeSignature)(object)type); break; default: throw new ArgumentOutOfRangeException(null); case 0: break; } } } 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 } }; } } internal static class TypeSignatureExtensions { public static bool IsValueTypeOrGenericParameter(this TypeSignature type) { if (type != null && (type.IsValueType || type is GenericParameterSignature)) { return true; } return false; } } } 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", "CallAnalysisFailedAttribute", AttributeTargets.Method, allowMultiple: false); Dictionary dictionary3 = AttributeInjectionUtils.InjectZeroParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallAnalysisNotSupportedAttribute", AttributeTargets.Method, allowMultiple: false); Dictionary dictionary4 = AttributeInjectionUtils.InjectOneParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallsDeduplicatedMethodsAttribute", AttributeTargets.Method, allowMultiple: false, appContext.SystemTypes.SystemInt32Type, "Count"); Dictionary dictionary5 = AttributeInjectionUtils.InjectOneParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallsUnknownMethodsAttribute", AttributeTargets.Method, allowMultiple: false, appContext.SystemTypes.SystemInt32Type, "Count"); Dictionary dictionary6 = AttributeInjectionUtils.InjectOneParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallerCountAttribute", AttributeTargets.Method, allowMultiple: false, appContext.SystemTypes.SystemInt32Type, "Count"); Dictionary dictionary7 = AttributeInjectionUtils.InjectThreeParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CallsAttribute", AttributeTargets.Method, allowMultiple: true, appContext.SystemTypes.SystemTypeType, "Type", appContext.SystemTypes.SystemStringType, "TypeFullName", appContext.SystemTypes.SystemStringType, "Member"); Dictionary dictionary8 = AttributeInjectionUtils.InjectThreeParameterAttribute(appContext, "Cpp2ILInjected.CallAnalysis", "CalledByAttribute", AttributeTargets.Method, allowMultiple: true, appContext.SystemTypes.SystemTypeType, "Type", appContext.SystemTypes.SystemStringType, "TypeFullName", appContext.SystemTypes.SystemStringType, "Member"); Dictionary dictionary9 = new Dictionary(); Dictionary dictionary10 = new Dictionary(); Dictionary dictionary11 = new Dictionary(); Dictionary> dictionary12 = new Dictionary>(); Dictionary> dictionary13 = new Dictionary>(); BaseKeyFunctionAddresses orCreateKeyFunctionAddresses = appContext.GetOrCreateKeyFunctionAddresses(); foreach (AssemblyAnalysisContext assembly in appContext.Assemblies) { InjectedMethodAnalysisContext constructor = dictionary2[assembly]; InjectedMethodAnalysisContext constructor2 = dictionary3[assembly]; InjectedMethodAnalysisContext constructor3 = 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, constructor3); } try { item.Analyze(); } catch { item.ConvertedIsil = null; AttributeInjectionUtils.AddZeroParameterAttribute(item, constructor); continue; } List convertedIsil = item.ConvertedIsil; if (convertedIsil != null && convertedIsil.Count == 0) { if ((item.MethodAttributes & MethodAttributes.Abstract) == 0) { AttributeInjectionUtils.AddZeroParameterAttribute(item, constructor2); } continue; } foreach (InstructionSetIndependentInstruction item2 in item.ConvertedIsil) { if (item2.OpCode != InstructionSetIndependentOpCode.Call && item2.OpCode != InstructionSetIndependentOpCode.CallNoReturn) { continue; } if (item2.Operands.Length != 0 && item2.Operands[0].Data is IsilImmediateOperand isilImmediateOperand) { ulong num = isilImmediateOperand.Value.ToUInt64(null); if (appContext.MethodsByAddress.TryGetValue(num, out List value2)) { dictionary9[num] = Extensions.GetOrDefault((IDictionary)dictionary9, num, 0) + 1; MethodAnalysisContext commonMethod; if (value2.Count == 0) { dictionary10[item] = Extensions.GetOrDefault((IDictionary)dictionary10, item, 0) + 1; } else if (TryGetCommonMethodFromList(value2, out commonMethod)) { Add(dictionary12, item, commonMethod); Add(dictionary13, commonMethod, item); } else { dictionary11[item] = Extensions.GetOrDefault((IDictionary)dictionary11, item, 0) + 1; } } else if (!orCreateKeyFunctionAddresses.IsKeyFunctionAddress(num) && !appContext.Binary.IsExportedFunction(num)) { dictionary10[item] = Extensions.GetOrDefault((IDictionary)dictionary10, item, 0) + 1; } } else { dictionary10[item] = Extensions.GetOrDefault((IDictionary)dictionary10, item, 0) + 1; } } } } foreach (AssemblyAnalysisContext assembly2 in appContext.Assemblies) { (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple = dictionary6[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple2 = dictionary5[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple3 = dictionary4[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext) tuple4 = dictionary7[assembly2]; (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext) tuple5 = dictionary8[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)dictionary10, item3, 0); if (dictionary13.TryGetValue(item3, out var value3) && value3.Count < 20) { foreach (MethodAnalysisContext item4 in value3) { if (TryGetDeclaringTypeForMethod(item3, item4, out TypeAnalysisContext targetDeclaringType, out string targetDeclaringTypeFullName)) { AttributeInjectionUtils.AddTwoParameterAttribute(item3, tuple5.Item1, tuple5.Item2, targetDeclaringType, tuple5.Item4, item4.Name); } else { AttributeInjectionUtils.AddTwoParameterAttribute(item3, tuple5.Item1, tuple5.Item3, targetDeclaringTypeFullName, tuple5.Item4, item4.Name); } } } (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext) tuple6 = tuple; AttributeInjectionUtils.AddOneParameterAttribute(item3, (tuple6.Item1, tuple6.Item2), Extensions.GetOrDefault((IDictionary)dictionary9, item3.UnderlyingPointer, 0)); if (dictionary12.TryGetValue(item3, out var value4)) { foreach (MethodAnalysisContext item5 in value4) { if (TryGetDeclaringTypeForMethod(item3, item5, out TypeAnalysisContext targetDeclaringType2, out string targetDeclaringTypeFullName2)) { AttributeInjectionUtils.AddTwoParameterAttribute(item3, tuple4.Item1, tuple4.Item2, targetDeclaringType2, tuple4.Item4, item5.Name); } else { AttributeInjectionUtils.AddTwoParameterAttribute(item3, tuple4.Item1, tuple4.Item3, targetDeclaringTypeFullName2, tuple4.Item4, item5.Name); } } } if (dictionary11.TryGetValue(item3, out var value5)) { tuple6 = tuple3; AttributeInjectionUtils.AddOneParameterAttribute(item3, (tuple6.Item1, tuple6.Item2), value5); } if (orDefault > 0) { tuple6 = tuple2; AttributeInjectionUtils.AddOneParameterAttribute(item3, (tuple6.Item1, tuple6.Item2), orDefault); } } } } private static bool TryGetCommonMethodFromList(List methods, [NotNullWhen(true)] out MethodAnalysisContext? commonMethod) { if (methods.Count < 1) { throw new ArgumentException("Count cannot be 0.", "methods"); } 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 obj = array[1]; string obfuscated = text; string deobfuscated = obj; 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 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 AsmResolverDummyDllOutputFormat : Cpp2IlOutputFormat { public override string OutputFormatId => "dummydll"; public override string OutputFormatName => "Stub (\"Dummy\") DLL Files"; private AssemblyDefinition? MostRecentCorLib { get; set; } public 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...", "DummyDllOutput"); if (!Directory.Exists(outputRoot)) { Directory.CreateDirectory(outputRoot); } List<(IPEImage, 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", "DummyDllOutput"); now = DateTime.Now; Logger.Verbose("Building and writing managed PE files to disk...", "DummyDllOutput"); ManagedPEFileBuilder val = new ManagedPEFileBuilder(); foreach (var item3 in list) { IPEImage item = item3.Item1; Utf8String item2 = item3.Item2; string text = Path.Combine(outputRoot, Utf8String.op_Implicit(item2)); ((PEFileBuilderBase)(object)val).CreateFile(item).Write(text); } Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DummyDllOutput"); } public List BuildAssemblies(ApplicationAnalysisContext context) { DateTime now = DateTime.Now; Logger.Verbose("Building stub assemblies...", "DummyDllOutput"); List result = BuildStubAssemblies(context); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DummyDllOutput"); now = DateTime.Now; Logger.Verbose("Configuring inheritance and generics...", "DummyDllOutput"); Parallel.ForEach(context.Assemblies, AsmResolverAssemblyPopulator.ConfigureHierarchy); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DummyDllOutput"); now = DateTime.Now; Logger.Verbose("Adding fields, methods, properties, and events (in parallel)...", "DummyDllOutput"); MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.CopyDataFromIl2CppToManaged); MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverMethodFiller.FillManagedMethodBodies); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DummyDllOutput"); now = DateTime.Now; Logger.Verbose("Adding custom attributes to all of the above...", "DummyDllOutput"); MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.PopulateCustomAttributes); Logger.VerboseNewline($"{(DateTime.Now - now).TotalMilliseconds:F1}ms", "DummyDllOutput"); TypeDefinitionsAsmResolver.Reset(); return result; } 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Il2CppTypeDefinition definition = typeContext.Definition; TypeDefinition val = new TypeDefinition(Utf8String.op_Implicit(typeContext.Namespace), Utf8String.op_Implicit(typeContext.Name), (TypeAttributes)(definition?.Flags ?? 257)); 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) { if (type.IsCompilerGeneratedBasedOnCustomAttributes) { return; } 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)) { 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); sb.Append("; //Field offset: 0x"); sb.Append(field.Offset.ToString("X")); 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)); 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) { string outputRoot2 = outputRoot; outputRoot2 = Path.Combine(outputRoot2, "IsilDump"); int count = context.Assemblies.Count; int num = 0; foreach (AssemblyAnalysisContext assembly in context.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 { 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(); } stringBuilder.AppendLine(); } } catch (Exception ex) { stringBuilder.Append("Method threw an exception while analyzing - ").AppendLine(ex.Message).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; } 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 ? ".ctor" : ".cctor", 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 = new List(); public readonly List Fields = new List(); public readonly List Properties = new List(); 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; } 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; } public abstract void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context); } public abstract class BaseCustomAttributeTypeParameter : BaseCustomAttributeParameter { public BaseCustomAttributeTypeParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { } public abstract TypeSignature? ToTypeSignature(ModuleDefinition parentModule); } 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 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; } public override string ToString() { return $"{Field.Name} = {Value}"; } } 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 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: throw new Exception("CustomAttributePrimitiveParameter constructed with a non-primitive type: " + ((object)(Il2CppTypeEnum)(ref PrimitiveType)).ToString()); } } public override string ToString() { if (!(PrimitiveValue is string text)) { return PrimitiveValue?.ToString(CultureInfo.InvariantCulture) ?? "null"; } return "\"" + text + "\""; } } public class CustomAttributeProperty { public readonly PropertyAnalysisContext Property; public readonly BaseCustomAttributeParameter Value; public CustomAttributeProperty(PropertyAnalysisContext property, BaseCustomAttributeParameter value) { Property = property; Value = value; } public override string ToString() { return $"{Property.Name} = {Value}"; } } public class CustomAttributeTypeParameter : BaseCustomAttributeTypeParameter { public Il2CppType? 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() { if (Type == null) { return "(Type) null"; } return "typeof(" + Type.AsClass().Name + ")"; } public override TypeSignature? ToTypeSignature(ModuleDefinition parentModule) { if (Type != null) { return AsmResolverUtils.GetTypeSignatureFromIl2CppType(parentModule, Type); } return null; } } public class InjectedCustomAttributeTypeParameter : BaseCustomAttributeTypeParameter { public TypeAnalysisContext? Type { get; } public InjectedCustomAttributeTypeParameter(TypeAnalysisContext? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { Type = type; } public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) { throw new NotSupportedException(); } public override TypeSignature? ToTypeSignature(ModuleDefinition parentModule) { if (Type == null) { return null; } TypeDefinition val = Type.GetExtraData("AsmResolverType") ?? throw new Exception("AsmResolver type not found in type analysis context for " + Type.FullName); return ((ITypeDescriptor)parentModule.DefaultImporter.ImportType((ITypeDefOrRef)(object)val)).ToTypeSignature(); } } } 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) { 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); } } return AssembliesByName[name]; } public TypeAnalysisContext? ResolveContextForType(Il2CppTypeDefinition typeDefinition) { return GetAssemblyByName(typeDefinition.DeclaringAssembly.Name)?.TypesByDefinition[typeDefinition]; } public BaseKeyFunctionAddresses GetOrCreateKeyFunctionAddresses() { 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 AssemblyAnalysisContext : HasCustomAttributes { public Il2CppAssemblyDefinition Definition; public List Types = new List(); public Il2CppCodeGenModule? CodeGenModule; private Dictionary TypesByName = new Dictionary(); public 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) { InjectedTypeAnalysisContext injectedTypeAnalysisContext = new InjectedTypeAnalysisContext(this, name, ns, baseType); Types.Add(injectedTypeAnalysisContext); return injectedTypeAnalysisContext; } public TypeAnalysisContext? GetTypeByFullName(string fullName) { if (!TypesByName.TryGetValue(fullName, 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 ConcreteGenericMethodAnalysisContext : MethodAnalysisContext { public readonly AssemblyAnalysisContext DeclaringAsm; public readonly Cpp2IlMethodRef MethodRef; public TypeAnalysisContext BaseTypeContext; public MethodAnalysisContext BaseMethodContext; public sealed override ulong UnderlyingPointer => MethodRef.GenericVariantPtr; public override bool IsStatic => BaseMethodContext.IsStatic; public override bool IsVoid => BaseMethodContext.IsVoid; public ConcreteGenericMethodAnalysisContext(Cpp2IlMethodRef methodRef, ApplicationAnalysisContext context) : base(context) { MethodRef = methodRef; DeclaringAsm = context.GetAssemblyByName(methodRef.DeclaringType.DeclaringAssembly.Name) ?? throw new Exception($"Unable to resolve declaring assembly {methodRef.DeclaringType.DeclaringAssembly.Name} for generic method {methodRef}"); BaseTypeContext = DeclaringAsm.GetTypeByFullName(methodRef.DeclaringType.FullName) ?? throw new Exception($"Unable to resolve declaring type {methodRef.DeclaringType.FullName} for generic method {methodRef}"); BaseMethodContext = BaseTypeContext.GetMethod(methodRef.BaseMethod) ?? throw new Exception($"Unable to resolve base method {methodRef.BaseMethod} for generic method {methodRef}"); Parameters.AddRange(BaseMethodContext.Parameters); if (UnderlyingPointer != 0L) { RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, isAttributeGenerator: false); } } } 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 virtual Il2CppType FieldType => 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 TypeAnalysisContext FieldTypeContext => DeclaringType.DeclaringAssembly.ResolveIl2CppType(FieldType); 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 (!FieldType.ThisOrElementIsGenericParam()) { return TypeAnalysisContext.GetSndnProviderForType(AppContext, FieldType); } return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(FieldType.GetGenericParamName()); } } 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); } } public class GenericInstanceTypeAnalysisContext : ReferencedTypeAnalysisContext { protected override TypeAnalysisContext ElementType { get; } public GenericInstanceTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(rawType, referencedFrom) { Il2CppGenericClass genericClass = rawType.GetGenericClass(); ElementType = AppContext.ResolveContextForType(genericClass.TypeDefinition) ?? throw new Exception("Could not resolve type " + genericClass.TypeDefinition.FullName + " for generic instance base type"); base.GenericArguments.AddRange(genericClass.Context.ClassInst.Types.Select(referencedFrom.ResolveIl2CppType)); } } public class GenericParameterTypeAnalysisContext : ReferencedTypeAnalysisContext { protected override TypeAnalysisContext ElementType { get { throw new Exception("Attempted to get element type of a generic parameter"); } } public GenericParameterTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(rawType, referencedFrom) { //IL_0009: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) Il2CppTypeEnum type = rawType.Type; if ((int)type != 19 && (int)type != 30) { throw new Exception($"Generic parameter type is not a generic parameter, but {rawType.Type}"); } base.GenericParameter = rawType.GetGenericParameterDef(); } } public abstract class HasApplicationContext : ContextWithDataStorage { public ApplicationAnalysisContext AppContext; protected HasApplicationContext(ApplicationAnalysisContext appContext) { AppContext = appContext; } } 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) : base(appContext) { Token = token; } } public class InjectedFieldAnalysisContext : FieldAnalysisContext { public override Il2CppType FieldType { get; } public override FieldAttributes Attributes { get; } public InjectedFieldAnalysisContext(string name, TypeAnalysisContext type, FieldAttributes attributes, TypeAnalysisContext parent) : base(null, parent) { base.OverrideName = name; Attributes = attributes; FieldType = LibCpp2IlReflection.GetTypeFromDefinition(type.Definition ?? throw new Exception("Fields with a type of an injected type are not supported yet.")); } } 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, this)); } } } public class InjectedParameterAnalysisContext : ParameterAnalysisContext { public override Il2CppType ParameterType { get; } public override bool IsRef => false; public InjectedParameterAnalysisContext(string? name, Il2CppType type, MethodAnalysisContext declaringMethod) : base(null, 0, declaringMethod) { base.OverrideName = name; ParameterType = type; } public InjectedParameterAnalysisContext(string? name, TypeAnalysisContext typeContext, MethodAnalysisContext declaringMethod) : this(name, LibCpp2IlReflection.GetTypeFromDefinition(typeContext.Definition ?? throw new Exception("Parameters with a type of an injected type are not supported yet.")), declaringMethod) { } } public class InjectedTypeAnalysisContext : TypeAnalysisContext { public override string DefaultName { get; } public override string DefaultNs { get; } public InjectedTypeAnalysisContext(AssemblyAnalysisContext containingAssembly, string name, string ns, TypeAnalysisContext? baseType) : base(null, containingAssembly) { DefaultName = name; DefaultNs = ns; base.OverrideBaseType = baseType; } 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 IControlFlowGraph? ControlFlowGraph; public List Parameters = new List(); 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) { if (UnderlyingPointer == 0L) { ConvertedIsil = new List(0); return; } ConvertedIsil = AppContext.InstructionSet.GetIsilFromMethod(this); _ = ConvertedIsil.Count; } } 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 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 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 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(ParameterTypeContext.Name).Append(" "); if (string.IsNullOrEmpty(ParameterName)) { stringBuilder.Append("unnamed_param_").Append(ParamIndex); } else { stringBuilder.Append(ParameterName); } if (ParameterAttributes.HasFlag(ParameterAttributes.HasDefault)) { StringBuilder stringBuilder2 = stringBuilder.Append(" = "); Il2CppParameterDefaultValue? defaultValue = DefaultValue; stringBuilder2.Append(((defaultValue != null) ? defaultValue.ContainedDefaultValue : null) ?? "null"); } return stringBuilder.ToString(); } } public class PropertyAnalysisContext : HasCustomAttributesAndName, IPropertyInfoProvider { public readonly TypeAnalysisContext DeclaringType; public readonly Il2CppPropertyDefinition Definition; public readonly MethodAnalysisContext? Getter; public readonly MethodAnalysisContext? Setter; 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 Il2CppType RawType { get; } protected abstract TypeAnalysisContext ElementType { get; } protected List GenericArguments { get; } = new List(); protected Il2CppGenericParameter? GenericParameter { get; set; } public override string DefaultNs => ElementType.Namespace; public override string DefaultName { get { //IL_0006: 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_000c: 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_0031: Expected I4, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 Il2CppTypeEnum type = RawType.Type; switch (type - 15) { default: if ((int)type != 29) { if ((int)type != 30) { break; } return GenericParameter.Name; } return ElementType.Name + "[]"; case 0: return ElementType.Name + "*"; case 1: return ElementType.Name + "&"; case 5: return $"{ElementType.Name}[{RawType.GetArrayRank()}]"; case 6: return ElementType.Name + "<" + string.Join(", ", GenericArguments.Select((TypeAnalysisContext a) => a.Name)) + ">"; case 4: return GenericParameter.Name; case 2: case 3: break; } throw new ArgumentOutOfRangeException(); } } protected override int CustomAttributeIndex => -1; public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly; protected ReferencedTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(null, referencedFrom) { RawType = rawType; } public override string ToString() { return DefaultName ?? ""; } } 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 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"); } } public class TypeAnalysisContext : HasCustomAttributesAndName, ITypeInfoProvider { 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(@namespace.Split('.')); } return ""; } } public TypeAnalysisContext UltimateDeclaringType => DeclaringType ?? this; public IEnumerable Interfaces => Definition.RawInterfaces.Select((Il2CppType t) => GetSndnProviderForType(AppContext, t)); public TypeAttributes TypeAttributes => Definition.Attributes; public int GenericParameterCount => Definition.GenericContainer?.genericParameterCount ?? 0; public string OriginalTypeName => DefaultName; public string RewrittenTypeName => base.Name; public string TypeNamespace => Namespace; public bool IsGenericInstance => false; public bool IsValueType => Definition.IsValueType; public bool IsEnumType => Definition.IsEnumType; public bool IsInterface => 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 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Invalid comparison between Unknown and I4 //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Invalid comparison between Unknown and I4 //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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; })) { 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) { return (ITypeInfoProvider)new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name); } type2 = type.Type; if ((int)type2 == 29 || (int)type2 == 15) { 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 class WrappedTypeAnalysisContext : ReferencedTypeAnalysisContext { protected override TypeAnalysisContext ElementType { get { //IL_0006: 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_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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_009d: Unknown result type (might be due to invalid IL or missing references) Il2CppTypeEnum type = base.RawType.Type; if ((int)type <= 16) { if ((int)type == 15) { return DeclaringAssembly.ResolveIl2CppType(base.RawType.GetEncapsulatedType()); } if ((int)type == 16) { throw new Exception("TODO Support TYPE_BYREF"); } } else { if ((int)type == 20) { return DeclaringAssembly.ResolveIl2CppType(base.RawType.GetArrayElementType()); } if ((int)type == 29) { return DeclaringAssembly.ResolveIl2CppType(base.RawType.GetEncapsulatedType()); } } throw new Exception($"Type {base.RawType.Type} is not a wrapper type"); } } public WrappedTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(rawType, referencedFrom) { } } } 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 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, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Subtract = new InstructionSetIndependentOpCode(IsilMnemonic.Subtract, 2, 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, 2, 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, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Or = new InstructionSetIndependentOpCode(IsilMnemonic.Or, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Xor = new InstructionSetIndependentOpCode(IsilMnemonic.Xor, 2, 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 NotImplemented = new InstructionSetIndependentOpCode(IsilMnemonic.NotImplemented, 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) { throw new Exception($"Too many operands! We have {operands.Length} but we only allow {MaxOperands}"); } if (PermittedOperandTypes.Length == 0) { return; } for (int i = 0; i < operands.Length; i++) { if ((operands[i].Type & PermittedOperandTypes[i]) == 0) { throw new Exception($"Instruction {instruction}: 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"); } } } 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, MemoryOrStack = 0xA, NotStack = 0x1D, Any = 0xF } 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); } private InstructionSetIndependentOperand(OperandType type, IsilOperandData data) { Type = type; Data = data; } public override string? ToString() { 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.ContainsKey(instruction.ActualAddress)) { InstructionAddressMap[instruction.ActualAddress].Add(instruction); } else { List list = new List(); list.Add(instruction); InstructionAddressMap[instruction.ActualAddress] = list; } 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 == null) { throw new IsilConversionException("This can't ever happen"); } if (instructionSetIndependentInstruction.Equals(item.Item1)) { throw new IsilConversionException("Invalid jump target for instruction: Instruction can't jump to itself"); } item.Item1.Operands = new InstructionSetIndependentOperand[1] { InstructionSetIndependentOperand.MakeInstruction(instructionSetIndependentInstruction) }; continue; } throw new IsilConversionException("Jump target not found in method. Ruh roh"); } } 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 left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Subtract, instructionAddress, IsilFlowControl.Continue, left, right)); } public void Add(ulong instructionAddress, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Add, instructionAddress, IsilFlowControl.Continue, left, right)); } public void Xor(ulong instructionAddress, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Xor, instructionAddress, IsilFlowControl.Continue, 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 left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.And, instructionAddress, IsilFlowControl.Continue, left, right)); } public void Or(ulong instructionAddress, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Or, instructionAddress, IsilFlowControl.Continue, 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 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 Interrupt(ulong instructionAddress) { AddInstruction(new InstructionSetIndependentInstruction(InstructionSetIndependentOpCode.Interrupt, instructionAddress, IsilFlowControl.Interrupt)); } 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; } 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() { try { if (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 ulong Addend; public readonly int Scale; public IsilMemoryOperand(ulong addend) { Base = null; Index = null; Addend = 0uL; Scale = 0; Addend = addend; } public IsilMemoryOperand(InstructionSetIndependentOperand @base) { Base = null; Index = null; Addend = 0uL; Scale = 0; Base = @base; } public IsilMemoryOperand(InstructionSetIndependentOperand @base, ulong addend) { Base = null; Index = null; Addend = 0uL; Scale = 0; Base = @base; Addend = addend; } public IsilMemoryOperand(InstructionSetIndependentOperand @base, InstructionSetIndependentOperand index, int scale) { Base = null; Index = null; Addend = 0uL; Scale = 0; Base = @base; Index = index; Scale = scale; } public IsilMemoryOperand(InstructionSetIndependentOperand @base, InstructionSetIndependentOperand index, ulong addend, int scale) { Base = null; Index = null; Addend = 0uL; 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 != 0) { if (flag) { stringBuilder.Append("+"); } if (Addend > 65536) { stringBuilder.AppendFormat("0x{0:X}", Addend); } else { stringBuilder.Append(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 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, NotImplemented } 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 { } } namespace Cpp2IL.Core.InstructionSets { public class Arm64InstructionSet : Cpp2IlInstructionSet { public virtual IControlFlowGraph BuildGraphForMethod(MethodAnalysisContext context) { return null; } 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 virtual IControlFlowGraph BuildGraphForMethod(MethodAnalysisContext context) { return null; } 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) - 1; int num2 = (int)context.UnderlyingPointer; int length = num - num2; if (num > 0) { return LibCpp2IlMain.Binary.GetRawBinaryContent().AsMemory(num2, length); } } Arm64DisassemblyResult arm64MethodBodyAtVirtualAddress = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); ulong endVirtualAddress = ((Arm64DisassemblyResult)(ref arm64MethodBodyAtVirtualAddress)).EndVirtualAddress; int num3 = (int)context.AppContext.Binary.MapVirtualAddressToRaw(context.UnderlyingPointer, true); int num4 = (int)context.AppContext.Binary.MapVirtualAddressToRaw(endVirtualAddress, true); return context.AppContext.Binary.GetRawBinaryContent().AsMemory(num3, num4 - num3); } public override List GetIsilFromMethod(MethodAnalysisContext context) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); return new List(); } public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() { return new NewArm64KeyFunctionAddresses(); } public override string PrintAssembly(MethodAnalysisContext context) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) return string.Join("\n", Disassembler.Disassemble((ReadOnlySpan)context.RawBytes.Span, context.UnderlyingPointer, true, false, true).Instructions); } } public class WasmInstructionSet : Cpp2IlInstructionSet { public virtual IControlFlowGraph BuildGraphForMethod(MethodAnalysisContext context) { return null; } public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { Il2CppMethodDefinition definition = context.Definition; if (definition != null) { WasmFunctionDefinition val = WasmUtils.TryGetWasmDefinition(definition); if (val == null) { Logger.WarnNewline("Could not find WASM definition for method " + definition.Name + ", probably incorrect signature calculation", "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 { 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) { InstructionList values = X86Utils.Disassemble(X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, isCaGen: false), context.UnderlyingPointer); return string.Join("\n", (IEnumerable)values); } public override List GetIsilFromMethod(MethodAnalysisContext context) { //IL_0017: 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_0026: 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_002d: Unknown result type (might be due to invalid IL or missing references) InstructionList obj = X86Utils.Disassemble(context.RawBytes, context.UnderlyingPointer); IsilBuilder isilBuilder = new IsilBuilder(); Enumerator enumerator = obj.GetEnumerator(); try { while (((Enumerator)(ref enumerator)).MoveNext()) { Instruction current = ((Enumerator)(ref enumerator)).Current; ConvertInstructionStatement(current, isilBuilder, context); } } finally { ((IDisposable)(Enumerator)(ref enumerator)).Dispose(); } 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Invalid comparison between Unknown and I4 //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Invalid comparison between Unknown and I4 //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Invalid comparison between Unknown and I4 //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Invalid comparison between Unknown and I4 //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Invalid comparison between Unknown and I4 //IL_008f: 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_00d4: Expected I4, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_0834: Unknown result type (might be due to invalid IL or missing references) //IL_083c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Invalid comparison between Unknown and I4 //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Invalid comparison between Unknown and I4 //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Invalid comparison between Unknown and I4 //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Invalid comparison between Unknown and I4 //IL_079f: Unknown result type (might be due to invalid IL or missing references) //IL_07e9: Unknown result type (might be due to invalid IL or missing references) //IL_07c4: Unknown result type (might be due to invalid IL or missing references) //IL_080b: Unknown result type (might be due to invalid IL or missing references) //IL_0755: Unknown result type (might be due to invalid IL or missing references) //IL_0700: Unknown result type (might be due to invalid IL or missing references) //IL_077a: 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_00db: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Invalid comparison between Unknown and I4 //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Invalid comparison between Unknown and I4 //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Invalid comparison between Unknown and I4 //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Invalid comparison between Unknown and I4 //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Invalid comparison between Unknown and I4 //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Invalid comparison between Unknown and I4 //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: 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_00e7: Invalid comparison between Unknown and I4 //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Invalid comparison between Unknown and I4 //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Invalid comparison between Unknown and I4 //IL_06e9: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0696: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_04df: 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_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_06a2: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_06ae: Unknown result type (might be due to invalid IL or missing references) //IL_06b5: 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_06c8: Unknown result type (might be due to invalid IL or missing references) Mnemonic mnemonic = ((Instruction)(ref instruction)).Mnemonic; if ((int)mnemonic <= 414) { if ((int)mnemonic <= 137) { if ((int)mnemonic <= 21) { if ((int)mnemonic == 7) { goto IL_0423; } if ((int)mnemonic == 21) { builder.And(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } } else { if ((int)mnemonic == 59) { goto IL_04ed; } if ((int)mnemonic == 93) { builder.Compare(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } if ((int)mnemonic == 137) { goto IL_04a3; } } } else if ((int)mnemonic <= 287) { if ((int)mnemonic != 277) { if ((int)mnemonic == 279) { goto IL_04a3; } if ((int)mnemonic == 287) { goto IL_0849; } } else { 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 { switch (mnemonic - 297) { case 11: goto IL_06fe; case 5: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget4 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfEqual(((Instruction)(ref instruction)).IP, nearBranchTarget4); return; } goto IL_0857; case 13: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget6 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfNotEqual(((Instruction)(ref instruction)).IP, nearBranchTarget6); return; } goto IL_0857; case 0: case 7: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget2 = ((Instruction)(ref instruction)).NearBranchTarget; builder.JumpIfGreater(((Instruction)(ref instruction)).IP, nearBranchTarget2); return; } goto IL_0857; 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_0857; 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_0857; 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_0857; case 4: case 6: case 12: goto IL_0857; } if ((int)mnemonic == 374) { builder.LoadAddress(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } if ((int)mnemonic == 414) { builder.Move(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } } } else if ((int)mnemonic <= 712) { if ((int)mnemonic <= 590) { if ((int)mnemonic == 466) { builder.Not(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0)); return; } if ((int)mnemonic == 467) { builder.Or(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } if ((int)mnemonic == 590) { builder.Pop(((Instruction)(ref instruction)).IP, InstructionSetIndependentOperand.MakeRegister("rsp"), ConvertOperand(instruction, 0)); return; } } 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 == 715) { builder.ShiftRight(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } if ((int)mnemonic == 740) { goto IL_0423; } if ((int)mnemonic == 751 && (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; } } else { if ((int)mnemonic == 1509) { builder.Exchange(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); return; } if ((int)mnemonic == 1518) { 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, 1)); } return; } if ((int)mnemonic == 1620) { goto IL_0849; } } goto IL_0857; IL_04ed: ulong nearBranchTarget7 = ((Instruction)(ref instruction)).NearBranchTarget; if (context.AppContext.MethodsByAddress.ContainsKey(nearBranchTarget7)) { int num = context.AppContext.MethodsByAddress[nearBranchTarget7].Select(delegate(MethodAnalysisContext p) { int num5 = p.Parameters.Count; if (!p.IsStatic) { num5++; } return num5 + 1; }).ToArray().Max(); List list = new string[4] { "rcx", "rdx", "r8", "r9" }.Select(InstructionSetIndependentOperand.MakeRegister).ToList(); if (num <= list.Count) { builder.Call(((Instruction)(ref instruction)).IP, nearBranchTarget7, list.GetRange(0, num).ToArray()); return; } num -= list.Count; int ptrSize = (int)((ClassReadingBinaryReader)context.AppContext.Binary).PointerSize; list = list.Concat((from p in Enumerable.Range(0, num) select p * ptrSize).Select(InstructionSetIndependentOperand.MakeStack)).ToList(); builder.Call(((Instruction)(ref instruction)).IP, nearBranchTarget7, list.ToArray()); builder.ShiftStack(((Instruction)(ref instruction)).IP, -num * 8); } else { InstructionSetIndependentOperand[] args = new string[4] { "rcx", "rdx", "r8", "r9" }.Select(InstructionSetIndependentOperand.MakeRegister).ToArray(); builder.Call(((Instruction)(ref instruction)).IP, nearBranchTarget7, args); } return; IL_06fe: if ((int)((Instruction)(ref instruction)).Op0Kind != 0) { ulong nearBranchTarget8 = ((Instruction)(ref instruction)).NearBranchTarget; ulong num2 = ((Instruction)(ref instruction)).IP + (ulong)context.RawBytes.Length; ulong underlyingPointer = context.UnderlyingPointer; if (nearBranchTarget8 >= underlyingPointer && nearBranchTarget8 <= num2) { builder.Goto(((Instruction)(ref instruction)).IP, nearBranchTarget8); return; } goto IL_04ed; } goto IL_0857; IL_0857: builder.NotImplemented(((Instruction)(ref instruction)).IP, ((object)(Instruction)(ref instruction)).ToString()); return; IL_0423: bool flag = (int)((Instruction)(ref instruction)).Mnemonic == 740; if ((int)((Instruction)(ref instruction)).Op0Register == 57 && ((Instruction)(ref instruction)).Op1Kind.IsImmediate()) { int num3 = (int)((Instruction)(ref instruction)).GetImmediate(1); builder.ShiftStack(((Instruction)(ref instruction)).IP, flag ? (-num3) : num3); return; } InstructionSetIndependentOperand left = ConvertOperand(instruction, 0); InstructionSetIndependentOperand right = ConvertOperand(instruction, 1); if (flag) { builder.Subtract(((Instruction)(ref instruction)).IP, left, right); } else { builder.Add(((Instruction)(ref instruction)).IP, left, right); } return; IL_04a3: bool num4 = (int)((Instruction)(ref instruction)).Mnemonic == 137; InstructionSetIndependentOperand right2 = InstructionSetIndependentOperand.MakeImmediate(1); if (num4) { builder.Subtract(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), right2); } else { builder.Add(((Instruction)(ref instruction)).IP, ConvertOperand(instruction, 0), right2); } return; IL_0849: builder.Interrupt(((Instruction)(ref instruction)).IP); } 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(((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)), ((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(((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"; }) 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") { break; } mnemonic = ((Instruction)(object)val).Mnemonic; if (mnemonic == "b" || mnemonic == "bl") { 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") { 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") { 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"; }).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 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 Arm64DisassemblyResult? _cachedDisassembledBytes; private Arm64DisassemblyResult DisassembleTextSection() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!_cachedDisassembledBytes.HasValue) { byte[] entirePrimaryExecutableSection = LibCpp2IlMain.Binary.GetEntirePrimaryExecutableSection(); _cachedDisassembledBytes = Disassembler.Disassemble((ReadOnlySpan)entirePrimaryExecutableSection, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection(), true, false, true); } return _cachedDisassembledBytes.Value; } protected override IEnumerable FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0u, params ulong[] addressesToIgnore) { List list = DisassembleTextSection().Instructions.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) && ((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_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) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return DisassembleTextSection().Instructions.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) && ((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; } 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_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 Mnemonic mnemonic = ((Instruction)(ref i)).Mnemonic; return ((int)mnemonic == 308 || (int)mnemonic == 59) && ((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.HLIL { public enum BinaryArithmeticOperator { Subtract, Add } public class HLILBuilder { public HLILMnemonic Mnemonic; public InstructionSetIndependentOperand[] Operands = Array.Empty(); } public class HlilInstruction { } public enum HLILMnemonic { Assign, Goto, JCond, Call, Ret, Push, Pop } public class HLILOperand { } public enum UnaryArithmeticOperator { Not, Or, Xor } } namespace Cpp2IL.Core.Graphs { public struct BasicBlock { public BlockType BlockType; public List Predecessors; public List Successors; public BasicBlock(BlockType blockType) { BlockType = blockType; Predecessors = new List(); Successors = new List(); } } public enum BlockType : byte { OneWay, TwoWay, NWay, Call, Return, Fall } public interface IControlFlowGraph { List INodes { get; } void Run(bool print = false); void TraverseEntireGraphPreOrder(Action action); } public interface IControlFlowNode { } public class IfStatement : IStatement { public List IfBlock; public List ElseBlock; public InstructionGraphCondition Condition; public IfStatement(InstructionGraphCondition condition, List @if, List @else) { Condition = condition; IfBlock = @if; ElseBlock = @else; } public IfStatement(InstructionGraphCondition condition, List @if) : this(condition, @if, new List()) { } public string GetTextDump(int indent) { StringBuilder stringBuilder = new StringBuilder(); string value = new string(' ', indent); StringBuilder stringBuilder2 = stringBuilder.Append(value); StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(5, 1, stringBuilder2); handler.AppendLiteral("if("); handler.AppendFormatted(Condition.ConditionString); handler.AppendLiteral(")\n"); stringBuilder2.Append(ref handler); stringBuilder.Append(value).Append("{\n"); foreach (IStatement item in IfBlock) { stringBuilder.Append(item.GetTextDump(indent + 4)); } stringBuilder.Append(value).Append("}\n"); if (ElseBlock.Count == 0) { return stringBuilder.ToString(); } stringBuilder.Append(value).Append("else\n"); stringBuilder.Append(value).Append("{\n"); foreach (IStatement item2 in ElseBlock) { stringBuilder.Append(item2.GetTextDump(indent + 4)); } stringBuilder.Append(value).Append("}\n"); return stringBuilder.ToString(); } } public class AbstractControlFlowGraph : IControlFlowGraph where TNode : InstructionGraphNode, new() { protected List Instructions; protected BaseKeyFunctionAddresses KeyFunctionAddresses; protected TNode ExitNode; private Dictionary InstructionsByAddress; protected int idCounter; private static Dictionary UsageAndDefinitions = new Dictionary(); private Collection nodeSet; public TNode Root { get; } protected Collection Nodes => nodeSet; public List INodes => Nodes.Cast().ToList(); public int Count => nodeSet.Count; protected AbstractControlFlowGraph(List instructions, BaseKeyFunctionAddresses keyFunctionAddresses) { if (instructions == null) { throw new ArgumentNullException("instructions"); } TNode val = new TNode { ID = idCounter++, FlowControl = InstructionGraphNodeFlowControl.Entry }; ExitNode = new TNode { ID = idCounter++, FlowControl = InstructionGraphNodeFlowControl.Exit }; Instructions = instructions; KeyFunctionAddresses = keyFunctionAddresses; InstructionsByAddress = new Dictionary(); Root = val; nodeSet = new Collection(); foreach (TInstruction instruction in Instructions) { InstructionsByAddress.Add(GetAddressOfInstruction(instruction), instruction); } } protected virtual ulong GetAddressOfInstruction(TInstruction instruction) { throw new NotImplementedException(); } protected TNode SplitAndCreate(TNode target, int index) { if (index < 0 || index >= target.Instructions.Count) { throw new ArgumentOutOfRangeException("index"); } if (index == 0) { return target; } TNode val = new TNode { ID = idCounter++ }; List range = target.Instructions.GetRange(index, target.Instructions.Count - index); target.Instructions.RemoveRange(index, target.Instructions.Count - index); val.Instructions.AddRange(range); val.FlowControl = target.FlowControl; target.FlowControl = InstructionGraphNodeFlowControl.Continue; val.Successors = target.Successors; val.HasProcessedSuccessors = target.HasProcessedSuccessors; val.NeedsCorrectingDueToJump = target.NeedsCorrectingDueToJump; target.NeedsCorrectingDueToJump = false; target.Successors = new InstructionGraphNodeSet(); foreach (InstructionGraphNode successor in val.Successors) { for (int i = 0; i < successor.Predecessors.Count; i++) { if (successor.Predecessors[i] == target) { successor.Predecessors[i] = val; } } } AddNode(val); AddDirectedEdge(target, val); return val; } public void Run(bool print = false) { AddNode(Root); if (Instructions.Count == 0) { AddNode(ExitNode); AddDirectedEdge(Root, ExitNode); return; } BuildInitialGraph(); AddNode(ExitNode); SegmentGraph(); ConstructConditions(); SquashGraph(); ComputeDominators(); IdentifyLoops(); CalculateUseDefs(); DetermineLocals(); if (print) { Console.WriteLine(Print()); } } private void SquashGraph() { foreach (TNode node in Nodes) { node.Visited = false; } TraverseAndPostExecute(Root, delegate(InstructionGraphNode node) { foreach (TInstruction instruction in node.Instructions) { node.Statements.Add(new InstructionStatement(instruction)); } }); foreach (TNode node2 in Nodes) { node2.Visited = false; } TraverseAndPostExecute(Root, delegate(InstructionGraphNode node) { bool flag = false; while (TrySquash(node)) { } }); } public void TraverseEntireGraphPreOrder(Action action) { TraversePreOrder(Root, action); } public void TraversePreOrder(TNode node, Action action) { action(node); foreach (InstructionGraphNode successor in node.Successors) { TraversePreOrder((TNode)successor, action); } } private void TraverseAndPostExecute(InstructionGraphNode node, Action> action) { node.Visited = true; foreach (InstructionGraphNode successor in node.Successors) { if (!successor.Visited) { TraverseAndPostExecute(successor, action); } } action(node); } private bool TrySquash(InstructionGraphNode node) { if (node == ExitNode || node == Root) { return false; } if (node.Successors.Count == 1) { if (node.Successors[0].Predecessors.Count == 1) { TNode val = (TNode)node.Successors[0]; if (val == ExitNode) { return false; } node.FlowControl = val.FlowControl; node.Successors = val.Successors; foreach (InstructionGraphNode successor in val.Successors) { successor.Predecessors.Remove(val); successor.Predecessors.Add(node); } node.Condition = val.Condition; node.Statements.AddRange(val.Statements); DirectedEdgeRemove(node, val); nodeSet.Remove(val); return true; } } else if (node.Successors.Count == 2) { return TrySquashConditional(node); } return false; } protected void DirectedEdgeRemove(InstructionGraphNode from, InstructionGraphNode to) { from.Successors.Remove((TNode)to); to.Predecessors.Remove((TNode)from); } private bool TrySquashConditional(InstructionGraphNode node) { if (!node.IsConditionalBranch) { return false; } InstructionGraphCondition condition = node.Condition; InstructionGraphNode instructionGraphNode = node.Successors[1]; InstructionGraphNode instructionGraphNode2 = node.Successors[0]; if (instructionGraphNode == null || instructionGraphNode2 == null) { throw new NullReferenceException("True or false path is null, this shouldn't happen ever"); } InstructionGraphNode singleSucc = GetSingleSucc(instructionGraphNode); InstructionGraphNode singleSucc2 = GetSingleSucc(instructionGraphNode2); if (singleSucc2 == instructionGraphNode) { if (instructionGraphNode2.Predecessors.Count != 1) { return false; } IfStatement item = new IfStatement(condition, instructionGraphNode2.Statements); node.FlowControl = InstructionGraphNodeFlowControl.Continue; node.Condition = null; DirectedEdgeRemove(instructionGraphNode2, instructionGraphNode); DirectedEdgeRemove(node, instructionGraphNode2); Nodes.Remove((TNode)instructionGraphNode2); node.Statements.Add(item); return true; } if (singleSucc == instructionGraphNode2) { if (instructionGraphNode.Predecessors.Count != 1) { return false; } condition.FlipCondition(); IfStatement item2 = new IfStatement(condition, instructionGraphNode.Statements); node.FlowControl = InstructionGraphNodeFlowControl.Continue; node.Condition = null; DirectedEdgeRemove(instructionGraphNode, instructionGraphNode2); DirectedEdgeRemove(node, instructionGraphNode); Nodes.Remove((TNode)instructionGraphNode); node.Statements.Add(item2); return true; } if (singleSucc != null && singleSucc2 != null && singleSucc == singleSucc2) { if (instructionGraphNode2.Predecessors.Count != 1 || instructionGraphNode.Predecessors.Count != 1) { return false; } IfStatement item3 = new IfStatement(condition, instructionGraphNode2.Statements, instructionGraphNode.Statements); node.FlowControl = InstructionGraphNodeFlowControl.Continue; node.Condition = null; DirectedEdgeRemove(node, instructionGraphNode); DirectedEdgeRemove(node, instructionGraphNode2); DirectedEdgeRemove(instructionGraphNode, singleSucc); DirectedEdgeRemove(instructionGraphNode2, singleSucc2); AddDirectedEdge((TNode)node, (TNode)singleSucc2); Nodes.Remove((TNode)instructionGraphNode); Nodes.Remove((TNode)instructionGraphNode2); node.Statements.Add(item3); return true; } return false; } private InstructionGraphNode? GetSingleSucc(InstructionGraphNode node) { if (node.Successors.Count != 1) { return null; } return node.Successors[0]; } protected virtual void DetermineLocals() { throw new NotImplementedException(); } private void ConstructConditions() { foreach (TNode node in Nodes) { if (node.IsConditionalBranch) { node.CheckCondition(); } } } private void CalculateUseDefs() { foreach (TNode node in Nodes) { foreach (TInstruction instruction in node.Instructions) { InstructionGraphUseDef instructionGraphUseDef = new InstructionGraphUseDef(); GetUseDefsForInstruction(instruction, instructionGraphUseDef); } } } protected virtual void GetUseDefsForInstruction(TInstruction instruction, InstructionGraphUseDef instructionGraphUseDef) { throw new NotImplementedException(); } protected virtual void SegmentGraph() { throw new NotImplementedException(); } protected virtual void BuildInitialGraph() { throw new NotImplementedException(); } private void ComputeDominators() { for (int i = 0; i < nodeSet.Count; i++) { nodeSet[i].Dominators = new BitArray(nodeSet.Count); nodeSet[i].Dominators.SetAll(value: true); nodeSet[i].ID = i; } Root.Dominators.SetAll(value: false); Root.Dominators.Set(Root.ID, value: true); BitArray bitArray = new BitArray(nodeSet.Count); bool flag = false; do { flag = false; foreach (TNode item in nodeSet) { if (item == Root) { continue; } foreach (InstructionGraphNode predecessor in item.Predecessors) { bitArray.SetAll(value: false); bitArray.Or(item.Dominators); item.Dominators.And(predecessor.Dominators); item.Dominators.Set(item.ID, value: true); if (!item.Dominators.BitsAreEqual(bitArray)) { flag = true; } } } } while (flag); } private void IdentifyLoops() { List>> list = new List>>(); foreach (TNode item in nodeSet) { if (item == Root) { continue; } foreach (InstructionGraphNode successor in item.Successors) { if (item.Dominators.Get(successor.ID)) { list.Add(GetLoopForEdge(successor, item)); } } } list = SortLoops(list); using List>>.Enumerator enumerator3 = list.GetEnumerator(); if (enumerator3.MoveNext()) { _ = enumerator3.Current; throw new NotImplementedException("Loops aren't currently implemented"); } } private List>> SortLoops(List>> loops) { return loops; } private InstructionGraphLoop> GetLoopForEdge(InstructionGraphNode header, InstructionGraphNode tail) { Stack> stack = new Stack>(); InstructionGraphLoop> instructionGraphLoop = new InstructionGraphLoop>(header); if (header != tail) { instructionGraphLoop.Nodes.Add(tail); stack.Push(tail); } while (stack.Count != 0) { foreach (InstructionGraphNode predecessor in stack.Pop().Predecessors) { if (!instructionGraphLoop.Nodes.Contains(predecessor)) { instructionGraphLoop.Nodes.Add(predecessor); stack.Push(predecessor); } } } return instructionGraphLoop; } protected TNode? FindNodeByAddress(ulong address) { if (InstructionsByAddress.TryGetValue(address, out var _)) { foreach (TNode node in Nodes) { if (node.Instructions.Any((TInstruction instr) => GetAddressOfInstruction(instr) == address)) { return node; } } } return null; } protected void AddDirectedEdge(TNode from, TNode to) { from.Successors.Add(to); to.Predecessors.Add(from); } protected void AddNode(TNode node) { nodeSet.Add(node); } public string Print(bool instructions = false) { StringBuilder stringBuilder = new StringBuilder(); foreach (TNode item in nodeSet) { stringBuilder.Append("=========================\n"); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(38, 4, stringBuilder2); handler.AppendLiteral("ID: "); handler.AppendFormatted(item.ID); handler.AppendLiteral(", FC: "); handler.AppendFormatted(item.FlowControl); handler.AppendLiteral(", Successors:"); handler.AppendFormatted(string.Join(",", item.Successors.Select((InstructionGraphNode i) => i.ID))); handler.AppendLiteral(", Predecessors:"); handler.AppendFormatted(string.Join(",", item.Predecessors.Select((InstructionGraphNode i) => i.ID))); stringBuilder3.Append(ref handler); if (item.IsConditionalBranch) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2); handler.AppendLiteral(", Condition: "); handler.AppendFormatted(item.Condition?.ConditionString ?? "Null"); stringBuilder4.Append(ref handler); } if (item.Instructions.Count > 0) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2); handler.AppendLiteral(", Address "); handler.AppendFormatted(item.GetFormattedInstructionAddress(item.Instructions.First())); stringBuilder5.Append(ref handler); } stringBuilder2 = stringBuilder; StringBuilder stringBuilder6 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(24, 1, stringBuilder2); handler.AppendLiteral(", Number of Statements: "); handler.AppendFormatted(item.Statements.Count); stringBuilder6.Append(ref handler); stringBuilder.Append("\n"); if (instructions) { foreach (TInstruction instruction in item.Instructions) { stringBuilder.AppendLine(instruction?.ToString()); } } else { foreach (IStatement statement in item.Statements) { stringBuilder.Append(statement.GetTextDump(0)); } } stringBuilder.Append('\n'); } return stringBuilder.ToString(); } } public class InstructionGraphCondition { public TInstruction Comparison { get; } public TInstruction Jump { get; } public string ConditionString { get; set; } public InstructionGraphCondition(TInstruction comparison, TInstruction conditionalJump) { Comparison = comparison; Jump = conditionalJump; ConditionString = GetCondition(); } public virtual string GetCondition(bool invert = false) { throw new NotImplementedException(); } public virtual void FlipCondition() { throw new NotImplementedException(); } public virtual string GetConditionOperator(bool invert = false) { throw new NotImplementedException(); } } public class InstructionGraphLoop { public TNode Header; public List Nodes; public InstructionGraphLoop(TNode header) { Header = header; Nodes = new List(); Nodes.Add(header); } } public class InstructionGraphNode : IControlFlowNode { private InstructionGraphNodeFlowControl? _flowControl; public bool HasProcessedSuccessors; public bool NeedsCorrectingDueToJump; public bool Visited; public BitArray? Dominators; public List TranslatedInstructions = new List(); public int ID { get; set; } public bool IsConditionalBranch => _flowControl == InstructionGraphNodeFlowControl.ConditionalJump; public InstructionGraphCondition? Condition { get; protected internal set; } public InstructionGraphNodeSet Successors { get; set; } public InstructionGraphNodeSet Predecessors { get; set; } public List Statements { get; } public InstructionGraphNodeFlowControl? FlowControl { get { return _flowControl; } set { _flowControl = value; } } public List Instructions { get; } = new List(); public InstructionGraphNode() { Instructions = new List(); Successors = new InstructionGraphNodeSet(); Predecessors = new InstructionGraphNodeSet(); Statements = new List(); } public void AddInstruction(TInstruction instruction) { Instructions.Add(instruction); } public void CheckCondition() { if (Successors.Count != 2) { throw new Exception($"Node didn't have 2 neighbours, instead had {Successors.Count}, aborting...\n\nNode Dump:\n{GetTextDump()}"); } InstructionGraphNode instructionGraphNode = this; while (!instructionGraphNode.ThisNodeHasComparison()) { if (instructionGraphNode.Predecessors.Count != 1) { throw new NodeConditionCalculationException("Don't have a comparison and don't have a single predecessor line to a node which has one"); } instructionGraphNode = instructionGraphNode.Predecessors.Single(); } TInstruction lastComparison = instructionGraphNode.GetLastComparison(); CreateCondition(lastComparison); if (Condition != null) { Instructions.Remove(Condition.Jump); instructionGraphNode.Instructions.Remove(lastComparison); } } protected virtual void CreateCondition(TInstruction comparison) { throw new NotImplementedException(); } protected virtual TInstruction GetLastComparison() { throw new NotImplementedException(); } protected string GetTextDump() { StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(19, 2, stringBuilder2); handler.AppendLiteral("ID: "); handler.AppendFormatted(ID); handler.AppendLiteral(", FlowControl: "); handler.AppendFormatted(_flowControl); stringBuilder3.Append(ref handler); if (IsConditionalBranch) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder2); handler.AppendLiteral(", Condition: "); handler.AppendFormatted(Condition?.ConditionString); stringBuilder4.Append(ref handler); } stringBuilder.Append('\n'); foreach (TInstruction instruction in Instructions) { string formattedInstructionAddress = GetFormattedInstructionAddress(instruction); TInstruction val = instruction; stringBuilder.AppendLine(formattedInstructionAddress + " " + val); } return stringBuilder.ToString(); } public virtual string GetFormattedInstructionAddress(TInstruction instruction) { throw new NotImplementedException(); } public virtual bool ThisNodeHasComparison() { throw new NotImplementedException(); } } public enum InstructionGraphNodeFlowControl { Continue, UnconditionalJump, ConditionalJump, IndirectJump, Call, IndirectCall, Return, NoReturn, Entry, Exit } public class InstructionGraphNodeSet : Collection> { } public class InstructionGraphStatement { public InstructionGraphCondition? Expression; public List>? Nodes; public InstructionGraphNode? ContinueNode; public InstructionGraphNode? BreakNode; public InstructionGraphStatementType Type { get; } public InstructionGraphStatement(InstructionGraphStatementType type) { Type = type; } } public enum InstructionGraphStatementType { Goto, If, DoWhile } public struct InstructionGraphUseDef { public List Uses; public List Definitions; public InstructionGraphUseDef() { Uses = new List(); Definitions = new List(); } } public class InstructionStatement : IStatement { public TInstruction Instruction { get; } public InstructionStatement(TInstruction instruction) { Instruction = instruction; } public string GetTextDump(int indent) { return new string(' ', indent) + Instruction?.ToString() + "\n"; } } public interface IStatement { string GetTextDump(int indent); } public class X86ControlFlowGraph : AbstractControlFlowGraph { public bool Is32Bit; private static HashSet _volatileRegisters = new HashSet { (Register)54, (Register)55, (Register)61, (Register)62, (Register)63, (Register)64, (Register)77, (Register)78, (Register)79, (Register)80, (Register)81, (Register)82 }; private static InstructionInfoFactory _instructionInfoFactory = new InstructionInfoFactory(); public X86ControlFlowGraph(List instructions, bool is32Bit, BaseKeyFunctionAddresses keyFunctionAddresses) : base(instructions, keyFunctionAddresses) { Is32Bit = is32Bit; } protected override ulong GetAddressOfInstruction(Instruction instruction) { return ((Instruction)(ref instruction)).IP; } protected override void SegmentGraph() { for (int i = 0; i < base.Nodes.Count; i++) { X86ControlFlowGraphNode x86ControlFlowGraphNode = base.Nodes[i]; if (!x86ControlFlowGraphNode.HasProcessedSuccessors) { InstructionGraphNodeFlowControl? flowControl = x86ControlFlowGraphNode.FlowControl; if (flowControl.HasValue && flowControl.GetValueOrDefault() == InstructionGraphNodeFlowControl.ConditionalJump) { FixNode(x86ControlFlowGraphNode); } x86ControlFlowGraphNode.HasProcessedSuccessors = true; } } } private void FixNode(X86ControlFlowGraphNode node, bool removeJmp = false) { //IL_0028: 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_008e: Unknown result type (might be due to invalid IL or missing references) if ((node.FlowControl ?? InstructionGraphNodeFlowControl.UnconditionalJump) == InstructionGraphNodeFlowControl.Continue) { return; } Instruction jump = node.Instructions.Last(); X86ControlFlowGraphNode x86ControlFlowGraphNode = FindNodeByAddress(((Instruction)(ref jump)).NearBranchTarget); if (x86ControlFlowGraphNode == null) { node.FlowControl = InstructionGraphNodeFlowControl.Call; return; } int index = x86ControlFlowGraphNode.Instructions.FindIndex((Instruction instruction) => ((Instruction)(ref instruction)).IP == ((Instruction)(ref jump)).NearBranchTarget); X86ControlFlowGraphNode to = SplitAndCreate(x86ControlFlowGraphNode, index); AddDirectedEdge(node, to); node.NeedsCorrectingDueToJump = false; if (removeJmp) { node.Instructions.Remove(jump); } } protected override void DetermineLocals() { TraverseNode(base.Root); } private void TraverseNode(InstructionGraphNode node) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) node.Visited = true; foreach (InstructionGraphNode successor in node.Successors) { if (!successor.Visited) { TraverseNode(successor); } } for (int i = 0; i < node.Instructions.Count; i++) { _ = node.Instructions[i]; } } protected unsafe override void GetUseDefsForInstruction(Instruction instruction, InstructionGraphUseDef instructionGraphUseDef) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0019: 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_0021: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected I4, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) InstructionInfo info = Unsafe.Read((void*)_instructionInfoFactory.GetInfo(ref instruction)); UsedRegisterIterator usedRegisters = ((InstructionInfo)(ref info)).GetUsedRegisters(); UsedRegisterIterator enumerator = ((UsedRegisterIterator)(ref usedRegisters)).GetEnumerator(); try { while (((UsedRegisterIterator)(ref enumerator)).MoveNext()) { UsedRegister current = ((UsedRegisterIterator)(ref enumerator)).Current; OpAccess access = ((UsedRegister)(ref current)).Access; Register fullRegister; switch (access - 1) { case 0: case 1: { List uses = instructionGraphUseDef.Uses; fullRegister = RegisterExtensions.GetFullRegister(((UsedRegister)(ref current)).Register); uses.Add(((object)(Register)(ref fullRegister)).ToString()); break; } case 2: case 3: { List definitions2 = instructionGraphUseDef.Definitions; fullRegister = RegisterExtensions.GetFullRegister(((UsedRegister)(ref current)).Register); definitions2.Add(((object)(Register)(ref fullRegister)).ToString()); break; } case 4: case 5: { fullRegister = RegisterExtensions.GetFullRegister(((UsedRegister)(ref current)).Register); string item = ((object)(Register)(ref fullRegister)).ToString(); instructionGraphUseDef.Uses.Add(item); List definitions = instructionGraphUseDef.Definitions; fullRegister = RegisterExtensions.GetFullRegister(((UsedRegister)(ref current)).Register); definitions.Add(((object)(Register)(ref fullRegister)).ToString()); break; } } } } finally { ((IDisposable)(UsedRegisterIterator)(ref enumerator)).Dispose(); } } private InstructionGraphNodeFlowControl GetAbstractControlFlow(FlowControl flowControl) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected I4, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) return (int)flowControl switch { 5 => InstructionGraphNodeFlowControl.Call, 1 => InstructionGraphNodeFlowControl.UnconditionalJump, 6 => InstructionGraphNodeFlowControl.IndirectCall, 4 => InstructionGraphNodeFlowControl.Return, 0 => InstructionGraphNodeFlowControl.Continue, 7 => InstructionGraphNodeFlowControl.NoReturn, 3 => InstructionGraphNodeFlowControl.ConditionalJump, 2 => InstructionGraphNodeFlowControl.IndirectJump, _ => throw new NotImplementedException($"Flow control {flowControl} not supported"), }; } protected override void BuildInitialGraph() { //IL_006c: 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_0075: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected I4, but got Unknown //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: 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_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_0146: Unknown result type (might be due to invalid IL or missing references) X86ControlFlowGraphNode x86ControlFlowGraphNode = new X86ControlFlowGraphNode { ID = idCounter++ }; AddNode(x86ControlFlowGraphNode); AddDirectedEdge(base.Root, x86ControlFlowGraphNode); int i; for (i = 0; i < Instructions.Count; i++) { bool flag = i == Instructions.Count - 1; Instruction val = Instructions[i]; FlowControl flowControl = ((Instruction)(ref val)).FlowControl; switch ((int)flowControl) { case 1: x86ControlFlowGraphNode.AddInstruction(Instructions[i]); if (!flag) { X86ControlFlowGraphNode x86ControlFlowGraphNode8 = new X86ControlFlowGraphNode { ID = idCounter++ }; AddNode(x86ControlFlowGraphNode8); if (!Instructions.Any(delegate(Instruction instruction) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) ulong iP = ((Instruction)(ref instruction)).IP; Instruction val2 = Instructions[i]; return iP == ((Instruction)(ref val2)).NearBranchTarget; })) { AddDirectedEdge(x86ControlFlowGraphNode, ExitNode); } else { x86ControlFlowGraphNode.NeedsCorrectingDueToJump = true; } X86ControlFlowGraphNode x86ControlFlowGraphNode9 = x86ControlFlowGraphNode; val = Instructions[i]; x86ControlFlowGraphNode9.FlowControl = GetAbstractControlFlow(((Instruction)(ref val)).FlowControl); x86ControlFlowGraphNode = x86ControlFlowGraphNode8; } else { AddDirectedEdge(x86ControlFlowGraphNode, ExitNode); x86ControlFlowGraphNode.NeedsCorrectingDueToJump = true; } break; case 5: case 6: x86ControlFlowGraphNode.AddInstruction(Instructions[i]); if (!flag) { X86ControlFlowGraphNode x86ControlFlowGraphNode6 = new X86ControlFlowGraphNode { ID = idCounter++ }; AddNode(x86ControlFlowGraphNode6); AddDirectedEdge(x86ControlFlowGraphNode, x86ControlFlowGraphNode6); X86ControlFlowGraphNode x86ControlFlowGraphNode7 = x86ControlFlowGraphNode; val = Instructions[i]; x86ControlFlowGraphNode7.FlowControl = GetAbstractControlFlow(((Instruction)(ref val)).FlowControl); x86ControlFlowGraphNode = x86ControlFlowGraphNode6; } else { AddDirectedEdge(x86ControlFlowGraphNode, ExitNode); } break; case 0: x86ControlFlowGraphNode.AddInstruction(Instructions[i]); if (!flag) { } break; case 4: { x86ControlFlowGraphNode.AddInstruction(Instructions[i]); X86ControlFlowGraphNode x86ControlFlowGraphNode10 = new X86ControlFlowGraphNode { ID = idCounter++ }; AddNode(x86ControlFlowGraphNode10); AddDirectedEdge(x86ControlFlowGraphNode, ExitNode); X86ControlFlowGraphNode x86ControlFlowGraphNode11 = x86ControlFlowGraphNode; val = Instructions[i]; x86ControlFlowGraphNode11.FlowControl = GetAbstractControlFlow(((Instruction)(ref val)).FlowControl); x86ControlFlowGraphNode = x86ControlFlowGraphNode10; break; } case 3: x86ControlFlowGraphNode.AddInstruction(Instructions[i]); if (!flag) { X86ControlFlowGraphNode x86ControlFlowGraphNode4 = new X86ControlFlowGraphNode { ID = idCounter++ }; AddNode(x86ControlFlowGraphNode4); AddDirectedEdge(x86ControlFlowGraphNode, x86ControlFlowGraphNode4); X86ControlFlowGraphNode x86ControlFlowGraphNode5 = x86ControlFlowGraphNode; val = Instructions[i]; x86ControlFlowGraphNode5.FlowControl = GetAbstractControlFlow(((Instruction)(ref val)).FlowControl); x86ControlFlowGraphNode = x86ControlFlowGraphNode4; } else { AddDirectedEdge(x86ControlFlowGraphNode, ExitNode); } break; case 7: { x86ControlFlowGraphNode.AddInstruction(Instructions[i]); X86ControlFlowGraphNode x86ControlFlowGraphNode2 = new X86ControlFlowGraphNode { ID = idCounter++ }; AddNode(x86ControlFlowGraphNode2); AddDirectedEdge(x86ControlFlowGraphNode, ExitNode); X86ControlFlowGraphNode x86ControlFlowGraphNode3 = x86ControlFlowGraphNode; val = Instructions[i]; x86ControlFlowGraphNode3.FlowControl = GetAbstractControlFlow(((Instruction)(ref val)).FlowControl); x86ControlFlowGraphNode = x86ControlFlowGraphNode2; break; } case 2: throw new NotImplementedException("Indirect branch not implemented currently"); default: { val = Instructions[i]; string? text = ((object)(Instruction)(ref val)).ToString(); val = Instructions[i]; FlowControl flowControl2 = ((Instruction)(ref val)).FlowControl; throw new NotImplementedException(text + " " + ((object)(FlowControl)(ref flowControl2)).ToString()); } } } for (int j = 0; j < base.Nodes.Count; j++) { X86ControlFlowGraphNode x86ControlFlowGraphNode12 = base.Nodes[j]; if (x86ControlFlowGraphNode12.NeedsCorrectingDueToJump) { FixNode(x86ControlFlowGraphNode12, removeJmp: true); } } } private void CleanUp() { List list = new List(); foreach (X86ControlFlowGraphNode node in base.Nodes) { if (node.Successors.Count == 0 && node.Predecessors.Count == 0) { list.Add(node); } } foreach (X86ControlFlowGraphNode item in list) { base.Nodes.Remove(item); } } } public class X86InstructionGraphCondition : InstructionGraphCondition { private static MasmFormatter _formatter = new MasmFormatter(); private static StringOutput _output = new StringOutput(); public X86InstructionGraphCondition(Instruction comparison, Instruction conditionalJump) : base(comparison, conditionalJump) { }//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) public override string GetCondition(bool invert = false) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_0147: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //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_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0200: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_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_0031: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) Instruction comparison = base.Comparison; if ((int)((Instruction)(ref comparison)).Mnemonic == 751) { comparison = base.Comparison; if ((int)((Instruction)(ref comparison)).Op0Kind == 0) { comparison = base.Comparison; if ((int)((Instruction)(ref comparison)).Op1Kind == 0) { comparison = base.Comparison; Register op0Register = ((Instruction)(ref comparison)).Op0Register; comparison = base.Comparison; if (op0Register == ((Instruction)(ref comparison)).Op1Register) { MasmFormatter formatter = _formatter; comparison = base.Comparison; ((Formatter)formatter).FormatOperand(ref comparison, (FormatterOutput)(object)_output, 0); return _output.ToStringAndReset() + " " + GetConditionOperator(invert) + " 0"; } } } MasmFormatter formatter2 = _formatter; comparison = base.Comparison; ((Formatter)formatter2).FormatOperand(ref comparison, (FormatterOutput)(object)_output, 0); string value = _output.ToStringAndReset(); MasmFormatter formatter3 = _formatter; comparison = base.Comparison; ((Formatter)formatter3).FormatOperand(ref comparison, (FormatterOutput)(object)_output, 1); string value2 = _output.ToStringAndReset(); return $"({value} & {value2}) {GetConditionOperator(invert)} 0"; } comparison = base.Comparison; if ((int)((Instruction)(ref comparison)).Mnemonic == 93) { MasmFormatter formatter4 = _formatter; comparison = base.Comparison; ((Formatter)formatter4).FormatOperand(ref comparison, (FormatterOutput)(object)_output, 0); string value3 = _output.ToStringAndReset(); MasmFormatter formatter5 = _formatter; comparison = base.Comparison; ((Formatter)formatter5).FormatOperand(ref comparison, (FormatterOutput)(object)_output, 1); string value4 = _output.ToStringAndReset(); return $"{value3} {GetConditionOperator(invert)} {value4}"; } DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(27, 1); defaultInterpolatedStringHandler.AppendLiteral("Don't know what to do with "); comparison = base.Comparison; defaultInterpolatedStringHandler.AppendFormatted(((Instruction)(ref comparison)).Mnemonic); throw new Exception(defaultInterpolatedStringHandler.ToStringAndClear()); } public override void FlipCondition() { base.ConditionString = GetCondition(invert: true); } public override string GetConditionOperator(bool invert = false) { //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_0009: 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_000f: 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_006f: Expected I4, but got Unknown //IL_011d: 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_0125: Unknown result type (might be due to invalid IL or missing references) Instruction jump = base.Jump; Mnemonic mnemonic = ((Instruction)(ref jump)).Mnemonic; switch (mnemonic - 297) { case 5: if (!invert) { return "!="; } return "=="; case 13: if (!invert) { return "=="; } return "!="; case 7: if (!invert) { return "<"; } return ">"; case 8: if (!invert) { return "<="; } return ">="; case 9: case 20: if (!invert) { return ">"; } return "<"; case 10: if (!invert) { return ">="; } return "<="; case 0: if (!invert) { return "<"; } return ">"; case 1: case 16: if (!invert) { return "<="; } return ">="; case 2: if (!invert) { return ">"; } return "<"; case 3: if (!invert) { return ">="; } return "<="; case 18: return "has parity idk todo"; default: { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(26, 1); jump = base.Jump; defaultInterpolatedStringHandler.AppendFormatted(((Instruction)(ref jump)).Mnemonic); defaultInterpolatedStringHandler.AppendLiteral(" isn't supported currently"); throw new Exception(defaultInterpolatedStringHandler.ToStringAndClear()); } } } } public class X86ControlFlowGraphNode : InstructionGraphNode { public override string GetFormattedInstructionAddress(Instruction instruction) { return "0x" + ((Instruction)(ref instruction)).IP.ToString("X8").ToUpperInvariant(); } public override bool ThisNodeHasComparison() { return base.Instructions.Any(delegate(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: 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 instruction)).Mnemonic; return (int)mnemonic == 93 || (int)mnemonic == 751; }); } protected override Instruction GetLastComparison() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) return base.Instructions.Last(delegate(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_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 Mnemonic mnemonic = ((Instruction)(ref instruction)).Mnemonic; return (int)mnemonic == 751 || (int)mnemonic == 93; }); } protected override void CreateCondition(Instruction comparison) { //IL_0006: 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_000d: 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) Instruction conditionalJump = base.Instructions.Last(); base.Condition = new X86InstructionGraphCondition(comparison, conditionalJump); } } } namespace Cpp2IL.Core.Extensions { internal static class ArrayExtensions { public static bool Contains(this T[] array, T item) { return Array.IndexOf(array, item) >= 0; } } 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_000a: Invalid comparison between Unknown and I4 //IL_000c: 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 ArmOperandType type = operand.Type; return (int)type == 64 || (int)type == 2 || (int)type == 65; } 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_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 Arm64OperandType type = operand.Type; return (int)type == 64 || (int)type == 2; } 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); Array.Reverse(array); return new List(array); } 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(); } public 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 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(); } } } namespace Cpp2IL.Core.Exceptions { public class DllSaveException : Exception { public string FullPath { get; } public Exception Cause { get; } public DllSaveException(string fullPath, Exception cause) : base("Fatal Exception writing DLL " + fullPath, cause) { FullPath = fullPath; Cause = 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 IsilConversionException : Exception { public string Reason { get; } public IsilConversionException(string message) : base("Failed to convert to ISIL. Reason: " + message) { Reason = message; } } 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(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); } 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 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; } } }