diff --git a/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs b/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs index 19874ad23..802f2424b 100644 --- a/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs +++ b/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs @@ -1,5 +1,3 @@ -using NUnit.Framework; - namespace Cpp2IL.Core.Tests; public class Cpp2IlApiTests diff --git a/Cpp2IL.Core/Api/Cpp2IlPlugin.cs b/Cpp2IL.Core/Api/Cpp2IlPlugin.cs index 60a25ff17..27a9e0d53 100644 --- a/Cpp2IL.Core/Api/Cpp2IlPlugin.cs +++ b/Cpp2IL.Core/Api/Cpp2IlPlugin.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using Cpp2IL.Core.Logging; using LibCpp2IL; namespace Cpp2IL.Core.Api; diff --git a/Cpp2IL.Core/Cpp2IlApi.cs b/Cpp2IL.Core/Cpp2IlApi.cs index b557ae3c9..c26731e0a 100644 --- a/Cpp2IL.Core/Cpp2IlApi.cs +++ b/Cpp2IL.Core/Cpp2IlApi.cs @@ -51,7 +51,7 @@ public static void ConfigureLib(bool allowUserToInputAddresses) LibCpp2IlMain.Settings.MetadataFixupFunc = Cpp2IlPluginManager.MetadataFixupFuncs is { } funcs ? (originalBytes, version) => { Logger.InfoNewline("Received request for metadata fixup from LibCpp2Il. Calling registered plugin fixup functions..."); - + foreach (var func in funcs) { try @@ -68,7 +68,7 @@ public static void ConfigureLib(bool allowUserToInputAddresses) Logger.ErrorNewline($"Metadata fixup function threw an exception: {e}. Ignoring and trying next fixup function, if any..."); } } - + //only get here if every fixup function returns null or throws. return null; } : null; @@ -85,20 +85,16 @@ public static void InitializeLibCpp2Il(string assemblyPath, string metadataPath, ConfigureLib(allowUserToInputAddresses); -#if !DEBUG - try - { -#endif - if (!LibCpp2IlMain.LoadFromFile(assemblyPath, metadataPath, unityVersion)) - throw new Exception("Initialization with LibCpp2Il failed"); -#if !DEBUG - } - catch (Exception e) - { - throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", e); - } -#endif - OnLibInitialized(); + try + { + var context = LibCpp2IlMain.LoadFromFileAsContext(assemblyPath, metadataPath, unityVersion); + OnLibInitialized(context); + } + catch (Exception e) + { + throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", e); + } + } [MemberNotNull(nameof(CurrentAppContext))] @@ -112,27 +108,24 @@ public static void InitializeLibCpp2Il(byte[] assemblyData, byte[] metadataData, try { - if (!LibCpp2IlMain.Initialize(assemblyData, metadataData, unityVersion)) - throw new Exception("Initialization with LibCpp2Il failed"); + var context = LibCpp2IlMain.InitializeAsContext(assemblyData, metadataData, unityVersion); + OnLibInitialized(context); } catch (Exception e) { throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", e); } - - OnLibInitialized(); } [MemberNotNull(nameof(CurrentAppContext))] - private static void OnLibInitialized() + private static void OnLibInitialized(LibCpp2IlContext libContext) { - MiscUtils.Init(); - LibCpp2IlMain.Binary!.AllCustomAttributeGenerators.ToList() + libContext.Binary.AllCustomAttributeGenerators.ToList() .ForEach(ptr => SharedState.AttributeGeneratorStarts.Add(ptr)); var start = DateTime.Now; Logger.InfoNewline("Creating application model..."); - CurrentAppContext = new(LibCpp2IlMain.Binary, LibCpp2IlMain.TheMetadata!); + CurrentAppContext = new(libContext); Logger.InfoNewline($"Application model created in {(DateTime.Now - start).TotalMilliseconds}ms"); } @@ -144,8 +137,6 @@ public static void ResetInternalState() AsmResolverUtils.Reset(); - LibCpp2IlMain.Reset(); - CurrentAppContext = null; } @@ -176,6 +167,6 @@ public static void ResetInternalState() private static bool IsLibInitialized() { - return LibCpp2IlMain.Binary != null && LibCpp2IlMain.TheMetadata != null; + return CurrentAppContext != null; } } diff --git a/Cpp2IL.Core/Exceptions/UnsupportedInstructionSetException.cs b/Cpp2IL.Core/Exceptions/UnsupportedInstructionSetException.cs index bcf9402ef..6853a1f91 100644 --- a/Cpp2IL.Core/Exceptions/UnsupportedInstructionSetException.cs +++ b/Cpp2IL.Core/Exceptions/UnsupportedInstructionSetException.cs @@ -1,9 +1,8 @@ -using System; -using LibCpp2IL; +using System; namespace Cpp2IL.Core.Exceptions; -public class UnsupportedInstructionSetException : Exception +public class UnsupportedInstructionSetException(string? instructionSetId = null) : 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."; + public override string Message => $"This action is not supported on the {instructionSetId ?? "unknown"} instruction set yet. If running the CLI, try adding the --skip-analysis argument."; } diff --git a/Cpp2IL.Core/Graphs/ISILControlFlowGraph.cs b/Cpp2IL.Core/Graphs/ISILControlFlowGraph.cs index c4ac34a25..1397e52d3 100644 --- a/Cpp2IL.Core/Graphs/ISILControlFlowGraph.cs +++ b/Cpp2IL.Core/Graphs/ISILControlFlowGraph.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Text; using Cpp2IL.Core.ISIL; namespace Cpp2IL.Core.Graphs; diff --git a/Cpp2IL.Core/Graphs/Processors/CallProcessor.cs b/Cpp2IL.Core/Graphs/Processors/CallProcessor.cs index a3f3784f5..f306a8c4c 100644 --- a/Cpp2IL.Core/Graphs/Processors/CallProcessor.cs +++ b/Cpp2IL.Core/Graphs/Processors/CallProcessor.cs @@ -1,4 +1,3 @@ -using System.Linq; using Cpp2IL.Core.Il2CppApiFunctions; using Cpp2IL.Core.ISIL; using Cpp2IL.Core.Model.Contexts; diff --git a/Cpp2IL.Core/Graphs/Processors/MetadataProcessor.cs b/Cpp2IL.Core/Graphs/Processors/MetadataProcessor.cs index 19ad5bdbb..5130da711 100644 --- a/Cpp2IL.Core/Graphs/Processors/MetadataProcessor.cs +++ b/Cpp2IL.Core/Graphs/Processors/MetadataProcessor.cs @@ -1,8 +1,6 @@ -using System.Linq; using Cpp2IL.Core.ISIL; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Utils; -using LibCpp2IL; namespace Cpp2IL.Core.Graphs.Processors; @@ -26,11 +24,11 @@ public void Process(MethodAnalysisContext methodAnalysisContext, Block block) var memoryOp = (IsilMemoryOperand)instruction.Operands[1].Data; if (memoryOp.Base == null && memoryOp.Index == null && memoryOp.Scale == 0) { - var val = LibCpp2IlMain.GetLiteralByAddress((ulong)memoryOp.Addend); + var val = methodAnalysisContext.AppContext.LibCpp2IlContext.GetLiteralByAddress((ulong)memoryOp.Addend); if (val == null) { // Try instead check if its type metadata usage - var metadataUsage = LibCpp2IlMain.GetTypeGlobalByAddress((ulong)memoryOp.Addend); + var metadataUsage = methodAnalysisContext.AppContext.LibCpp2IlContext.GetTypeGlobalByAddress((ulong)memoryOp.Addend); if (metadataUsage != null && methodAnalysisContext.DeclaringType is not null) { var typeAnalysisContext = metadataUsage.ToContext(methodAnalysisContext.DeclaringType!.DeclaringAssembly); diff --git a/Cpp2IL.Core/ISIL/InstructionSetIndependentInstruction.cs b/Cpp2IL.Core/ISIL/InstructionSetIndependentInstruction.cs index fac7931a0..9d5cb7813 100644 --- a/Cpp2IL.Core/ISIL/InstructionSetIndependentInstruction.cs +++ b/Cpp2IL.Core/ISIL/InstructionSetIndependentInstruction.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Cpp2IL.Core.ISIL; public class InstructionSetIndependentInstruction : IsilOperandData diff --git a/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs b/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs index de75395cc..78c834d18 100644 --- a/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs +++ b/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs @@ -1,4 +1,3 @@ -using System; using System.Linq; using Cpp2IL.Core.Extensions; diff --git a/Cpp2IL.Core/ISIL/IsilBuilder.cs b/Cpp2IL.Core/ISIL/IsilBuilder.cs index ca94f17f7..d6bdd256b 100644 --- a/Cpp2IL.Core/ISIL/IsilBuilder.cs +++ b/Cpp2IL.Core/ISIL/IsilBuilder.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Cpp2IL.Core.Exceptions; namespace Cpp2IL.Core.ISIL; diff --git a/Cpp2IL.Core/ISIL/IsilVectorRegisterElementOperand.cs b/Cpp2IL.Core/ISIL/IsilVectorRegisterElementOperand.cs index e1fe49aa7..7afa0b8f2 100644 --- a/Cpp2IL.Core/ISIL/IsilVectorRegisterElementOperand.cs +++ b/Cpp2IL.Core/ISIL/IsilVectorRegisterElementOperand.cs @@ -1,6 +1,3 @@ -using System; -using System.Globalization; - namespace Cpp2IL.Core.ISIL; public readonly struct IsilVectorRegisterElementOperand( diff --git a/Cpp2IL.Core/Il2CppApiFunctions/Arm64KeyFunctionAddresses.cs b/Cpp2IL.Core/Il2CppApiFunctions/Arm64KeyFunctionAddresses.cs index 189e9cc95..b18a93dea 100644 --- a/Cpp2IL.Core/Il2CppApiFunctions/Arm64KeyFunctionAddresses.cs +++ b/Cpp2IL.Core/Il2CppApiFunctions/Arm64KeyFunctionAddresses.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Cpp2IL.Core.Extensions; @@ -9,7 +9,6 @@ using Gee.External.Capstone.Arm64; using LibCpp2IL; using LibCpp2IL.NintendoSwitch; -using LibCpp2IL.Reflection; namespace Cpp2IL.Core.Il2CppApiFunctions; @@ -195,7 +194,7 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max protected override ulong GetObjectIsInstFromSystemType() { Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst..."); - var typeIsInstanceOfType = LibCpp2IlReflection.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType"); + var typeIsInstanceOfType = ReflectionCache.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType"); if (typeIsInstanceOfType == null) { Logger.VerboseNewline("Type or method not found, aborting."); @@ -208,7 +207,7 @@ protected override ulong GetObjectIsInstFromSystemType() //The last call is to Object::IsInst Logger.Verbose($"IsInstanceOfType found at 0x{typeIsInstanceOfType.MethodPointer:X}..."); - var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(typeIsInstanceOfType.MethodPointer, false); + var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext.Binary, typeIsInstanceOfType.MethodPointer, false); var lastCall = instructions.LastOrDefault(i => i.Mnemonic == "bl"); @@ -253,12 +252,12 @@ protected override void AttemptInstructionAnalysisToFillGaps() if (il2cpp_object_new == 0) { Logger.Verbose("\tAttempting to use Array GetEnumerator to find il2cpp_codegen_object_new..."); - if (LibCpp2IlReflection.GetType("Array", "System") is { } arrayTypeDef) + if (ReflectionCache.GetType("Array", "System") is { } arrayTypeDef) { if (arrayTypeDef.Methods!.FirstOrDefault(m => m.Name == "GetEnumerator") is { } methodDef) { var ptr = methodDef.MethodPointer; - var body = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(ptr); + var body = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext.Binary, ptr); //Looking for adrp, ldr, ldr, bl. Probably more than one - the first will be initializing the method, second will be the constructor call var probableResult = 0L; diff --git a/Cpp2IL.Core/Il2CppApiFunctions/BaseKeyFunctionAddresses.cs b/Cpp2IL.Core/Il2CppApiFunctions/BaseKeyFunctionAddresses.cs index 5fac4f97b..c02cdca2c 100644 --- a/Cpp2IL.Core/Il2CppApiFunctions/BaseKeyFunctionAddresses.cs +++ b/Cpp2IL.Core/Il2CppApiFunctions/BaseKeyFunctionAddresses.cs @@ -52,7 +52,10 @@ public abstract class BaseKeyFunctionAddresses public IEnumerable> Pairs => resolvedAddressMap; - private ApplicationAnalysisContext _appContext = null!; //Always initialized before used + protected ApplicationAnalysisContext _appContext = null!; //Always initialized before used + + protected LibCpp2IlReflectionCache ReflectionCache => + _appContext.LibCpp2IlContext.ReflectionCache; private readonly Dictionary resolvedAddressMap = []; private readonly HashSet resolvedAddressSet = []; @@ -124,14 +127,14 @@ protected void TryGetInitMetadataFromException() //Exception.get_Message() - first call is either to codegen_initialize_method (< v27) or codegen_initialize_runtime_metadata Logger.VerboseNewline("\tLooking for Type System.Exception, Method get_Message..."); - var type = LibCpp2IlReflection.GetType("Exception", "System")!; + var type = ReflectionCache.GetType("Exception", "System")!; Logger.VerboseNewline("\t\tType Located. Ensuring method exists..."); var targetMethod = type.Methods!.FirstOrDefault(m => m.Name == "get_Message"); if (targetMethod != null) //Check struct contains valid data { Logger.VerboseNewline($"\t\tTarget Method Located at {targetMethod.MethodPointer}. Taking first CALL as the (version-specific) metadata initialization function..."); - var disasm = X86Utils.GetMethodBodyAtVirtAddressNew(targetMethod.MethodPointer, false); + var disasm = X86Utils.GetMethodBodyAtVirtAddressNew(targetMethod.MethodPointer, false, _appContext.Binary); var calls = disasm.Where(i => i.Mnemonic == Mnemonic.Call).ToList(); if (calls.Count == 0) @@ -294,6 +297,7 @@ private void FindThunks() protected virtual void Init(ApplicationAnalysisContext context) { + _appContext = context; } private void InitializeResolvedAddresses() diff --git a/Cpp2IL.Core/Il2CppApiFunctions/Il2CppApiFunction.cs b/Cpp2IL.Core/Il2CppApiFunctions/Il2CppApiFunction.cs index c2af4a429..d392d795a 100644 --- a/Cpp2IL.Core/Il2CppApiFunctions/Il2CppApiFunction.cs +++ b/Cpp2IL.Core/Il2CppApiFunctions/Il2CppApiFunction.cs @@ -1,5 +1,3 @@ -using System; - namespace Cpp2IL.Core.Il2CppApiFunctions; public class Il2CppApiFunction diff --git a/Cpp2IL.Core/Il2CppApiFunctions/NewArm64KeyFunctionAddresses.cs b/Cpp2IL.Core/Il2CppApiFunctions/NewArm64KeyFunctionAddresses.cs index 96a1ce65f..873bd73f3 100644 --- a/Cpp2IL.Core/Il2CppApiFunctions/NewArm64KeyFunctionAddresses.cs +++ b/Cpp2IL.Core/Il2CppApiFunctions/NewArm64KeyFunctionAddresses.cs @@ -1,11 +1,8 @@ -using System; using System.Collections.Generic; using System.Linq; using Disarm; using Cpp2IL.Core.Logging; using Cpp2IL.Core.Utils; -using LibCpp2IL; -using LibCpp2IL.Reflection; namespace Cpp2IL.Core.Il2CppApiFunctions; @@ -17,8 +14,9 @@ private List DisassembleTextSection() { if (_cachedDisassembledBytes == null) { - var toDisasm = LibCpp2IlMain.Binary!.GetEntirePrimaryExecutableSection(); - _cachedDisassembledBytes = Disassembler.Disassemble(toDisasm, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection(), new(true, true, false)).ToList(); + var binary = _appContext.Binary; + var toDisasm = binary.GetEntirePrimaryExecutableSection(); + _cachedDisassembledBytes = Disassembler.Disassemble(toDisasm, binary.GetVirtualAddressOfPrimaryExecutableSection(), new(true, true, false)).ToList(); } return _cachedDisassembledBytes; @@ -37,13 +35,14 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max if (addressesToIgnore.Contains(matchingJmp.Address)) continue; //Find this instruction in the raw file - var offsetInPe = (ulong)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(matchingJmp.Address); - if (offsetInPe == 0 || offsetInPe == (ulong)(LibCpp2IlMain.Binary.RawLength - 1)) + var binary = _appContext.Binary; + var offsetInPe = (ulong)binary.MapVirtualAddressToRaw(matchingJmp.Address); + if (offsetInPe == 0 || offsetInPe == (ulong)(binary.RawLength - 1)) continue; //get next and previous bytes - var previousByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe - 1); - var nextByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe + 4); + var previousByte = binary.GetByteAtRawAddress(offsetInPe - 1); + var nextByte = binary.GetByteAtRawAddress(offsetInPe + 4); //Double-cc = thunk if (previousByte == 0xCC && nextByte == 0xCC) @@ -60,7 +59,7 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max //Move to next jmp break; - if (LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC) + if (binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC) { yield return matchingJmp.Address - (backtrack - 1); break; @@ -73,7 +72,7 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max protected override ulong GetObjectIsInstFromSystemType() { Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst..."); - var typeIsInstanceOfType = LibCpp2IlReflection.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType"); + var typeIsInstanceOfType = ReflectionCache.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType"); if (typeIsInstanceOfType == null) { Logger.VerboseNewline("Type or method not found, aborting."); @@ -86,7 +85,7 @@ protected override ulong GetObjectIsInstFromSystemType() //The last call is to Object::IsInst Logger.Verbose($"IsInstanceOfType found at 0x{typeIsInstanceOfType.MethodPointer:X}..."); - var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(typeIsInstanceOfType.MethodPointer, true); + var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext.Binary, typeIsInstanceOfType.MethodPointer, true); var lastCall = instructions.LastOrDefault(i => i.Mnemonic == Arm64Mnemonic.BL); @@ -102,7 +101,7 @@ protected override ulong GetObjectIsInstFromSystemType() protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false) { - var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(thunkPtr, true); + var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext.Binary, thunkPtr, true); var target = prioritiseCall ? Arm64Mnemonic.BL : Arm64Mnemonic.B; var matchingCall = instructions.FirstOrDefault(i => i.Mnemonic == target); diff --git a/Cpp2IL.Core/Il2CppApiFunctions/X86KeyFunctionAddresses.cs b/Cpp2IL.Core/Il2CppApiFunctions/X86KeyFunctionAddresses.cs index d8deb5439..ccb49b762 100644 --- a/Cpp2IL.Core/Il2CppApiFunctions/X86KeyFunctionAddresses.cs +++ b/Cpp2IL.Core/Il2CppApiFunctions/X86KeyFunctionAddresses.cs @@ -1,12 +1,9 @@ -using System; using System.Collections.Generic; using System.Linq; using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Utils; using Iced.Intel; -using LibCpp2IL; -using LibCpp2IL.Reflection; namespace Cpp2IL.Core.Il2CppApiFunctions; @@ -18,8 +15,9 @@ private InstructionList DisassembleTextSection() { if (_cachedDisassembledBytes == null) { - var toDisasm = LibCpp2IlMain.Binary!.GetEntirePrimaryExecutableSection(); - _cachedDisassembledBytes = X86Utils.Disassemble(toDisasm, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection()); + var binary = _appContext.Binary; + var toDisasm = binary.GetEntirePrimaryExecutableSection(); + _cachedDisassembledBytes = X86Utils.Disassemble(toDisasm, binary.GetVirtualAddressOfPrimaryExecutableSection(), binary.is32Bit); } return _cachedDisassembledBytes; @@ -45,13 +43,14 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max if (addressesToIgnore.Contains(matchingJmp.IP)) continue; //Find this instruction in the raw file - var offsetInPe = (ulong)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(matchingJmp.IP); - if (offsetInPe == 0 || offsetInPe == (ulong)(LibCpp2IlMain.Binary!.RawLength - 1)) + var binary = _appContext.Binary; + var offsetInPe = (ulong)binary.MapVirtualAddressToRaw(matchingJmp.IP); + if (offsetInPe == 0 || offsetInPe == (ulong)(binary.RawLength - 1)) continue; //get next and previous bytes - var previousByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe - 1); - var nextByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe + (ulong)matchingJmp.Length); + var previousByte = binary.GetByteAtRawAddress(offsetInPe - 1); + var nextByte = binary.GetByteAtRawAddress(offsetInPe + (ulong)matchingJmp.Length); //Double-cc = thunk if (previousByte == 0xCC && nextByte == 0xCC) @@ -68,7 +67,7 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max //Move to next jmp break; - if (LibCpp2IlMain.Binary!.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC) + if (binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC) { yield return matchingJmp.IP - (backtrack - 1); break; @@ -81,7 +80,7 @@ protected override IEnumerable FindAllThunkFunctions(ulong addr, uint max protected override ulong GetObjectIsInstFromSystemType() { Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst..."); - var typeIsInstanceOfType = LibCpp2IlReflection.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType"); + var typeIsInstanceOfType = ReflectionCache.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType"); if (typeIsInstanceOfType == null) { Logger.VerboseNewline("Type or method not found, aborting."); @@ -94,7 +93,7 @@ protected override ulong GetObjectIsInstFromSystemType() //The last call is to Object::IsInst Logger.Verbose($"IsInstanceOfType found at 0x{typeIsInstanceOfType.MethodPointer:X}..."); - var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(typeIsInstanceOfType.MethodPointer, true); + var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(typeIsInstanceOfType.MethodPointer, true, _appContext.Binary); var lastCall = instructions.LastOrDefault(i => i.Mnemonic == Mnemonic.Call); @@ -110,7 +109,7 @@ protected override ulong GetObjectIsInstFromSystemType() protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false) { - var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(thunkPtr, true); + var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(thunkPtr, true, _appContext.Binary); var target = prioritiseCall ? Mnemonic.Call : Mnemonic.Jmp; var matchingCall = instructions.FirstOrDefault(i => i.Mnemonic == target); diff --git a/Cpp2IL.Core/Il2CppArrayUtils.cs b/Cpp2IL.Core/Il2CppArrayUtils.cs index 1880e0b4b..7577fa498 100644 --- a/Cpp2IL.Core/Il2CppArrayUtils.cs +++ b/Cpp2IL.Core/Il2CppArrayUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using LibCpp2IL; @@ -7,7 +7,7 @@ namespace Cpp2IL.Core; public static class Il2CppArrayUtils { - public static uint FirstItemOffset = (uint)(LibCpp2IlMain.Binary!.is32Bit ? 0x10 : 0x20); + public static uint GetFirstItemOffset(Il2CppBinary binary) => (uint)(binary.is32Bit ? 0x10 : 0x20); //32-bit: //0x0: klass ptr //0x4: monitor ptr @@ -23,21 +23,21 @@ public static class Il2CppArrayUtils new UsefulOffset("length", 0x18, typeof(int), false) ]; - public static string? GetOffsetName(uint offset) + public static string? GetOffsetName(uint offset, Il2CppBinary binary) { - var is32Bit = LibCpp2IlMain.Binary!.is32Bit; + var is32Bit = binary.is32Bit; return UsefulOffsets.FirstOrDefault(o => o.is32Bit == is32Bit && o.offset == offset)?.name; } - public static bool IsIl2cppLengthAccessor(uint offset) + public static bool IsIl2cppLengthAccessor(uint offset, Il2CppBinary binary) { - return GetOffsetName(offset) == "length"; + return GetOffsetName(offset, binary) == "length"; } - public static bool IsAtLeastFirstItemPtr(uint offset) + public static bool IsAtLeastFirstItemPtr(uint offset, Il2CppBinary binary) { - return offset >= FirstItemOffset; + return offset >= GetFirstItemOffset(binary); } public class UsefulOffset(string name, uint offset, Type type, bool is32Bit) diff --git a/Cpp2IL.Core/Il2CppClassUsefulOffsets.cs b/Cpp2IL.Core/Il2CppClassUsefulOffsets.cs index b1f9088c0..3ba327e07 100644 --- a/Cpp2IL.Core/Il2CppClassUsefulOffsets.cs +++ b/Cpp2IL.Core/Il2CppClassUsefulOffsets.cs @@ -1,7 +1,6 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -using LibCpp2IL; namespace Cpp2IL.Core; @@ -10,69 +9,65 @@ public static class Il2CppClassUsefulOffsets public const int X86_INTERFACE_OFFSETS_OFFSET = 0x50; public const int X86_64_INTERFACE_OFFSETS_OFFSET = 0xB0; - private static readonly int V24_2_VTABLE_OFFSET = LibCpp2IlMain.Binary!.is32Bit ? 0x999 /*TODO*/ : 0x138; - private static readonly int PRE_24_2_VTABLE_OFFSET = LibCpp2IlMain.Binary.is32Bit ? 0x999 /*TODO*/ : 0x128; - - public static readonly int VTABLE_OFFSET = LibCpp2IlMain.MetadataVersion >= 24.2 ? V24_2_VTABLE_OFFSET : PRE_24_2_VTABLE_OFFSET; + public static int GetVtableOffset(float metadataVersion, bool is32Bit) => + metadataVersion >= 24.2f + ? is32Bit ? 0x999 /*TODO*/ : 0x138 + : is32Bit ? 0x999 /*TODO*/ : 0x128; public static readonly List UsefulOffsets = [ - new UsefulOffset("cctor_finished", 0x74, typeof(uint), true), - new UsefulOffset("flags1", 0xBB, typeof(byte), true), + new("cctor_finished", 0x74, typeof(uint), true), + new("flags1", 0xBB, typeof(byte), true), //new UsefulOffset("interface_offsets_count", 0x12A, typeof(ushort), true), //TODO // new UsefulOffset("rgctx_data", 0xC0, typeof(IntPtr), true), //TODO - new UsefulOffset("interfaceOffsets", X86_INTERFACE_OFFSETS_OFFSET, typeof(IntPtr), true), - new UsefulOffset("static_fields", 0x5C, typeof(IntPtr), true), + new("interfaceOffsets", X86_INTERFACE_OFFSETS_OFFSET, typeof(IntPtr), true), + new("static_fields", 0x5C, typeof(IntPtr), true), //new UsefulOffset("vtable", 0x138, typeof(IntPtr), true), //TODO //64-bit offsets: - new UsefulOffset("elementType", 0x40, typeof(IntPtr), false), - new UsefulOffset("interfaceOffsets", X86_64_INTERFACE_OFFSETS_OFFSET, typeof(IntPtr), false), - new UsefulOffset("static_fields", 0xB8, typeof(IntPtr), false), - new UsefulOffset("rgctx_data", 0xC0, typeof(IntPtr), false), - new UsefulOffset("cctor_finished", 0xE0, typeof(uint), false), - new UsefulOffset("interface_offsets_count", 0x12A, typeof(ushort), false), - new UsefulOffset("flags1", 0x132, typeof(byte), false), - new UsefulOffset("flags2", 0x133, typeof(byte), false), - new UsefulOffset("vtable", 0x138, typeof(IntPtr), false) + new("elementType", 0x40, typeof(IntPtr), false), + new("interfaceOffsets", X86_64_INTERFACE_OFFSETS_OFFSET, typeof(IntPtr), false), + new("static_fields", 0xB8, typeof(IntPtr), false), + new("rgctx_data", 0xC0, typeof(IntPtr), false), + new("cctor_finished", 0xE0, typeof(uint), false), + new("interface_offsets_count", 0x12A, typeof(ushort), false), + new("flags1", 0x132, typeof(byte), false), + new("flags2", 0x133, typeof(byte), false), + new("vtable", 0x138, typeof(IntPtr), false) ]; - public static bool IsStaticFieldsPtr(uint offset) + public static bool IsStaticFieldsPtr(uint offset, bool is32Bit) { - return GetOffsetName(offset) == "static_fields"; + return GetOffsetName(offset, is32Bit) == "static_fields"; } - public static bool IsInterfaceOffsetsPtr(uint offset) + public static bool IsInterfaceOffsetsPtr(uint offset, bool is32Bit) { - return GetOffsetName(offset) == "interfaceOffsets"; + return GetOffsetName(offset, is32Bit) == "interfaceOffsets"; } - public static bool IsInterfaceOffsetsCount(uint offset) + public static bool IsInterfaceOffsetsCount(uint offset, bool is32Bit) { - return GetOffsetName(offset) == "interface_offsets_count"; + return GetOffsetName(offset, is32Bit) == "interface_offsets_count"; } - public static bool IsRGCTXDataPtr(uint offset) + public static bool IsRGCTXDataPtr(uint offset, bool is32Bit) { - return GetOffsetName(offset) == "rgctx_data"; + return GetOffsetName(offset, is32Bit) == "rgctx_data"; } - public static bool IsElementTypePtr(uint offset) + public static bool IsElementTypePtr(uint offset, bool is32Bit) { - return GetOffsetName(offset) == "elementType"; + return GetOffsetName(offset, is32Bit) == "elementType"; } - public static bool IsPointerIntoVtable(uint offset) + public static bool IsPointerIntoVtable(uint offset, float metadataVersion, bool is32Bit) { - return offset >= VTABLE_OFFSET; + return offset >= GetVtableOffset(metadataVersion, is32Bit); } - public static string? GetOffsetName(uint offset) - { - var is32Bit = LibCpp2IlMain.Binary!.is32Bit; - - return UsefulOffsets.FirstOrDefault(o => o.is32Bit == is32Bit && o.offset == offset)?.name; - } + public static string? GetOffsetName(uint offset, bool is32Bit) => + UsefulOffsets.FirstOrDefault(o => o.is32Bit == is32Bit && o.offset == offset)?.name; public class UsefulOffset(string name, uint offset, Type type, bool is32Bit) { diff --git a/Cpp2IL.Core/Il2CppMethodDefinitionUsefulOffsets.cs b/Cpp2IL.Core/Il2CppMethodDefinitionUsefulOffsets.cs index 75cb57f6f..ac825b338 100644 --- a/Cpp2IL.Core/Il2CppMethodDefinitionUsefulOffsets.cs +++ b/Cpp2IL.Core/Il2CppMethodDefinitionUsefulOffsets.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using LibCpp2IL; @@ -22,13 +22,13 @@ public static class Il2CppMethodDefinitionUsefulOffsets new UsefulOffset("methodPtr", 0x30, typeof(IntPtr), false) ]; - public static bool IsSlotOffset(uint offset) => GetOffsetName(offset) == "slot"; - public static bool IsKlassPtr(uint offset) => GetOffsetName(offset) == "klass"; - public static bool IsMethodPtr(uint offset) => GetOffsetName(offset) == "methodPtr"; + public static bool IsSlotOffset(uint offset, Il2CppBinary binary) => GetOffsetName(offset, binary) == "slot"; + public static bool IsKlassPtr(uint offset, Il2CppBinary binary) => GetOffsetName(offset, binary) == "klass"; + public static bool IsMethodPtr(uint offset, Il2CppBinary binary) => GetOffsetName(offset, binary) == "methodPtr"; - public static string? GetOffsetName(uint offset) + public static string? GetOffsetName(uint offset, Il2CppBinary binary) { - var is32Bit = LibCpp2IlMain.Binary!.is32Bit; + var is32Bit = binary.is32Bit; return UsefulOffsets.FirstOrDefault(o => o.is32Bit == is32Bit && o.offset == offset)?.name; } diff --git a/Cpp2IL.Core/Il2CppMethodInfoUsefulOffsets.cs b/Cpp2IL.Core/Il2CppMethodInfoUsefulOffsets.cs index 5ecd18204..6a5529733 100644 --- a/Cpp2IL.Core/Il2CppMethodInfoUsefulOffsets.cs +++ b/Cpp2IL.Core/Il2CppMethodInfoUsefulOffsets.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using LibCpp2IL; @@ -18,14 +18,14 @@ public static class Il2CppMethodInfoUsefulOffsets new UsefulOffset("klass", X86_64_KLASS_OFFSET, typeof(IntPtr), false) ]; - public static bool IsKlassPtr(uint offset) + public static bool IsKlassPtr(uint offset, Il2CppBinary binary) { - return GetOffsetName(offset) == "klass"; + return GetOffsetName(offset, binary) == "klass"; } - public static string? GetOffsetName(uint offset) + public static string? GetOffsetName(uint offset, Il2CppBinary binary) { - var is32Bit = LibCpp2IlMain.Binary!.is32Bit; + var is32Bit = binary.is32Bit; return UsefulOffsets.FirstOrDefault(o => o.is32Bit == is32Bit && o.offset == offset)?.name; } diff --git a/Cpp2IL.Core/InstructionSets/Arm64InstructionSet.cs b/Cpp2IL.Core/InstructionSets/Arm64InstructionSet.cs index 74dafcaea..3873f7510 100644 --- a/Cpp2IL.Core/InstructionSets/Arm64InstructionSet.cs +++ b/Cpp2IL.Core/InstructionSets/Arm64InstructionSet.cs @@ -3,12 +3,10 @@ using System.Linq; using System.Text; using Cpp2IL.Core.Api; -using Cpp2IL.Core.Graphs; using Cpp2IL.Core.Il2CppApiFunctions; using Cpp2IL.Core.ISIL; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Utils; -using LibCpp2IL; namespace Cpp2IL.Core.InstructionSets; @@ -20,15 +18,15 @@ public override Memory GetRawBytesForMethod(MethodAnalysisContext context, if (true || context is not ConcreteGenericMethodAnalysisContext) { //Managed method or attr gen => grab raw byte range between a and b - var startOfNextFunction = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer) - 1; + var startOfNextFunction = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer, context.AppContext.Binary) - 1; var ptrAsInt = (int)context.UnderlyingPointer; var count = startOfNextFunction - ptrAsInt; if (startOfNextFunction > 0) - return LibCpp2IlMain.Binary!.GetRawBinaryContent().AsMemory(ptrAsInt, count); + return context.AppContext.Binary.GetRawBinaryContent().AsMemory(ptrAsInt, count); } - var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); + var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(context.AppContext.Binary, context.UnderlyingPointer); return instructions.SelectMany(i => i.Bytes).ToArray(); } @@ -44,7 +42,7 @@ public override string PrintAssembly(MethodAnalysisContext context) { var sb = new StringBuilder(); - var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); + var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(context.AppContext.Binary, context.UnderlyingPointer); var first = true; foreach (var instruction in instructions) diff --git a/Cpp2IL.Core/InstructionSets/ArmV7InstructionSet.cs b/Cpp2IL.Core/InstructionSets/ArmV7InstructionSet.cs index 8f621dc7f..8c09df751 100644 --- a/Cpp2IL.Core/InstructionSets/ArmV7InstructionSet.cs +++ b/Cpp2IL.Core/InstructionSets/ArmV7InstructionSet.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Text; using Cpp2IL.Core.Api; -using Cpp2IL.Core.Graphs; using Cpp2IL.Core.Il2CppApiFunctions; using Cpp2IL.Core.ISIL; using Cpp2IL.Core.Model.Contexts; @@ -15,10 +14,10 @@ public class ArmV7InstructionSet : Cpp2IlInstructionSet { public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) { - if (ArmV7Utils.TryGetMethodBodyBytesFast(context.UnderlyingPointer, context is AttributeGeneratorMethodAnalysisContext) is { } ret) + if (ArmV7Utils.TryGetMethodBodyBytesFast(context.AppContext.Binary, context.UnderlyingPointer, context is AttributeGeneratorMethodAnalysisContext) is { } ret) return ret; - var instructions = ArmV7Utils.GetArmV7MethodBodyAtVirtualAddress(context.UnderlyingPointer); + var instructions = ArmV7Utils.GetArmV7MethodBodyAtVirtualAddress(context.AppContext.Binary, context.UnderlyingPointer); return instructions.SelectMany(i => i.Bytes).ToArray(); } @@ -38,7 +37,7 @@ public override string PrintAssembly(MethodAnalysisContext context) { var sb = new StringBuilder(); - var instructions = ArmV7Utils.GetArmV7MethodBodyAtVirtualAddress(context.UnderlyingPointer); + var instructions = ArmV7Utils.GetArmV7MethodBodyAtVirtualAddress(context.AppContext.Binary, context.UnderlyingPointer); var first = true; foreach (var instruction in instructions) diff --git a/Cpp2IL.Core/InstructionSets/NewArmV8InstructionSet.cs b/Cpp2IL.Core/InstructionSets/NewArmV8InstructionSet.cs index f2ac95c45..61731afc0 100644 --- a/Cpp2IL.Core/InstructionSets/NewArmV8InstructionSet.cs +++ b/Cpp2IL.Core/InstructionSets/NewArmV8InstructionSet.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using Disarm; using Cpp2IL.Core.Api; @@ -9,7 +8,6 @@ using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Utils; using Disarm.InternalDisassembly; -using LibCpp2IL; namespace Cpp2IL.Core.InstructionSets; @@ -23,15 +21,15 @@ public override Memory GetRawBytesForMethod(MethodAnalysisContext context, if (context is not ConcreteGenericMethodAnalysisContext) { //Managed method or attr gen => grab raw byte range between a and b - var startOfNextFunction = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer); + var startOfNextFunction = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer, context.AppContext.Binary); var ptrAsInt = (int)context.UnderlyingPointer; var count = startOfNextFunction - ptrAsInt; if (startOfNextFunction > 0) - return LibCpp2IlMain.Binary!.GetRawBinaryContent().AsMemory(ptrAsInt, count); + return context.AppContext.Binary.GetRawBinaryContent().AsMemory(ptrAsInt, count); } - var result = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); + var result = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.AppContext.Binary, context.UnderlyingPointer); var lastInsn = result.LastValid(); var start = (int)context.AppContext.Binary.MapVirtualAddressToRaw(context.UnderlyingPointer); @@ -48,7 +46,7 @@ public override Memory GetRawBytesForMethod(MethodAnalysisContext context, public override List GetIsilFromMethod(MethodAnalysisContext context) { - var insns = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer); + var insns = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.AppContext.Binary, context.UnderlyingPointer); var builder = new IsilBuilder(); diff --git a/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs b/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs index 0484b2ce7..be8bd3433 100644 --- a/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs +++ b/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs @@ -5,7 +5,6 @@ using Cpp2IL.Core.Extensions; using Cpp2IL.Core.Il2CppApiFunctions; using Cpp2IL.Core.ISIL; -using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Utils; using Iced.Intel; @@ -33,7 +32,7 @@ public static string FormatInstruction(Instruction instruction) } } - public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) => X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, isAttributeGenerator); + public override Memory GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) => X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, isAttributeGenerator, context.AppContext.Binary); public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() => new X86KeyFunctionAddresses(); @@ -41,7 +40,7 @@ public override string PrintAssembly(MethodAnalysisContext context) { lock (Formatter) { - var insns = X86Utils.Iterate(X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, false), context.UnderlyingPointer); + var insns = X86Utils.Iterate(X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, false, context.AppContext.Binary), context.UnderlyingPointer, context.AppContext.Binary.is32Bit); return string.Join("\n", insns.Select(FormatInstructionInternal)); } diff --git a/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs index 5c5bf7dc8..93fa1fcd3 100644 --- a/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs @@ -23,12 +23,12 @@ public class ApplicationAnalysisContext : ContextWithDataStorage /// /// The IL2CPP binary file this application was loaded from /// - public Il2CppBinary Binary; + public Il2CppBinary Binary => LibCpp2IlContext.Binary; /// /// The IL2CPP global-metadata file this application was loaded from. /// - public Il2CppMetadata Metadata; + public Il2CppMetadata Metadata => LibCpp2IlContext.Metadata; /// /// The version of the IL2CPP metadata file this application was loaded from. @@ -40,6 +40,11 @@ public class ApplicationAnalysisContext : ContextWithDataStorage /// public UnityVersion UnityVersion => Metadata.UnityVersion; + /// + /// The LibCpp2IlContext instance which this ApplicationAnalysisContext belongs to, containing the binary and metadata files that this application was loaded from. + /// + public LibCpp2IlContext LibCpp2IlContext; + /// /// The instruction set helper class associated with the instruction set that this application was compiled with. /// @@ -82,18 +87,17 @@ public class ApplicationAnalysisContext : ContextWithDataStorage private readonly Dictionary AssembliesByImageDefinition = new(); - public ApplicationAnalysisContext(Il2CppBinary binary, Il2CppMetadata metadata) + public ApplicationAnalysisContext(LibCpp2IlContext context) { - Binary = binary; - Metadata = metadata; + LibCpp2IlContext = context; try { - InstructionSet = InstructionSetRegistry.GetInstructionSet(binary.InstructionSetId); + InstructionSet = InstructionSetRegistry.GetInstructionSet(context.Binary.InstructionSetId); } catch (Exception) { - throw new InstructionSetHandlerNotRegisteredException(binary.InstructionSetId); + throw new InstructionSetHandlerNotRegisteredException(context.Binary.InstructionSetId); } Logger.VerboseNewline("\tUsing instruction set handler: " + InstructionSet.GetType().FullName); @@ -108,7 +112,7 @@ public ApplicationAnalysisContext(Il2CppBinary binary, Il2CppMetadata metadata) } SystemTypes = new(this); - + MiscUtils.InitFunctionStarts(this); PopulateMethodsByAddressTable(); diff --git a/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs b/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs index 5d92b6538..9a55b9d94 100644 --- a/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs +++ b/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using Cpp2IL.Core.Extensions; diff --git a/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs index 6422da0d3..fd7d50b04 100644 --- a/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs @@ -36,7 +36,7 @@ public class MethodAnalysisContext : HasGenericParameters, IMethodInfoProvider /// public virtual ulong UnderlyingPointer => Definition?.MethodPointer ?? throw new("Subclasses of MethodAnalysisContext should override UnderlyingPointer"); - public ulong Rva => UnderlyingPointer == 0 || LibCpp2IlMain.Binary == null ? 0 : LibCpp2IlMain.Binary.GetRva(UnderlyingPointer); + public ulong Rva => UnderlyingPointer == 0 ? 0 : AppContext.Binary.GetRva(UnderlyingPointer); /// /// The raw method body as machine code in the active instruction set. diff --git a/Cpp2IL.Core/Model/Contexts/NativeMethodAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/NativeMethodAnalysisContext.cs index b918f3551..3f6be677d 100644 --- a/Cpp2IL.Core/Model/Contexts/NativeMethodAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/NativeMethodAnalysisContext.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using LibCpp2IL; namespace Cpp2IL.Core.Model.Contexts; @@ -29,7 +28,7 @@ public NativeMethodAnalysisContext(TypeAnalysisContext parent, ulong address, bo isVoid = voidReturn; UnderlyingPointer = address; - if (LibCpp2IlMain.Binary?.TryGetExportedFunctionName(UnderlyingPointer, out var name) ?? false) + if (AppContext.Binary.TryGetExportedFunctionName(UnderlyingPointer, out var name)) { DefaultName = name; } diff --git a/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs index d11dfb91b..6d8cf890f 100644 --- a/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs @@ -8,7 +8,6 @@ using Cpp2IL.Core.Utils; using LibCpp2IL.BinaryStructures; using LibCpp2IL.Metadata; -using LibCpp2IL.Reflection; using StableNameDotNet.Providers; namespace Cpp2IL.Core.Model.Contexts; @@ -340,7 +339,7 @@ public static ITypeInfoProvider GetSndnProviderForType(ApplicationAnalysisContex return GetSndnProviderForType(appContext, type.GetArrayElementType()); if (type.Type.IsIl2CppPrimitive()) - return appContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type])!; + return appContext.ResolveContextForType(appContext.LibCpp2IlContext.ReflectionCache.PrimitiveTypeDefinitions[type.Type])!; return appContext.ResolveContextForType(type.AsClass())!; } diff --git a/Cpp2IL.Core/OutputFormats/WasmMappingOutputFormat.cs b/Cpp2IL.Core/OutputFormats/WasmMappingOutputFormat.cs index 71bff8b2c..34071515e 100644 --- a/Cpp2IL.Core/OutputFormats/WasmMappingOutputFormat.cs +++ b/Cpp2IL.Core/OutputFormats/WasmMappingOutputFormat.cs @@ -45,7 +45,7 @@ public override void DoOutput(ApplicationAnalysisContext context, string outputR try { var wasmDef = WasmUtils.GetWasmDefinition(methodAnalysisContext); - var ghidraName = WasmUtils.GetGhidraFunctionName(wasmDef); + var ghidraName = WasmUtils.GetGhidraFunctionName(context.Binary, wasmDef); output.AppendLine(ghidraName); } diff --git a/Cpp2IL.Core/OutputFormats/WasmNameSectionOutputFormat.cs b/Cpp2IL.Core/OutputFormats/WasmNameSectionOutputFormat.cs index 9e6a58da8..98abd2231 100644 --- a/Cpp2IL.Core/OutputFormats/WasmNameSectionOutputFormat.cs +++ b/Cpp2IL.Core/OutputFormats/WasmNameSectionOutputFormat.cs @@ -52,7 +52,7 @@ public override void DoOutput(ApplicationAnalysisContext context, string outputR .Where(v => v.definition is not null) .Select(v => { - var trueParamCount = v.definition!.GetType((WasmFile)LibCpp2IlMain.Binary!).ParamTypes.Length; + var trueParamCount = v.definition!.GetType((WasmFile)context.Binary).ParamTypes.Length; // Also see WasmUtils.BuildSignature var parameters = v.method.Parameters.Select(param => param.Name).ToList(); diff --git a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs index 88e8e18c2..b63e4b81c 100644 --- a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs +++ b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -7,7 +6,6 @@ using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Model.CustomAttributes; using Cpp2IL.Core.Utils; -using LibCpp2IL; namespace Cpp2IL.Core.ProcessingLayers; diff --git a/Cpp2IL.Core/ProcessingLayers/StableRenamingProcessingLayer.cs b/Cpp2IL.Core/ProcessingLayers/StableRenamingProcessingLayer.cs index bcae34040..3de4da215 100644 --- a/Cpp2IL.Core/ProcessingLayers/StableRenamingProcessingLayer.cs +++ b/Cpp2IL.Core/ProcessingLayers/StableRenamingProcessingLayer.cs @@ -5,7 +5,6 @@ using Cpp2IL.Core.Api; using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; -using LibCpp2IL; using StableNameDotNet; namespace Cpp2IL.Core.ProcessingLayers; diff --git a/Cpp2IL.Core/SharedState.cs b/Cpp2IL.Core/SharedState.cs index 2a9b30ea9..9ce1ecb2b 100644 --- a/Cpp2IL.Core/SharedState.cs +++ b/Cpp2IL.Core/SharedState.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Cpp2IL.Core.Utils; using Cpp2IL.Core.Utils.AsmResolver; using LibCpp2IL.Metadata; diff --git a/Cpp2IL.Core/Utils/Arm64Utils.cs b/Cpp2IL.Core/Utils/Arm64Utils.cs index 044c4e4ab..f19c7839e 100644 --- a/Cpp2IL.Core/Utils/Arm64Utils.cs +++ b/Cpp2IL.Core/Utils/Arm64Utils.cs @@ -11,7 +11,8 @@ namespace Cpp2IL.Core.Utils; public static class Arm64Utils { private static readonly ConcurrentDictionary CachedArm64RegNamesNew = new(); - private static CapstoneArm64Disassembler? _arm64Disassembler; + private static CapstoneArm64Disassembler? _bigEndianDisassembler; + private static CapstoneArm64Disassembler? _littleEndianDisassembler; public static string GetRegisterNameNew(Arm64RegisterId registerId) { @@ -90,39 +91,41 @@ public static string GetRegisterNameNew(Arm64RegisterId registerId) return ret; } - private static void InitArm64Decompilation() + private static CapstoneArm64Disassembler CreateDisassembler(bool isBigEndian) { - var disassembler = CapstoneDisassembler.CreateArm64Disassembler(LibCpp2IlMain.Binary!.IsBigEndian ? Arm64DisassembleMode.BigEndian : Arm64DisassembleMode.LittleEndian); + var disassembler = CapstoneDisassembler.CreateArm64Disassembler(isBigEndian ? Arm64DisassembleMode.BigEndian : Arm64DisassembleMode.LittleEndian); disassembler.EnableInstructionDetails = true; disassembler.EnableSkipDataMode = true; disassembler.DisassembleSyntax = DisassembleSyntax.Intel; - _arm64Disassembler = disassembler; + + return disassembler; } - public static List GetArm64MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) + public static List GetArm64MethodBodyAtVirtualAddress(Il2CppBinary binary, ulong virtAddress, bool managed = true, int count = -1) { - if (_arm64Disassembler == null) - InitArm64Decompilation(); + var disassembler = binary.IsBigEndian + ? _bigEndianDisassembler ??= CreateDisassembler(binary.IsBigEndian) + : _littleEndianDisassembler ??= CreateDisassembler(binary.IsBigEndian); //We can't use CppMethodBodyBytes to get the byte array, because ARMv7 doesn't have filler bytes like x86 does. //So we can't work out the end of the method. //But we can find the start of the next one! (If managed) if (managed) { - var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); + var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress, binary); //We have to fall through to default behavior for the last method because we cannot accurately pinpoint its end if (startOfNext > 0) { - var rawStartOfNextMethod = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(startOfNext); + var rawStartOfNextMethod = binary.MapVirtualAddressToRaw(startOfNext); - var rawStart = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress); + var rawStart = binary.MapVirtualAddressToRaw(virtAddress); if (rawStartOfNextMethod < rawStart) - rawStartOfNextMethod = LibCpp2IlMain.Binary.RawLength; + rawStartOfNextMethod = binary.RawLength; - byte[] bytes = LibCpp2IlMain.Binary.GetRawBinaryContent().SubArray((int)rawStart..(int)rawStartOfNextMethod); + byte[] bytes = binary.GetRawBinaryContent().SubArray((int)rawStart..(int)rawStartOfNextMethod); - var iter = _arm64Disassembler!.Iterate(bytes, (long)virtAddress); + var iter = disassembler.Iterate(bytes, (long)virtAddress); if (count > 0) iter = iter.Take(count); @@ -131,14 +134,14 @@ public static List GetArm64MethodBodyAtVirtualAddress(ulong vi } //Unmanaged function, look for first b or bl - var pos = (int)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(virtAddress); - var allBytes = LibCpp2IlMain.Binary.GetRawBinaryContent(); + var pos = (int)binary.MapVirtualAddressToRaw(virtAddress); + var allBytes = binary.GetRawBinaryContent(); List ret = []; while (!ret.Any(i => i.Mnemonic is "b" or ".byte") && (count == -1 || ret.Count < count)) { //All arm64 instructions are 4 bytes - ret.AddRange(_arm64Disassembler!.Iterate(allBytes.SubArray(pos..(pos + 4)), (long)virtAddress)); + ret.AddRange(disassembler.Iterate(allBytes.SubArray(pos..(pos + 4)), (long)virtAddress)); virtAddress += 4; pos += 4; } diff --git a/Cpp2IL.Core/Utils/ArmV7Utils.cs b/Cpp2IL.Core/Utils/ArmV7Utils.cs index 06a11a594..d93eed0a6 100644 --- a/Cpp2IL.Core/Utils/ArmV7Utils.cs +++ b/Cpp2IL.Core/Utils/ArmV7Utils.cs @@ -20,9 +20,9 @@ private static void InitArmDecompilation() _armDisassembler = disassembler; } - public static byte[]? TryGetMethodBodyBytesFast(ulong virtAddress, bool isCAGen) + public static byte[]? TryGetMethodBodyBytesFast(Il2CppBinary binary, ulong virtAddress, bool isCAGen) { - var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); + var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress, binary); var length = (startOfNext - virtAddress); if (isCAGen && length > 50_000) @@ -32,16 +32,16 @@ private static void InitArmDecompilation() //We have to fall through to default behavior for the last method because we cannot accurately pinpoint its end return null; - var rawStartOfNextMethod = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(startOfNext); + var rawStartOfNextMethod = binary.MapVirtualAddressToRaw(startOfNext); - var rawStart = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress); + var rawStart = binary.MapVirtualAddressToRaw(virtAddress); if (rawStartOfNextMethod < rawStart) - rawStartOfNextMethod = LibCpp2IlMain.Binary.RawLength; + rawStartOfNextMethod = binary.RawLength; - return LibCpp2IlMain.Binary.GetRawBinaryContent().SubArray((int)rawStart..(int)rawStartOfNextMethod); + return binary.GetRawBinaryContent().SubArray((int)rawStart..(int)rawStartOfNextMethod); } - public static List GetArmV7MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) + public static List GetArmV7MethodBodyAtVirtualAddress(Il2CppBinary binary, ulong virtAddress, bool managed = true, int count = -1) { if (_armDisassembler == null) InitArmDecompilation(); @@ -51,18 +51,18 @@ public static List GetArmV7MethodBodyAtVirtualAddress(ulong virt //But we can find the start of the next one! (If managed) if (managed) { - var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); + var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress, binary); //We have to fall through to default behavior for the last method because we cannot accurately pinpoint its end if (startOfNext > 0) { - var rawStartOfNextMethod = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(startOfNext); + var rawStartOfNextMethod = binary.MapVirtualAddressToRaw(startOfNext); - var rawStart = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress); + var rawStart = binary.MapVirtualAddressToRaw(virtAddress); if (rawStartOfNextMethod < rawStart) - rawStartOfNextMethod = LibCpp2IlMain.Binary.RawLength; + rawStartOfNextMethod = binary.RawLength; - byte[] bytes = LibCpp2IlMain.Binary.GetRawBinaryContent().SubArray((int)rawStart..(int)rawStartOfNextMethod); + byte[] bytes = binary.GetRawBinaryContent().SubArray((int)rawStart..(int)rawStartOfNextMethod); var iter = _armDisassembler!.Iterate(bytes, (long)virtAddress); if (count > 0) @@ -73,8 +73,8 @@ public static List GetArmV7MethodBodyAtVirtualAddress(ulong virt } //Unmanaged function, look for first b or bl - var pos = (int)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(virtAddress); - var allBytes = LibCpp2IlMain.Binary.GetRawBinaryContent(); + var pos = (int)binary.MapVirtualAddressToRaw(virtAddress); + var allBytes = binary.GetRawBinaryContent(); List ret = []; while (!ret.Any(i => i.Mnemonic is "b" or ".byte") && (count == -1 || ret.Count < count)) diff --git a/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs b/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs index 0788fa478..1b15fe929 100644 --- a/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs +++ b/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs @@ -6,7 +6,6 @@ using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Model.CustomAttributes; using LibCpp2IL.BinaryStructures; -using LibCpp2IL.Reflection; namespace Cpp2IL.Core.Utils; diff --git a/Cpp2IL.Core/Utils/Il2CppTypeReflectionDataToContext.cs b/Cpp2IL.Core/Utils/Il2CppTypeReflectionDataToContext.cs index de63796c0..ffca38976 100644 --- a/Cpp2IL.Core/Utils/Il2CppTypeReflectionDataToContext.cs +++ b/Cpp2IL.Core/Utils/Il2CppTypeReflectionDataToContext.cs @@ -1,5 +1,4 @@ using Cpp2IL.Core.Model.Contexts; -using LibCpp2IL.BinaryStructures; using LibCpp2IL.Reflection; namespace Cpp2IL.Core.Utils; diff --git a/Cpp2IL.Core/Utils/Il2CppTypeToContext.cs b/Cpp2IL.Core/Utils/Il2CppTypeToContext.cs index 4d51aa09a..67afb5ce9 100644 --- a/Cpp2IL.Core/Utils/Il2CppTypeToContext.cs +++ b/Cpp2IL.Core/Utils/Il2CppTypeToContext.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Cpp2IL.Core.Model.Contexts; using LibCpp2IL.BinaryStructures; -using LibCpp2IL.Reflection; namespace Cpp2IL.Core.Utils; @@ -16,7 +15,7 @@ public static class Il2CppTypeToContext TypeAnalysisContext ret; if (type.Type.IsIl2CppPrimitive()) - ret = context.AppContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type]) ?? throw new($"Could not resolve type context for type {type.Type}"); + ret = context.AppContext.ResolveContextForType(context.AppContext.LibCpp2IlContext.ReflectionCache.PrimitiveTypeDefinitions[type.Type]) ?? throw new($"Could not resolve type context for type {type.Type}"); else if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_CLASS or Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) ret = context.AppContext.ResolveContextForType(type.AsClass()) ?? throw new($"Could not resolve type context for type {type.AsClass().FullName}"); else if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) diff --git a/Cpp2IL.Core/Utils/MiscUtils.cs b/Cpp2IL.Core/Utils/MiscUtils.cs index c720ede44..1e1444f5c 100644 --- a/Cpp2IL.Core/Utils/MiscUtils.cs +++ b/Cpp2IL.Core/Utils/MiscUtils.cs @@ -12,8 +12,6 @@ public static class MiscUtils { private static List? _allKnownFunctionStarts; - private static Dictionary _primitiveSizes = new(); - public static readonly List InvalidPathChars = ['<', '>', ':', '"', '/', '\\', '|', '?', '*']; public static readonly HashSet InvalidPathElements = @@ -47,28 +45,6 @@ internal static void Reset() _allKnownFunctionStarts = null; } - internal static void Init() - { - _primitiveSizes = new(14) - { - { "Byte", 1 }, - { "SByte", 1 }, - { "Boolean", 1 }, - { "Int16", 2 }, - { "UInt16", 2 }, - { "Char", 2 }, - { "Int32", 4 }, - { "UInt32", 4 }, - { "Single", 4 }, - { "Int64", 8 }, - { "UInt64", 8 }, - { "Double", 8 }, - { "IntPtr", LibCpp2IlMain.Binary!.is32Bit ? 4UL : 8UL }, - { "UIntPtr", LibCpp2IlMain.Binary.is32Bit ? 4UL : 8UL }, - }; - } - - internal static string[] GetGenericParams(string input) { if (!input.Contains('<')) @@ -129,9 +105,9 @@ internal static string[] GetGenericParams(string input) return null; } - public static int GetSlotNum(int offset) + public static int GetSlotNum(int offset, float metadataVersion, bool is32Bit) { - var offsetInVtable = offset - Il2CppClassUsefulOffsets.VTABLE_OFFSET; //0x128 being the address of the vtable in an Il2CppClass + var offsetInVtable = offset - Il2CppClassUsefulOffsets.GetVtableOffset(metadataVersion, is32Bit); //0x128 being the address of the vtable in an Il2CppClass if (offsetInVtable % 0x10 != 0 && offsetInVtable % 0x8 == 0) offsetInVtable -= 0x8; //Handle read of the second pointer in the struct. @@ -146,11 +122,6 @@ public static int GetSlotNum(int offset) return -1; } - public static int GetPointerSizeBytes() - { - return LibCpp2IlMain.Binary!.is32Bit ? 4 : 8; - } - internal static byte[] RawBytes(IConvertible original) => original switch { @@ -182,7 +153,7 @@ internal static void InitFunctionStarts(ApplicationAnalysisContext appContext) } //TODO: End - public static ulong GetAddressOfNextFunctionStart(ulong current) + public static ulong GetAddressOfNextFunctionStart(ulong current, Il2CppBinary binary) { if (_allKnownFunctionStarts == null) throw new("Function starts not initialized!"); @@ -224,7 +195,7 @@ public static ulong GetAddressOfNextFunctionStart(ulong current) if (ret <= current && upper == _allKnownFunctionStarts.Count - 1) return 0; - if (!LibCpp2IlMain.Binary!.TryMapVirtualAddressToRaw(ret, out _)) + if (!binary.TryMapVirtualAddressToRaw(ret, out _)) return 0; return ret; diff --git a/Cpp2IL.Core/Utils/NewArm64Utils.cs b/Cpp2IL.Core/Utils/NewArm64Utils.cs index 9a5397ba9..76ae5f899 100644 --- a/Cpp2IL.Core/Utils/NewArm64Utils.cs +++ b/Cpp2IL.Core/Utils/NewArm64Utils.cs @@ -8,30 +8,30 @@ namespace Cpp2IL.Core.Utils; public static class NewArm64Utils { - public static List GetArm64MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1) + public static List GetArm64MethodBodyAtVirtualAddress(Il2CppBinary binary, ulong virtAddress, bool managed = true, int count = -1) { if (managed) { - var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress); + var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress, binary); //We have to fall through to default behavior for the last method because we cannot accurately pinpoint its end if (startOfNext > 0) { - var rawStartOfNextMethod = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(startOfNext); + var rawStartOfNextMethod = binary.MapVirtualAddressToRaw(startOfNext); - var rawStart = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress); + var rawStart = binary.MapVirtualAddressToRaw(virtAddress); if (rawStartOfNextMethod < rawStart) - rawStartOfNextMethod = LibCpp2IlMain.Binary.RawLength; + rawStartOfNextMethod = binary.RawLength; - var bytes = LibCpp2IlMain.Binary.GetRawBinaryContent().AsSpan((int)rawStart, (int)(rawStartOfNextMethod - rawStart)); + var bytes = binary.GetRawBinaryContent().AsSpan((int)rawStart, (int)(rawStartOfNextMethod - rawStart)); return Disassemble(bytes, virtAddress); } } //Unmanaged function, look for first b - var pos = (int)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(virtAddress); - var allBytes = LibCpp2IlMain.Binary.GetRawBinaryContent(); + var pos = (int)binary.MapVirtualAddressToRaw(virtAddress); + var allBytes = binary.GetRawBinaryContent(); var span = allBytes.AsSpan(pos, 4); List ret = []; diff --git a/Cpp2IL.Core/Utils/WasmUtils.cs b/Cpp2IL.Core/Utils/WasmUtils.cs index 117645a99..744932101 100644 --- a/Cpp2IL.Core/Utils/WasmUtils.cs +++ b/Cpp2IL.Core/Utils/WasmUtils.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using Cpp2IL.Core.Model.Contexts; using LibCpp2IL; using LibCpp2IL.BinaryStructures; using LibCpp2IL.Metadata; -using LibCpp2IL.Reflection; using LibCpp2IL.Wasm; namespace Cpp2IL.Core.Utils; @@ -76,10 +74,10 @@ private static string GetSignatureLetter(TypeAnalysisContext type, bool isRefOrO }; } - public static string GetGhidraFunctionName(WasmFunctionDefinition functionDefinition) + public static string GetGhidraFunctionName(Il2CppBinary binary, WasmFunctionDefinition functionDefinition) { var index = functionDefinition.IsImport - ? ((WasmFile)LibCpp2IlMain.Binary!).FunctionTable.IndexOf(functionDefinition) + ? ((WasmFile)binary).FunctionTable.IndexOf(functionDefinition) : functionDefinition.FunctionTableIndex; return $"unnamed_function_{index}"; @@ -101,12 +99,12 @@ public static WasmFunctionDefinition GetWasmDefinition(MethodAnalysisContext con { if (context.Definition == null) throw new($"Attempted to get wasm definition for probably-injected method context: {context}"); - + //First, we have to calculate the signature var signature = BuildSignature(context); try { - return ((WasmFile)LibCpp2IlMain.Binary!).GetFunctionFromIndexAndSignature(context.Definition.MethodPointer, signature); + return ((WasmFile)context.AppContext.Binary).GetFunctionFromIndexAndSignature(context.Definition.MethodPointer, signature); } catch (Exception e) { diff --git a/Cpp2IL.Core/Utils/X64CallingConventionResolver.cs b/Cpp2IL.Core/Utils/X64CallingConventionResolver.cs index f0084df1a..030e74afd 100644 --- a/Cpp2IL.Core/Utils/X64CallingConventionResolver.cs +++ b/Cpp2IL.Core/Utils/X64CallingConventionResolver.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using Cpp2IL.Core.ISIL; using Cpp2IL.Core.Model.Contexts; -using LibCpp2IL.BinaryStructures; using LibCpp2IL.PE; namespace Cpp2IL.Core.Utils; diff --git a/Cpp2IL.Core/Utils/X86Utils.cs b/Cpp2IL.Core/Utils/X86Utils.cs index 8f20aff9f..f8debf279 100644 --- a/Cpp2IL.Core/Utils/X86Utils.cs +++ b/Cpp2IL.Core/Utils/X86Utils.cs @@ -18,13 +18,13 @@ public static class X86Utils private static readonly ConcurrentDictionary CachedX86RegNamesNew = new(); //TODO Consider implementing a CodeReader for Memory - public static InstructionList Disassemble(Memory bytes, ulong methodBase) - => Disassemble(bytes.ToArray(), methodBase); + public static InstructionList Disassemble(Memory bytes, ulong methodBase, bool is32Bit) + => Disassemble(bytes.ToArray(), methodBase, is32Bit); - public static InstructionList Disassemble(byte[] bytes, ulong methodBase) + public static InstructionList Disassemble(byte[] bytes, ulong methodBase, bool is32Bit) { var codeReader = new ByteArrayCodeReader(bytes); - var decoder = Decoder.Create(LibCpp2IlMain.Binary!.is32Bit ? 32 : 64, codeReader); + var decoder = Decoder.Create(is32Bit ? 32 : 64, codeReader); decoder.IP = methodBase; var instructions = new InstructionList(); var endRip = decoder.IP + (uint)bytes.Length; @@ -37,18 +37,18 @@ public static InstructionList Disassemble(byte[] bytes, ulong methodBase) public static InstructionList Disassemble(MethodAnalysisContext context) { - return Disassemble(context.RawBytes, context.UnderlyingPointer); + return Disassemble(context.RawBytes, context.UnderlyingPointer, context.AppContext.Binary.is32Bit); } - public static IEnumerable Iterate(Memory bytes, ulong methodBase) + public static IEnumerable Iterate(Memory bytes, ulong methodBase, bool is32Bit) { - return Iterate(bytes.AsEnumerable(), methodBase); + return Iterate(bytes.AsEnumerable(), methodBase, is32Bit); } - public static IEnumerable Iterate(IEnumerable bytes, ulong methodBase) + public static IEnumerable Iterate(IEnumerable bytes, ulong methodBase, bool is32Bit) { var codeReader = new EnumerableCodeReader(bytes); - var decoder = Decoder.Create(LibCpp2IlMain.Binary!.is32Bit ? 32 : 64, codeReader); + var decoder = Decoder.Create(is32Bit ? 32 : 64, codeReader); decoder.IP = methodBase; decoder.Decode(out var instruction); @@ -61,30 +61,30 @@ public static IEnumerable Iterate(IEnumerable bytes, ulong me public static IEnumerable Iterate(MethodAnalysisContext context) { - return Iterate(context.RawBytes, context.UnderlyingPointer); + return Iterate(context.RawBytes, context.UnderlyingPointer, context.AppContext.Binary.is32Bit); } - public static Memory GetRawManagedOrCaCacheGenMethodBody(ulong ptr, bool isCaGen) + public static Memory GetRawManagedOrCaCacheGenMethodBody(ulong ptr, bool isCaGen, Il2CppBinary binary) { - var rawAddr = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(ptr, false); + var rawAddr = binary.MapVirtualAddressToRaw(ptr, false); if (rawAddr <= 0) return Memory.Empty; - var virtStartNextFunc = MiscUtils.GetAddressOfNextFunctionStart(ptr); + var virtStartNextFunc = MiscUtils.GetAddressOfNextFunctionStart(ptr, binary); if (virtStartNextFunc == 0 || (isCaGen && virtStartNextFunc - ptr > 50000)) { - GetMethodBodyAtVirtAddressNew(ptr, false, out var ret); + GetMethodBodyAtVirtAddressNew(ptr, false, binary, out var ret); return ret; } - var ra2 = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtStartNextFunc, false); + var ra2 = binary.MapVirtualAddressToRaw(virtStartNextFunc, false); if (ra2 <= 0) { //Don't have a known end point => fall back - GetMethodBodyAtVirtAddressNew(ptr, false, out var ret); + GetMethodBodyAtVirtAddressNew(ptr, false, binary, out var ret); return ret; } @@ -93,18 +93,18 @@ public static Memory GetRawManagedOrCaCacheGenMethodBody(ulong ptr, bool i if (startOfNextFunc < rawAddr) { Logger.WarnNewline($"StartOfNextFunc returned va 0x{virtStartNextFunc:X}, raw address 0x{startOfNextFunc:X}, for raw address 0x{rawAddr:X}. It should be more than raw address. Falling back to manual, slow, decompiler-based approach."); - GetMethodBodyAtVirtAddressNew(ptr, false, out var ret); + GetMethodBodyAtVirtAddressNew(ptr, false, binary, out var ret); return ret; } - var rawArray = LibCpp2IlMain.Binary.GetRawBinaryContent(); + var rawArray = binary.GetRawBinaryContent(); var lastPos = startOfNextFunc - 1; if (lastPos >= rawArray.Length) { Logger.WarnNewline($"StartOfNextFunc returned va 0x{virtStartNextFunc:X}, raw address 0x{startOfNextFunc:X}, for raw address 0x{rawAddr:X}. LastPos should be less than the raw array length. Falling back to manual, slow, decompiler-based approach."); - GetMethodBodyAtVirtAddressNew(ptr, false, out var ret); + GetMethodBodyAtVirtAddressNew(ptr, false, binary, out var ret); return ret; } @@ -115,7 +115,7 @@ public static Memory GetRawManagedOrCaCacheGenMethodBody(ulong ptr, bool i if (TryFindJumpTableStart(memArray, ptr, virtStartNextFunc, out var startIndex, out var jumpTableElements)) { // TODO: Figure out what to do with jumpTableElements, how do we handle returning it from this function? - // we might need to return the address it was found at in TryFindJumpTableStart function too + // we might need to return the address it was found at in TryFindJumpTableStart function too // Should clean up the way we handle the bytes array too /* foreach (var element in jumpTableElements) @@ -152,18 +152,18 @@ private static bool TryFindJumpTableStart(Memory methodBytes, ulong method return foundTable; } - public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool peek) => GetMethodBodyAtVirtAddressNew(addr, peek, out _); + public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool peek, Il2CppBinary binary) => GetMethodBodyAtVirtAddressNew(addr, peek, binary, out _); - public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool peek, out byte[] rawBytes) + public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool peek, Il2CppBinary binary, out byte[] rawBytes) { var functionStart = addr; var ret = new InstructionList(); var con = true; var buff = new List(); - var rawAddr = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(addr); - var startOfNextFunc = MiscUtils.GetAddressOfNextFunctionStart(addr); + var rawAddr = binary.MapVirtualAddressToRaw(addr); + var startOfNextFunc = MiscUtils.GetAddressOfNextFunctionStart(addr, binary); - if (rawAddr < 0 || rawAddr >= LibCpp2IlMain.Binary.RawLength) + if (rawAddr < 0 || rawAddr >= binary.RawLength) { Logger.ErrorNewline($"Invalid call to GetMethodBodyAtVirtAddressNew, virt addr {addr} resolves to raw {rawAddr} which is out of bounds"); rawBytes = []; @@ -175,9 +175,9 @@ public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool pee if (addr >= startOfNextFunc) break; - buff.Add(LibCpp2IlMain.Binary.GetByteAtRawAddress((ulong)rawAddr)); + buff.Add(binary.GetByteAtRawAddress((ulong)rawAddr)); - ret = X86Utils.Disassemble(buff.ToArray(), functionStart); + ret = X86Utils.Disassemble(buff.ToArray(), functionStart, binary.is32Bit); if (ret.All(i => i.Mnemonic != Mnemonic.INVALID) && ret.Any(i => i.Code == Code.Int3)) con = false; @@ -189,7 +189,7 @@ public static InstructionList GetMethodBodyAtVirtAddressNew(ulong addr, bool pee addr++; rawAddr++; - if (rawAddr >= LibCpp2IlMain.Binary.RawLength) + if (rawAddr >= binary.RawLength) con = false; } diff --git a/Cpp2IL.Plugin.StrippedCodeRegSupport/StrippedCodeRegSupportPlugin.cs b/Cpp2IL.Plugin.StrippedCodeRegSupport/StrippedCodeRegSupportPlugin.cs index 8d7b2dbb2..58c53f886 100644 --- a/Cpp2IL.Plugin.StrippedCodeRegSupport/StrippedCodeRegSupportPlugin.cs +++ b/Cpp2IL.Plugin.StrippedCodeRegSupport/StrippedCodeRegSupportPlugin.cs @@ -38,7 +38,7 @@ private void OnReadFail(Il2CppBinary binary, Il2CppMetadata metadata, ref Il2Cpp //All we NEED to find is pCodegenModules - the rest of the CodeRegistration struct isn't critical to a successful dump. //We can piggyback off BinarySearcher: - var searcher = new BinarySearcher(binary, metadata.MethodDefinitionCount, metadata.TypeDefinitionCount); + var searcher = new BinarySearcher(binary, metadata, metadata.MethodDefinitionCount, metadata.TypeDefinitionCount); var mscorlibs = searcher.FindAllStrings("mscorlib.dll\0").Select(idx => binary.MapRawAddressToVirtual(idx)).ToList(); diff --git a/Cpp2IL/CommandLineArgs.cs b/Cpp2IL/CommandLineArgs.cs index bd3f8e802..b3d0e3332 100644 --- a/Cpp2IL/CommandLineArgs.cs +++ b/Cpp2IL/CommandLineArgs.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; diff --git a/LibCpp2IL/BinarySearcher.cs b/LibCpp2IL/BinarySearcher.cs index a003194c8..efc5f3040 100644 --- a/LibCpp2IL/BinarySearcher.cs +++ b/LibCpp2IL/BinarySearcher.cs @@ -8,11 +8,10 @@ using LibCpp2IL.Logging; using LibCpp2IL.Metadata; using LibCpp2IL.NintendoSwitch; -using LibCpp2IL.Wasm; namespace LibCpp2IL; -public class BinarySearcher(Il2CppBinary binary, int methodCount, int typeDefinitionsCount) +public class BinarySearcher(Il2CppBinary binary, Il2CppMetadata metadata, int methodCount, int typeDefinitionsCount) { private readonly byte[] _binaryBytes = binary.GetRawBinaryContent(); @@ -115,17 +114,17 @@ public ulong FindCodeRegistrationPre2019() LibLogger.VerboseNewline($"\t\t\tChecking for CodeRegistration at virtual address 0x{va:x}..."); var cr = binary.ReadReadableAtVirtualAddress(va); - if ((long)cr.customAttributeCount == LibCpp2IlMain.TheMetadata!.attributeTypeRanges!.Count) + if ((long)cr.customAttributeCount == metadata.attributeTypeRanges!.Count) return va; - LibLogger.VerboseNewline($"\t\t\t\tNot a valid CodeRegistration - custom attribute count is {cr.customAttributeCount}, expecting {LibCpp2IlMain.TheMetadata!.attributeTypeRanges.Count}"); + LibLogger.VerboseNewline($"\t\t\t\tNot a valid CodeRegistration - custom attribute count is {cr.customAttributeCount}, expecting {metadata.attributeTypeRanges.Count}"); } return 0; } [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] - internal ulong FindCodeRegistrationPost2019(Il2CppMetadata metadata) + internal ulong FindCodeRegistrationPost2019() { //Works only on >=24.2 var mscorlibs = FindAllStrings("mscorlib.dll\0").Select(idx => binary.MapRawAddressToVirtual(idx)).ToList(); @@ -161,9 +160,9 @@ internal ulong FindCodeRegistrationPost2019(Il2CppMetadata metadata) else { //but in v27 it's close to the LAST codegen module (winrt.dll is an exception), so we need to work back until we find an xref. - var sanityCheckNumberOfModules = Math.Min(400, LibCpp2IlMain.TheMetadata!.imageDefinitions.Length); + var sanityCheckNumberOfModules = Math.Min(400, metadata.imageDefinitions.Length); var pSomewhereInCodegenModules = pMscorlibCodegenEntryInCodegenModulesList.AsEnumerable(); - var numModuleDefs = LibCpp2IlMain.TheMetadata!.imageDefinitions.Length; + var numModuleDefs = metadata.imageDefinitions.Length; var initialBacktrack = numModuleDefs - 10; pSomewhereInCodegenModules = pSomewhereInCodegenModules.Select(va => va - ptrSize * (ulong)initialBacktrack); @@ -183,7 +182,7 @@ internal ulong FindCodeRegistrationPost2019(Il2CppMetadata metadata) if (moduleCount < 0 || moduleCount > sanityCheckNumberOfModules) pCodegenModules = []; else - LibLogger.VerboseNewline($"\t\t\tFound valid address for pCodegenModules after a backtrack of {backtrack}, module count is {LibCpp2IlMain.TheMetadata!.imageDefinitions.Length}"); + LibLogger.VerboseNewline($"\t\t\tFound valid address for pCodegenModules after a backtrack of {backtrack}, module count is {metadata.imageDefinitions.Length}"); } else if (pCodegenModules.Count > 1) { @@ -230,9 +229,9 @@ internal ulong FindCodeRegistrationPost2019(Il2CppMetadata metadata) LibLogger.Verbose($"\t\t\tConsidering potential code registration at 0x{address:X}..."); - var codeReg = LibCpp2IlMain.Binary!.ReadReadableAtVirtualAddress(address); + var codeReg = binary.ReadReadableAtVirtualAddress(address); - var success = ValidateCodeRegistration(codeReg, fieldsByName); + var success = ValidateCodeRegistration(codeReg, fieldsByName, binary); if (success) { @@ -244,7 +243,7 @@ internal ulong FindCodeRegistrationPost2019(Il2CppMetadata metadata) return 0; } - public static bool ValidateCodeRegistration(Il2CppCodeRegistration codeReg, Dictionary fieldsByName) + public static bool ValidateCodeRegistration(Il2CppCodeRegistration codeReg, Dictionary fieldsByName, Il2CppBinary binaryToValidate) { var success = true; foreach (var keyValuePair in fieldsByName) @@ -267,7 +266,7 @@ public static bool ValidateCodeRegistration(Il2CppCodeRegistration codeReg, Dict else { //Pointer - if (!LibCpp2IlMain.Binary!.TryMapVirtualAddressToRaw(fieldValue, out _)) + if (!binaryToValidate.TryMapVirtualAddressToRaw(fieldValue, out _)) { LibLogger.VerboseNewline($"Rejected due to invalid pointer 0x{fieldValue:X} for field {keyValuePair.Key}"); success = false; @@ -287,9 +286,9 @@ public ulong FindMetadataRegistrationPre24_5() var bytesToSubtract = sizeOfMr - ptrSize * 4; - var potentialMetaRegPointers = MapOffsetsToVirt(FindAllBytes(BitConverter.GetBytes(LibCpp2IlMain.TheMetadata!.TypeDefinitionCount), 1)).ToList(); + var potentialMetaRegPointers = MapOffsetsToVirt(FindAllBytes(BitConverter.GetBytes(metadata.TypeDefinitionCount), 1)).ToList(); - LibLogger.VerboseNewline($"\t\t\tFound {potentialMetaRegPointers.Count} instances of the number of type defs, {LibCpp2IlMain.TheMetadata.TypeDefinitionCount}"); + LibLogger.VerboseNewline($"\t\t\tFound {potentialMetaRegPointers.Count} instances of the number of type defs, {metadata.TypeDefinitionCount}"); potentialMetaRegPointers = potentialMetaRegPointers.Select(p => p - bytesToSubtract).ToList(); @@ -297,19 +296,19 @@ public ulong FindMetadataRegistrationPre24_5() { var mr = binary.ReadReadableAtVirtualAddress(potentialMetaRegPointer); - if (mr.metadataUsagesCount == (ulong)LibCpp2IlMain.TheMetadata!.metadataUsageLists!.Length) + if (mr.metadataUsagesCount == (ulong)metadata.metadataUsageLists!.Length) { LibLogger.VerboseNewline($"\t\t\tFound and selected probably valid metadata registration at 0x{potentialMetaRegPointer:X}."); return potentialMetaRegPointer; } else - LibLogger.VerboseNewline($"\t\t\tSkipping 0x{potentialMetaRegPointer:X} as the metadata reg, metadata usage count was 0x{mr.metadataUsagesCount:X}, expecting 0x{LibCpp2IlMain.TheMetadata.metadataUsageLists.Length:X}"); + LibLogger.VerboseNewline($"\t\t\tSkipping 0x{potentialMetaRegPointer:X} as the metadata reg, metadata usage count was 0x{mr.metadataUsagesCount:X}, expecting 0x{metadata.metadataUsageLists.Length:X}"); } return 0; } - public ulong FindMetadataRegistrationPost24_5(Il2CppMetadata metadata) + public ulong FindMetadataRegistrationPost24_5() { var ptrSize = binary.is32Bit ? 4ul : 8ul; var sizeOfMr = (uint)Il2CppMetadataRegistration.GetStructSize(binary.is32Bit); diff --git a/LibCpp2IL/BinaryStructures/Il2CppArrayType.cs b/LibCpp2IL/BinaryStructures/Il2CppArrayType.cs index e6d262403..53214546d 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppArrayType.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppArrayType.cs @@ -4,9 +4,6 @@ namespace LibCpp2IL.BinaryStructures; public class Il2CppArrayType : ReadableClass { - // Populated by the caller after reading. - internal Il2CppBinary? OwningBinary { get; set; } - public ulong etype; public byte rank; public byte numsizes; @@ -14,17 +11,7 @@ public class Il2CppArrayType : ReadableClass public ulong sizes; public ulong lobounds; - public Il2CppType? ElementType - { - get - { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - return binary == null ? null : binary.GetIl2CppTypeFromPointer(etype); - } - } - - public Il2CppType GetElementTypeOrThrow() - => ElementType ?? throw new InvalidOperationException("No binary context available to resolve Il2CppArrayType.ElementType"); + public Il2CppType ElementType => OwningContext.Binary.GetIl2CppTypeFromPointer(etype); public override void Read(ClassReadingBinaryReader reader) { diff --git a/LibCpp2IL/BinaryStructures/Il2CppCodeGenModule.cs b/LibCpp2IL/BinaryStructures/Il2CppCodeGenModule.cs index 89ace72c2..9b6af0508 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppCodeGenModule.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppCodeGenModule.cs @@ -34,18 +34,13 @@ public class Il2CppCodeGenModule : ReadableClass private string? _cachedName; - internal Il2CppBinary? OwningBinary { get; set; } - public string Name { get { if (_cachedName == null) { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) - throw new InvalidOperationException("No binary context available to resolve Il2CppCodeGenModule.Name"); - + var binary = OwningContext.Binary; _cachedName = binary.ReadStringToNull(binary.MapVirtualAddressToRaw(moduleName)); } @@ -53,17 +48,7 @@ public string Name } } - public Il2CppTokenRangePair[] RGCTXRanges - { - get - { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) - throw new InvalidOperationException("No binary context available to resolve Il2CppCodeGenModule.RGCTXRanges"); - - return binary.GetRgctxRangePairsForModule(this); - } - } + public Il2CppTokenRangePair[] RGCTXRanges => OwningContext.Binary.GetRgctxRangePairsForModule(this); public override void Read(ClassReadingBinaryReader reader) { diff --git a/LibCpp2IL/BinaryStructures/Il2CppGenericClass.cs b/LibCpp2IL/BinaryStructures/Il2CppGenericClass.cs index b01e58297..097ddbc00 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppGenericClass.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppGenericClass.cs @@ -1,34 +1,23 @@ -using System; using LibCpp2IL.Metadata; namespace LibCpp2IL.BinaryStructures; public class Il2CppGenericClass : ReadableClass { - // Populated by the caller after reading. - internal Il2CppBinary? OwningBinary { get; set; } - internal Il2CppMetadata? OwningMetadata { get; set; } - [Version(Max = 24.5f)] public long TypeDefinitionIndex; /* the generic type definition */ [Version(Min = 27.0f)] public ulong V27TypePointer; - + public Il2CppGenericContext Context = null!; /* a context that contains the type instantiation doesn't contain any method instantiation */ public ulong CachedClass; /* if present, the Il2CppClass corresponding to the instantiation. */ - private float EffectiveMetadataVersion => OwningMetadata?.MetadataVersion ?? LibCpp2IlMain.MetadataVersion; - public Il2CppTypeDefinition TypeDefinition { get { - if (EffectiveMetadataVersion < 27f) + if (MetadataVersion < 27f) { - var md = OwningMetadata ?? LibCpp2IlMain.TheMetadata; - if (md == null) - throw new InvalidOperationException("No metadata context available for generic class type definition resolution."); - - return md.GetTypeDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)TypeDefinitionIndex)); + return OwningContext.Metadata.GetTypeDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)TypeDefinitionIndex)); } return V27BaseType!.AsClass(); @@ -39,18 +28,10 @@ public Il2CppType? V27BaseType { get { - if (EffectiveMetadataVersion < 27f) + if (MetadataVersion < 27f) return null; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) - return null; - - var t = binary.ReadReadableAtVirtualAddress(V27TypePointer); - t.OwningBinary = binary; - t.OwningMetadata = OwningMetadata ?? LibCpp2IlMain.TheMetadata; - t.Il2CppTypeHasNumMods5Bits ??= (OwningMetadata?.MetadataVersion ?? LibCpp2IlMain.MetadataVersion) >= 27.2f; - return t; + return OwningContext.Binary.ReadReadableAtVirtualAddress(V27TypePointer); } } @@ -60,9 +41,8 @@ public override void Read(ClassReadingBinaryReader reader) V27TypePointer = reader.ReadNUint(); else TypeDefinitionIndex = reader.ReadNInt(); - + Context = reader.ReadReadableHereNoLock(); - Context.OwningBinary = OwningBinary; CachedClass = reader.ReadNUint(); } } diff --git a/LibCpp2IL/BinaryStructures/Il2CppGenericContext.cs b/LibCpp2IL/BinaryStructures/Il2CppGenericContext.cs index e8093c384..391aec040 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppGenericContext.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppGenericContext.cs @@ -2,9 +2,6 @@ namespace LibCpp2IL.BinaryStructures; public class Il2CppGenericContext : ReadableClass { - // Populated by the caller after reading. - internal Il2CppBinary? OwningBinary { get; set; } - /* The instantiation corresponding to the class generic parameters */ public ulong class_inst; @@ -16,11 +13,7 @@ public Il2CppGenericInst? ClassInst get { if (class_inst == 0) return null; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) return null; - var inst = binary.ReadReadableAtVirtualAddress(class_inst); - inst.OwningBinary = binary; - return inst; + return OwningContext.Binary.ReadReadableAtVirtualAddress(class_inst); } } @@ -29,11 +22,7 @@ public Il2CppGenericInst? MethodInst get { if (method_inst == 0) return null; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) return null; - var inst = binary.ReadReadableAtVirtualAddress(method_inst); - inst.OwningBinary = binary; - return inst; + return OwningContext.Binary.ReadReadableAtVirtualAddress(method_inst); } } diff --git a/LibCpp2IL/BinaryStructures/Il2CppGenericInst.cs b/LibCpp2IL/BinaryStructures/Il2CppGenericInst.cs index 55265b22d..98fff83c3 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppGenericInst.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppGenericInst.cs @@ -4,29 +4,12 @@ namespace LibCpp2IL.BinaryStructures; public class Il2CppGenericInst : ReadableClass { - // Populated by the caller after reading. - internal Il2CppBinary? OwningBinary { get; set; } - public ulong pointerCount; public ulong pointerStart; - public ulong[] Pointers - { - get - { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - return binary == null ? [] : binary.ReadNUintArrayAtVirtualAddress(pointerStart, (long)pointerCount); - } - } + public ulong[] Pointers => OwningContext.Binary.ReadNUintArrayAtVirtualAddress(pointerStart, (long)pointerCount); - public Il2CppType[] Types - { - get - { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - return binary == null ? [] : Pointers.Select(binary.GetIl2CppTypeFromPointer).ToArray(); - } - } + public Il2CppType[] Types => Pointers.Select(OwningContext.Binary.GetIl2CppTypeFromPointer).ToArray(); public override void Read(ClassReadingBinaryReader reader) { diff --git a/LibCpp2IL/BinaryStructures/Il2CppMethodSpec.cs b/LibCpp2IL/BinaryStructures/Il2CppMethodSpec.cs index cfdacfd46..23b798417 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppMethodSpec.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppMethodSpec.cs @@ -1,4 +1,3 @@ -using System; using System.Linq; using System.Text; using LibCpp2IL.Metadata; @@ -8,28 +7,20 @@ namespace LibCpp2IL.BinaryStructures; public class Il2CppMethodSpec : ReadableClass { - // Populated by Il2CppBinary.Init for per-context usage. - internal Il2CppBinary? OwningBinary { get; set; } - internal Il2CppMetadata? OwningMetadata { get; set; } - public int methodDefinitionIndex; public int classIndexIndex; public int methodIndexIndex; - public Il2CppMethodDefinition? MethodDefinition - => (OwningMetadata ?? LibCpp2IlMain.TheMetadata) - ?.GetMethodDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(methodDefinitionIndex)); //DynWidth: Il2CppMethodSpec is in-binary, dynamic widths weren't applied here. + public Il2CppMethodDefinition? MethodDefinition + => OwningContext.Metadata + .GetMethodDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(methodDefinitionIndex)); //DynWidth: Il2CppMethodSpec is in-binary, dynamic widths weren't applied here. public Il2CppGenericInst? GenericClassInst { get { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) return null; if (classIndexIndex < 0) return null; - var inst = binary.GetGenericInst(classIndexIndex); - inst.OwningBinary = binary; - return inst; + return OwningContext.Binary.GetGenericInst(classIndexIndex); } } @@ -37,18 +28,14 @@ public Il2CppGenericInst? GenericMethodInst { get { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) return null; if (methodIndexIndex < 0) return null; - var inst = binary.GetGenericInst(methodIndexIndex); - inst.OwningBinary = binary; - return inst; + return OwningContext.Binary.GetGenericInst(methodIndexIndex); } } - public Il2CppTypeReflectionData[] GenericClassParams => classIndexIndex == -1 ? [] : LibCpp2ILUtils.GetGenericTypeParams(GenericClassInst!)!; + public Il2CppTypeReflectionData[] GenericClassParams => classIndexIndex == -1 ? [] : LibCpp2ILUtils.GetGenericTypeParams(GenericClassInst!); - public Il2CppTypeReflectionData[] GenericMethodParams => methodIndexIndex == -1 ? [] : LibCpp2ILUtils.GetGenericTypeParams(GenericMethodInst!)!; + public Il2CppTypeReflectionData[] GenericMethodParams => methodIndexIndex == -1 ? [] : LibCpp2ILUtils.GetGenericTypeParams(GenericMethodInst!); public override string ToString() { diff --git a/LibCpp2IL/BinaryStructures/Il2CppRGCTXDefinition.cs b/LibCpp2IL/BinaryStructures/Il2CppRGCTXDefinition.cs index 3995999d7..e5052f4c6 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppRGCTXDefinition.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppRGCTXDefinition.cs @@ -5,33 +5,19 @@ namespace LibCpp2IL.BinaryStructures; public class Il2CppRGCTXDefinition : ReadableClass { - // Populated by Il2CppBinary.Init (codegen module init) for per-context usage. - internal Il2CppBinary? OwningBinary { get; set; } - internal Il2CppMetadata? OwningMetadata { get; set; } - public Il2CppRGCTXDataType type; - public int _rawIndex; public int MethodIndex => _defData?.MethodIndex ?? _constrainedData!.MethodIndex; public int TypeIndex => _defData?.TypeIndex ?? _constrainedData!.TypeIndex; - public Il2CppMethodSpec? MethodSpec - { - get - { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - return binary?.GetMethodSpec(MethodIndex); - } - } + public Il2CppMethodSpec MethodSpec => OwningContext.Binary.GetMethodSpec(MethodIndex); - public Il2CppTypeReflectionData? Type + public Il2CppTypeReflectionData Type { get { - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) return null; - var t = binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(TypeIndex)); + var t = OwningContext.Binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(TypeIndex)); return LibCpp2ILUtils.GetTypeReflectionData(t); } } @@ -54,7 +40,7 @@ public class Il2CppRGCTXConstrainedData : ReadableClass public int _encodedMethodIndex; public int TypeIndex => _typeIndex; public int MethodIndex => _encodedMethodIndex; - + public override void Read(ClassReadingBinaryReader reader) { _typeIndex = reader.ReadInt32(); @@ -79,15 +65,7 @@ public override void Read(ClassReadingBinaryReader reader) var va = reader.ReadNUint(); var bakPosition = reader.Position; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - if (binary == null) - { - // Can't resolve VA -> raw without a binary context. Leave as-is. - reader.Position = bakPosition; - return; - } - - reader.Position = binary.MapVirtualAddressToRaw(va); + reader.Position = OwningContext.Binary.MapVirtualAddressToRaw(va); if (type == Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_CONSTRAINED) { diff --git a/LibCpp2IL/BinaryStructures/Il2CppType.cs b/LibCpp2IL/BinaryStructures/Il2CppType.cs index 75f5e89ce..f0f125555 100644 --- a/LibCpp2IL/BinaryStructures/Il2CppType.cs +++ b/LibCpp2IL/BinaryStructures/Il2CppType.cs @@ -1,17 +1,11 @@ using System; using System.Diagnostics; using LibCpp2IL.Metadata; -using LibCpp2IL.Reflection; namespace LibCpp2IL.BinaryStructures; public class Il2CppType : ReadableClass { - // Populated by Il2CppBinary.Init for per-context usage. - internal Il2CppBinary? OwningBinary { get; set; } - internal Il2CppMetadata? OwningMetadata { get; set; } - internal bool? Il2CppTypeHasNumMods5Bits { get; set; } - public ulong Datapoint; public uint Bits; public Union Data { get; set; } = null!; //Late-bound @@ -28,8 +22,7 @@ private void InitUnionAndFlags() Type = (Il2CppTypeEnum)((Bits >> 16) & 0b1111_1111); //Bits 16-23 Data = new Union { Dummy = Datapoint }; - var hasNumMods5Bits = Il2CppTypeHasNumMods5Bits ?? LibCpp2IlMain.Il2CppTypeHasNumMods5Bits; - if (hasNumMods5Bits) + if (OwningContext.Il2CppTypeHasNumMods5Bits) { //Unity 2021 (v27.2) changed num_mods to be 5 bits not 6 //Which shifts byref and pinned left one @@ -51,7 +44,7 @@ private void InitUnionAndFlags() public class Union { public ulong Dummy; - + //DynamicWidth: Dummy is always nint, not dynamic, so temp usage is ok public Il2CppVariableWidthIndex ClassIndex => Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int) Dummy); public ulong Type => Dummy; @@ -68,8 +61,7 @@ private Il2CppTypeDefinition? Class if (Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) return null; - var metadata = OwningMetadata ?? LibCpp2IlMain.TheMetadata; - return metadata!.GetTypeDefinitionFromIndex(Data.ClassIndex); + return OwningContext.Metadata.GetTypeDefinitionFromIndex(Data.ClassIndex); } } @@ -85,8 +77,7 @@ private Il2CppType? EncapsulatedType if (Type is not Il2CppTypeEnum.IL2CPP_TYPE_PTR and not Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY) return null; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - return binary!.GetIl2CppTypeFromPointer(Data.Type); + return OwningContext.Binary.GetIl2CppTypeFromPointer(Data.Type); } } @@ -102,10 +93,7 @@ private Il2CppArrayType? ArrayType if (Type is not Il2CppTypeEnum.IL2CPP_TYPE_ARRAY) return null; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - var at = binary!.ReadReadableAtVirtualAddress(Data.Array); - at.OwningBinary = binary; - return at; + return OwningContext.Binary.ReadReadableAtVirtualAddress(Data.Array); } } @@ -114,7 +102,7 @@ public Il2CppArrayType GetArrayType() return ArrayType ?? throw new Exception("Type is not an array"); } - public Il2CppType GetArrayElementType() => GetArrayType().GetElementTypeOrThrow(); + public Il2CppType GetArrayElementType() => GetArrayType().ElementType; public int GetArrayRank() => GetArrayType().rank; @@ -125,8 +113,7 @@ private Il2CppGenericParameter? GenericParameter if (Type is not Il2CppTypeEnum.IL2CPP_TYPE_VAR and not Il2CppTypeEnum.IL2CPP_TYPE_MVAR) return null; - var metadata = OwningMetadata ?? LibCpp2IlMain.TheMetadata; - return metadata!.GetGenericParameterFromIndex(Data.GenericParameterIndex); + return OwningContext.Metadata.GetGenericParameterFromIndex(Data.GenericParameterIndex); } } @@ -144,12 +131,7 @@ private Il2CppGenericClass? GenericClass if (Type is not Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) return null; - var binary = OwningBinary ?? LibCpp2IlMain.Binary; - var gc = binary!.ReadReadableAtVirtualAddress(Data.GenericClass); - gc.OwningBinary = binary; - gc.OwningMetadata = OwningMetadata ?? LibCpp2IlMain.TheMetadata; - gc.Context.OwningBinary = binary; - return gc; + return OwningContext.Binary.ReadReadableAtVirtualAddress(Data.GenericClass); } } @@ -176,7 +158,7 @@ public Il2CppTypeDefinition CoerceToUnderlyingTypeDefinition() Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST => GetGenericClass().TypeDefinition, Il2CppTypeEnum.IL2CPP_TYPE_PTR or Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY => GetEncapsulatedType().CoerceToUnderlyingTypeDefinition(), Il2CppTypeEnum.IL2CPP_TYPE_ARRAY => GetArrayElementType().CoerceToUnderlyingTypeDefinition(), - _ => Type.IsIl2CppPrimitive() ? LibCpp2IlReflection.PrimitiveTypeDefinitions[Type] : AsClass() + _ => Type.IsIl2CppPrimitive() ? OwningContext.ReflectionCache.PrimitiveTypeDefinitions[Type] : AsClass() }; } diff --git a/LibCpp2IL/ClassReadingBinaryReader.cs b/LibCpp2IL/ClassReadingBinaryReader.cs index 6815d3c19..740907567 100644 --- a/LibCpp2IL/ClassReadingBinaryReader.cs +++ b/LibCpp2IL/ClassReadingBinaryReader.cs @@ -2,15 +2,13 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; using System.Text; using System.Threading; using LibCpp2IL.Metadata; namespace LibCpp2IL; -public abstract class ClassReadingBinaryReader : EndianAwareBinaryReader +public abstract class ClassReadingBinaryReader(Stream input) : EndianAwareBinaryReader(input) { /// /// Set this to true to enable storing of amount of bytes read of each readable structure. @@ -20,7 +18,7 @@ public abstract class ClassReadingBinaryReader : EndianAwareBinaryReader private SpinLock PositionShiftLock; public bool is32Bit; - private MemoryStream? _memoryStream; + private readonly MemoryStream? _memoryStream = input as MemoryStream; public ulong PointerSize => is32Bit ? 4ul : 8ul; @@ -30,17 +28,6 @@ public abstract class ClassReadingBinaryReader : EndianAwareBinaryReader public abstract float MetadataVersion { get; } - - public ClassReadingBinaryReader(MemoryStream input) : base(input) - { - _memoryStream = input; - } - - public ClassReadingBinaryReader(Stream input) : base(input) - { - _memoryStream = null; - } - public long Position { get => BaseStream.Position; @@ -177,6 +164,7 @@ protected internal int ReadUnityCompressedIntAtRawAddr(long position, bool doLoc private T InternalReadReadableClass() where T : ReadableClass, new() { var t = new T { MetadataVersion = MetadataVersion }; + OnReadableCreated(t); if (!_inReadableRead) { @@ -192,6 +180,12 @@ protected internal int ReadUnityCompressedIntAtRawAddr(long position, bool doLoc return t; } + /// + /// Called after a ReadableClass instance is created but before Read is called. + /// Override in subclasses to set OwningContext on newly created instances. + /// + protected virtual void OnReadableCreated(ReadableClass instance) { } + private object InternalReadClass(Type type, bool overrideArchCheck = false) { if (type.IsPrimitive) diff --git a/LibCpp2IL/Elf/ElfFile.cs b/LibCpp2IL/Elf/ElfFile.cs index 0dae7bad4..648b7caae 100644 --- a/LibCpp2IL/Elf/ElfFile.cs +++ b/LibCpp2IL/Elf/ElfFile.cs @@ -689,14 +689,14 @@ public override (ulong pCodeRegistration, ulong pMetadataRegistration) FindCodeA var typeDefinitionsCount = metadata.TypeDefinitionCount; LibLogger.VerboseNewline("Searching for il2cpp structures in an ELF binary using non-arch-specific method..."); - var searcher = new BinarySearcher(this, methodCount, typeDefinitionsCount); + var searcher = new BinarySearcher(this, metadata, methodCount, typeDefinitionsCount); LibLogger.VerboseNewline("\tLooking for code reg (this might take a while)..."); - var codeReg = metadata.MetadataVersion >= 24.2f ? searcher.FindCodeRegistrationPost2019(metadata) : searcher.FindCodeRegistrationPre2019(); + var codeReg = metadata.MetadataVersion >= 24.2f ? searcher.FindCodeRegistrationPost2019() : searcher.FindCodeRegistrationPre2019(); LibLogger.VerboseNewline($"\tGot code reg 0x{codeReg:X}"); LibLogger.VerboseNewline($"\tLooking for meta reg ({(metadata.MetadataVersion >= 27f ? "post-27" : "pre-27")})..."); - var metaReg = metadata.MetadataVersion >= 27f ? searcher.FindMetadataRegistrationPost24_5(metadata) : searcher.FindMetadataRegistrationPre24_5(); + var metaReg = metadata.MetadataVersion >= 27f ? searcher.FindMetadataRegistrationPost24_5() : searcher.FindMetadataRegistrationPre24_5(); LibLogger.VerboseNewline($"\tGot meta reg 0x{metaReg:x}"); return (codeReg, metaReg); diff --git a/LibCpp2IL/Il2CppBinary.cs b/LibCpp2IL/Il2CppBinary.cs index 734b34385..de206af1c 100644 --- a/LibCpp2IL/Il2CppBinary.cs +++ b/LibCpp2IL/Il2CppBinary.cs @@ -52,6 +52,9 @@ public abstract class Il2CppBinary(MemoryStream input) : ClassReadingBinaryReade private readonly Dictionary _typesByAddress = new(); public abstract long RawLength { get; } + + public int PointerSizeBytes => is32Bit ? 4 : 8; + public int NumTypes => _types.Length; public Il2CppType[] AllTypes => _types; @@ -61,16 +64,24 @@ public abstract class Il2CppBinary(MemoryStream input) : ClassReadingBinaryReade /// public virtual ClassReadingBinaryReader Reader => this; - private float? _metadataVersion; - public sealed override float MetadataVersion => _metadataVersion ?? 0; + public sealed override float MetadataVersion => + _context?.Metadata.MetadataVersion ?? 0; public int InBinaryMetadataSize { get; private set; } - private Il2CppMetadata? _metadata; + private LibCpp2IlContext? _context; - public void Init(Il2CppMetadata metadata) + protected override void OnReadableCreated(ReadableClass instance) { - _metadataVersion = metadata.MetadataVersion; + if (_context != null) + instance.OwningContext = _context; + } + + public void Init(LibCpp2IlContext context) + { + var metadata = context.Metadata ?? throw new InvalidOperationException("The metadata must be initialized before the binary."); + context.Binary = this; + _context = context; var start = DateTime.Now; @@ -88,7 +99,6 @@ public void Init(Il2CppMetadata metadata) public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMetadata metadata) { - _metadata = metadata; // Ensure any derived code that needs max metadata usages can access it without static metadata. _maxMetadataUsages = metadata.GetMaxMetadataUsages(); @@ -113,8 +123,6 @@ public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMet LibLogger.Verbose("\tReading generic instances..."); var start = DateTime.Now; _genericInsts = Array.ConvertAll(ReadNUintArrayAtVirtualAddress(_metadataRegistration.genericInsts, _metadataRegistration.genericInstsCount), ReadReadableAtVirtualAddress); - foreach (var gi in _genericInsts) - gi.OwningBinary = this; LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)"); InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear(); @@ -166,9 +174,6 @@ public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMet for (var i = 0; i < _metadataRegistration.numTypes; ++i) { _types[i] = ReadReadableAtVirtualAddress(typePtrs[i]); - _types[i].OwningBinary = this; - _types[i].OwningMetadata = metadata; - _types[i].Il2CppTypeHasNumMods5Bits = metadata.MetadataVersion >= 27.2f; _typesByAddress[typePtrs[i]] = _types[i]; } @@ -207,7 +212,6 @@ public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMet for (var i = 0; i < codeGenModulePtrs.Length; i++) { var codeGenModule = ReadReadableAtVirtualAddress(codeGenModulePtrs[i]); - codeGenModule.OwningBinary = this; _codeGenModules[i] = codeGenModule; _codeGenModulesByName[codeGenModule.Name] = codeGenModule; var name = codeGenModule.Name; @@ -255,11 +259,6 @@ public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMet try { var rgctxs = ReadReadableArrayAtVirtualAddress(codeGenModule.rgctxs, codeGenModule.rgctxsCount); - foreach (var rgctx in rgctxs) - { - rgctx.OwningBinary = this; - rgctx.OwningMetadata = metadata; - } _codegenModuleRgctxs[i] = rgctxs; LibLogger.VerboseNewline($"\t\t\t-Read {codeGenModule.rgctxsCount} RGCTXs."); } @@ -297,11 +296,6 @@ public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMet LibLogger.Verbose("\tReading method specifications..."); start = DateTime.Now; _methodSpecs = ReadReadableArrayAtVirtualAddress(_metadataRegistration.methodSpecs, _metadataRegistration.methodSpecsCount); - foreach (var ms in _methodSpecs) - { - ms.OwningBinary = this; - ms.OwningMetadata = metadata; - } LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)"); InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear(); @@ -507,7 +501,7 @@ public ulong GetMethodPointer(int methodIndex, Il2CppVariableWidthIndex MetadataVersion >= 29 ? [] : MetadataVersion >= 27 ? AllCustomAttributeGeneratorsV27 : _customAttributeGenerators!; private ulong[] AllCustomAttributeGeneratorsV27 => - (_metadata ?? throw new InvalidOperationException("Binary not initialized")) + (_context?.Metadata ?? throw new InvalidOperationException("Binary not initialized")) .imageDefinitions .Select(i => (image: i, cgm: GetCodegenModuleByName(i.Name!)!)) .SelectMany(tuple => LibCpp2ILUtils.Range(0, (int)tuple.image.customAttributeCount).Select(o => tuple.cgm.customAttributeCacheGenerator + (ulong)o * PointerSize)) @@ -532,21 +526,21 @@ public virtual bool TryGetExportedFunctionName(ulong addr, [NotNullWhen(true)] o public virtual (ulong pCodeRegistration, ulong pMetadataRegistration) FindCodeAndMetadataReg(Il2CppMetadata metadata) { - if (!_metadataVersion.HasValue) - throw new InvalidOperationException("MetadataVersion must be set before searching for code and metadata registration. Call SetMetadataVersion first."); + if (MetadataVersion == 0) + throw new InvalidOperationException("MetadataVersion must be set before searching for code and metadata registration."); LibLogger.VerboseNewline("\tAttempting to locate code and metadata registration functions..."); var methodCount = metadata.methodDefs.Count(x => x.methodIndex >= 0); var typeDefinitionsCount = metadata.TypeDefinitionCount; - var plusSearch = new BinarySearcher(this, methodCount, typeDefinitionsCount); + var plusSearch = new BinarySearcher(this, metadata, methodCount, typeDefinitionsCount); LibLogger.VerboseNewline("\t\t-Searching for MetadataReg..."); var pMetadataRegistration = metadata.MetadataVersion < 24.5f ? plusSearch.FindMetadataRegistrationPre24_5() - : plusSearch.FindMetadataRegistrationPost24_5(metadata); + : plusSearch.FindMetadataRegistrationPost24_5(); LibLogger.VerboseNewline("\t\t-Searching for CodeReg..."); @@ -554,7 +548,7 @@ public virtual (ulong pCodeRegistration, ulong pMetadataRegistration) FindCodeAn if (metadata.MetadataVersion >= 24.2f) { LibLogger.VerboseNewline("\t\t\tUsing mscorlib full-disassembly approach to get codereg, this may take a while..."); - pCodeRegistration = plusSearch.FindCodeRegistrationPost2019(metadata); + pCodeRegistration = plusSearch.FindCodeRegistrationPost2019(); } else pCodeRegistration = plusSearch.FindCodeRegistrationPre2019(); diff --git a/LibCpp2IL/LibCpp2IlBinaryRegistry.cs b/LibCpp2IL/LibCpp2IlBinaryRegistry.cs index 08a7a1c65..5c60598a9 100644 --- a/LibCpp2IL/LibCpp2IlBinaryRegistry.cs +++ b/LibCpp2IL/LibCpp2IlBinaryRegistry.cs @@ -5,7 +5,6 @@ using LibCpp2IL.Elf; using LibCpp2IL.Logging; using LibCpp2IL.MachO; -using LibCpp2IL.Metadata; using LibCpp2IL.NintendoSwitch; using LibCpp2IL.Wasm; @@ -49,7 +48,7 @@ public static void Register(string name, string source, Func is _binaries.Add(new(name, source, isValid, factory)); } - internal static Il2CppBinary CreateAndInit(byte[] buffer, Il2CppMetadata metadata) + internal static Il2CppBinary CreateAndInit(byte[] buffer, LibCpp2IlContext context) { if (_binaries.Count == 0) RegisterBuiltInBinarySupport(); @@ -67,9 +66,7 @@ internal static Il2CppBinary CreateAndInit(byte[] buffer, Il2CppMetadata metadat var binary = match.FactoryFunc(memStream); - // NOTE: Do not write to LibCpp2IlMain.Binary here. The binary registry is global, but the loaded binary is per-context. - - binary.Init(metadata); + binary.Init(context); return binary; } diff --git a/LibCpp2IL/LibCpp2IlContext.cs b/LibCpp2IL/LibCpp2IlContext.cs index bc72908c3..d057f2a16 100644 --- a/LibCpp2IL/LibCpp2IlContext.cs +++ b/LibCpp2IL/LibCpp2IlContext.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using LibCpp2IL.Metadata; using LibCpp2IL.Reflection; @@ -11,17 +12,26 @@ public sealed class LibCpp2IlContext { public LibCpp2IlMain.LibCpp2IlSettings Settings { get; } - public bool Il2CppTypeHasNumMods5Bits { get; internal set; } + public bool Il2CppTypeHasNumMods5Bits => Metadata.MetadataVersion >= 27.2f; public Il2CppBinary Binary { get; internal set; } = null!; public Il2CppMetadata Metadata { get; internal set; } = null!; - public float MetadataVersion => Metadata.MetadataVersion; - public Dictionary> MethodsByPtr { get; } = new(); public LibCpp2IlReflectionCache ReflectionCache { get; } = new(); + // Global mapper state + internal List TypeRefs = []; + internal List MethodRefs = []; + internal List FieldRefs = []; + internal List Literals = []; + + internal readonly Dictionary TypeRefsByAddress = new(); + internal readonly Dictionary MethodRefsByAddress = new(); + internal readonly Dictionary FieldRefsByAddress = new(); + internal readonly Dictionary LiteralsByAddress = new(); + internal LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings) { Settings = settings; @@ -30,10 +40,86 @@ internal LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings) public List? GetManagedMethodImplementationsAtAddress(ulong addr) => MethodsByPtr.TryGetValue(addr, out var ret) ? ret : null; + internal void MapGlobalIdentifiers() + { + if (Metadata.MetadataVersion < 27f) + MapGlobalIdentifiersPre27(); + + // Post-27 is a no-op + } + + private void MapGlobalIdentifiersPre27() + { + //Type 1 => TypeInfo + //Type 2 => Il2CppType + //Type 3 => MethodDef + //Type 4 => FieldInfo + //Type 5 => StringLiteral + //Type 6 => MethodRef + + //Type references + + //We non-null assert here because this function is only called pre-27, when this is guaranteed to be non-null + TypeRefs = Metadata.metadataUsageDic![(uint)MetadataUsageType.TypeInfo] + .Select(kvp => new MetadataUsage(MetadataUsageType.Type, Binary.GetRawMetadataUsage(kvp.Key), kvp.Value, this)) + .ToList(); + + //More type references + TypeRefs.AddRange(Metadata.metadataUsageDic[(uint)MetadataUsageType.Type] + .Select(kvp => new MetadataUsage(MetadataUsageType.Type, Binary.GetRawMetadataUsage(kvp.Key), kvp.Value, this)) + ); + + //Method references + MethodRefs = Metadata.metadataUsageDic[(uint)MetadataUsageType.MethodDef] + .Select(kvp => new MetadataUsage(MetadataUsageType.MethodDef, Binary.GetRawMetadataUsage(kvp.Key), kvp.Value, this)) + .ToList(); + + //Field references + FieldRefs = Metadata.metadataUsageDic[(uint)MetadataUsageType.FieldInfo] + .Select(kvp => new MetadataUsage(MetadataUsageType.FieldInfo, Binary.GetRawMetadataUsage(kvp.Key), kvp.Value, this)) + .ToList(); + + //Literals + Literals = Metadata.metadataUsageDic[(uint)MetadataUsageType.StringLiteral] + .Select(kvp => new MetadataUsage(MetadataUsageType.StringLiteral, Binary.GetRawMetadataUsage(kvp.Key), kvp.Value, this)).ToList(); + + //Generic method references + foreach (var (metadataUsageIdx, methodSpecIdx) in Metadata.metadataUsageDic[(uint)MetadataUsageType.MethodRef]) //kIl2CppMetadataUsageMethodRef + { + MethodRefs.Add(new MetadataUsage(MetadataUsageType.MethodRef, Binary.GetRawMetadataUsage(metadataUsageIdx), methodSpecIdx, this)); + } + + foreach (var globalIdentifier in TypeRefs) + TypeRefsByAddress[globalIdentifier.Offset] = globalIdentifier; + + foreach (var globalIdentifier in MethodRefs) + MethodRefsByAddress[globalIdentifier.Offset] = globalIdentifier; + + foreach (var globalIdentifier in FieldRefs) + FieldRefsByAddress[globalIdentifier.Offset] = globalIdentifier; + + foreach (var globalIdentifier in Literals) + LiteralsByAddress[globalIdentifier.Offset] = globalIdentifier; + } + + public MetadataUsage? CheckForPost27GlobalAt(ulong address) + { + if (!Binary.TryMapVirtualAddressToRaw(address, out var raw) || raw >= Binary.RawLength) + return null; + + var encoded = Binary.ReadPointerAtVirtualAddress(address); + var metadataUsage = MetadataUsage.DecodeMetadataUsage(encoded, address, this); + + if (metadataUsage?.IsValid != true) + return null; + + return metadataUsage; + } + public MetadataUsage? GetAnyGlobalByAddress(ulong address) { - if (MetadataVersion >= 27f) - return LibCpp2IlGlobalMapper.CheckForPost27GlobalAt(address); + if (Metadata.MetadataVersion >= 27f) + return CheckForPost27GlobalAt(address); var glob = GetLiteralGlobalByAddress(address); glob ??= GetMethodGlobalByAddress(address); @@ -44,7 +130,7 @@ internal LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings) } public MetadataUsage? GetLiteralGlobalByAddress(ulong address) - => MetadataVersion < 27f ? LibCpp2IlGlobalMapper.LiteralsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); + => Metadata.MetadataVersion < 27f ? LiteralsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); public string? GetLiteralByAddress(ulong address) { @@ -56,7 +142,7 @@ internal LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings) } public MetadataUsage? GetRawTypeGlobalByAddress(ulong address) - => MetadataVersion < 27f ? LibCpp2IlGlobalMapper.TypeRefsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); + => Metadata.MetadataVersion < 27f ? TypeRefsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); public Il2CppTypeReflectionData? GetTypeGlobalByAddress(ulong address) { @@ -69,13 +155,13 @@ internal LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings) } public MetadataUsage? GetRawFieldGlobalByAddress(ulong address) - => MetadataVersion < 27f ? LibCpp2IlGlobalMapper.FieldRefsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); + => Metadata.MetadataVersion < 27f ? FieldRefsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); public Il2CppFieldDefinition? GetFieldGlobalByAddress(ulong address) => GetRawFieldGlobalByAddress(address)?.AsField(); public MetadataUsage? GetMethodGlobalByAddress(ulong address) - => MetadataVersion < 27f ? LibCpp2IlGlobalMapper.MethodRefsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); + => Metadata.MetadataVersion < 27f ? MethodRefsByAddress.GetOrDefault(address) : GetAnyGlobalByAddress(address); public Il2CppMethodDefinition? GetMethodDefinitionByGlobalAddress(ulong address) { diff --git a/LibCpp2IL/LibCpp2IlContextBuilder.cs b/LibCpp2IL/LibCpp2IlContextBuilder.cs index db07db13c..9c23116f9 100644 --- a/LibCpp2IL/LibCpp2IlContextBuilder.cs +++ b/LibCpp2IL/LibCpp2IlContextBuilder.cs @@ -15,6 +15,7 @@ public sealed class LibCpp2IlContextBuilder AllowManualMetadataAndCodeRegInput = LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput, DisableMethodPointerMapping = LibCpp2IlMain.Settings.DisableMethodPointerMapping, DisableGlobalResolving = LibCpp2IlMain.Settings.DisableGlobalResolving, + MetadataFixupFunc = LibCpp2IlMain.Settings.MetadataFixupFunc }); private bool _metadataLoaded; @@ -30,11 +31,8 @@ public void LoadMetadata(byte[] metadataBytes, UnityVersion unityVersion) { metadata = Il2CppMetadata.ReadFrom(metadataBytes, unityVersion); } - catch (Exception e) + catch (Exception e) when (_context.Settings.MetadataFixupFunc is { } fixupFunc) { - if (LibCpp2IlMain.Settings.MetadataFixupFunc is not { } fixupFunc) - throw; - try { LibLogger.WarnNewline("Metadata read failed, but a fixup function is registered. Calling fixup function and then will attempt to read again..."); @@ -54,17 +52,15 @@ public void LoadMetadata(byte[] metadataBytes, UnityVersion unityVersion) } } - _context.Metadata = metadata; - - _context.Il2CppTypeHasNumMods5Bits = metadata.MetadataVersion >= 27.2f; - LibLogger.InfoNewline($"Initialized Metadata in {(DateTime.Now - start).TotalMilliseconds:F0}ms"); - // Legacy/static API compatibility: some in-binary structures still resolve via LibCpp2IlMain.Binary/TheMetadata - // during binary initialization, so we must set metadata defaults before initializing the binary. - LibCpp2IlMain.TheMetadata = metadata; - LibCpp2IlMain.DefaultContext = _context; - LibCpp2IlMain.Il2CppTypeHasNumMods5Bits = _context.Il2CppTypeHasNumMods5Bits; + LoadMetadata(metadata); + } + + public void LoadMetadata(Il2CppMetadata metadata) + { + _context.Metadata = metadata; + metadata.SetOwningContext(_context); _metadataLoaded = true; } @@ -74,10 +70,7 @@ public void LoadBinary(byte[] binaryBytes) if (!_metadataLoaded) throw new InvalidOperationException("Metadata must be loaded before the binary can be loaded."); - var bin = _context.Binary = LibCpp2IlBinaryRegistry.CreateAndInit(binaryBytes, _context.Metadata); - - // Complete legacy/static initialization now that the binary exists. - LibCpp2IlMain.Binary = bin; + LibCpp2IlBinaryRegistry.CreateAndInit(binaryBytes, _context); _binaryLoaded = true; } @@ -87,12 +80,7 @@ public void LoadBinary(Il2CppBinary binary) if (!_metadataLoaded) throw new InvalidOperationException("Metadata must be loaded before the binary can be loaded."); - binary.Init(_context.Metadata); - - _context.Binary = binary; - - // Complete legacy/static initialization now that the binary exists. - LibCpp2IlMain.Binary = binary; + binary.Init(_context); _binaryLoaded = true; } @@ -105,18 +93,19 @@ public LibCpp2IlContext Build() if (!_binaryLoaded) throw new InvalidOperationException("Binary must be loaded before context can be built."); - DateTime start; - if (!_context.Settings.DisableGlobalResolving && _context.MetadataVersion < 27) + _context.ReflectionCache.Init(_context); + + if (!_context.Settings.DisableGlobalResolving && _context.Metadata.MetadataVersion < 27) { - start = DateTime.Now; + var start = DateTime.Now; LibLogger.Info("Mapping Globals..."); - LibCpp2IlGlobalMapper.MapGlobalIdentifiers(_context.Metadata, _context.Binary); + _context.MapGlobalIdentifiers(); LibLogger.InfoNewline($"OK ({(DateTime.Now - start).TotalMilliseconds:F0}ms)"); } if (!_context.Settings.DisableMethodPointerMapping) { - start = DateTime.Now; + var start = DateTime.Now; LibLogger.Info("Mapping pointers to Il2CppMethodDefinitions..."); foreach (var (method, ptr) in _context.Metadata.methodDefs.Select(method => (method, ptr: method.MethodPointer))) { @@ -129,8 +118,6 @@ public LibCpp2IlContext Build() LibLogger.InfoNewline($"Processed {_context.Metadata.methodDefs.Length} OK ({(DateTime.Now - start).TotalMilliseconds:F0}ms)"); } - _context.ReflectionCache.Init(_context); - return _context; } @@ -149,11 +136,6 @@ public static LibCpp2IlContext BuildFromFiles(string pePath, string metadataPath var metadataBytes = File.ReadAllBytes(metadataPath); var peBytes = File.ReadAllBytes(pePath); - LibCpp2IlContextBuilder builder = new(); - - builder.LoadMetadata(metadataBytes, unityVersion); - builder.LoadBinary(peBytes); - - return builder.Build(); + return Build(peBytes, metadataBytes, unityVersion); } } diff --git a/LibCpp2IL/LibCpp2IlGlobalMapper.cs b/LibCpp2IL/LibCpp2IlGlobalMapper.cs deleted file mode 100644 index acaa4f82c..000000000 --- a/LibCpp2IL/LibCpp2IlGlobalMapper.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using LibCpp2IL.Metadata; - -namespace LibCpp2IL; - -public static class LibCpp2IlGlobalMapper -{ - internal static List TypeRefs = []; - internal static List MethodRefs = []; - internal static List FieldRefs = []; - internal static List Literals = []; - - internal static Dictionary TypeRefsByAddress = new(); - internal static Dictionary MethodRefsByAddress = new(); - internal static Dictionary FieldRefsByAddress = new(); - internal static Dictionary LiteralsByAddress = new(); - - internal static void Reset() - { - TypeRefs.Clear(); - MethodRefs.Clear(); - FieldRefs.Clear(); - Literals.Clear(); - TypeRefsByAddress.Clear(); - MethodRefsByAddress.Clear(); - FieldRefsByAddress.Clear(); - LiteralsByAddress.Clear(); - } - - internal static void MapGlobalIdentifiers(Il2CppMetadata metadata, Il2CppBinary cppAssembly) - { - if (metadata.MetadataVersion < 27f) - MapGlobalIdentifiersPre27(metadata, cppAssembly); - else - MapGlobalIdentifiersPost27(metadata, cppAssembly); - } - - private static void MapGlobalIdentifiersPost27(Il2CppMetadata metadata, Il2CppBinary cppAssembly) - { - //No-op - } - - private static void MapGlobalIdentifiersPre27(Il2CppMetadata metadata, Il2CppBinary cppAssembly) - { - //Type 1 => TypeInfo - //Type 2 => Il2CppType - //Type 3 => MethodDef - //Type 4 => FieldInfo - //Type 5 => StringLiteral - //Type 6 => MethodRef - - //Type references - - //We non-null assert here because this function is only called pre-27, when this is guaranteed to be non-null - TypeRefs = metadata.metadataUsageDic![(uint)MetadataUsageType.TypeInfo] - .Select(kvp => new MetadataUsage(MetadataUsageType.Type, cppAssembly.GetRawMetadataUsage(kvp.Key), kvp.Value)) - .ToList(); - - //More type references - TypeRefs.AddRange(metadata.metadataUsageDic[(uint)MetadataUsageType.Type] - .Select(kvp => new MetadataUsage(MetadataUsageType.Type, cppAssembly.GetRawMetadataUsage(kvp.Key), kvp.Value)) - ); - - //Method references - MethodRefs = metadata.metadataUsageDic[(uint)MetadataUsageType.MethodDef] - .Select(kvp => new MetadataUsage(MetadataUsageType.MethodDef, cppAssembly.GetRawMetadataUsage(kvp.Key), kvp.Value)) - .ToList(); - - //Field references - FieldRefs = metadata.metadataUsageDic[(uint)MetadataUsageType.FieldInfo] - .Select(kvp => new MetadataUsage(MetadataUsageType.FieldInfo, cppAssembly.GetRawMetadataUsage(kvp.Key), kvp.Value)) - .ToList(); - - //Literals - Literals = metadata.metadataUsageDic[(uint)MetadataUsageType.StringLiteral] - .Select(kvp => new MetadataUsage(MetadataUsageType.StringLiteral, cppAssembly.GetRawMetadataUsage(kvp.Key), kvp.Value)).ToList(); - - //Generic method references - foreach (var (metadataUsageIdx, methodSpecIdx) in metadata.metadataUsageDic[(uint)MetadataUsageType.MethodRef]) //kIl2CppMetadataUsageMethodRef - { - MethodRefs.Add(new MetadataUsage(MetadataUsageType.MethodRef, cppAssembly.GetRawMetadataUsage(metadataUsageIdx), methodSpecIdx)); - } - - foreach (var globalIdentifier in TypeRefs) - TypeRefsByAddress[globalIdentifier.Offset] = globalIdentifier; - - foreach (var globalIdentifier in MethodRefs) - MethodRefsByAddress[globalIdentifier.Offset] = globalIdentifier; - - foreach (var globalIdentifier in FieldRefs) - FieldRefsByAddress[globalIdentifier.Offset] = globalIdentifier; - - foreach (var globalIdentifier in Literals) - LiteralsByAddress[globalIdentifier.Offset] = globalIdentifier; - } - - public static MetadataUsage? CheckForPost27GlobalAt(ulong address) - { - if (!LibCpp2IlMain.Binary!.TryMapVirtualAddressToRaw(address, out var raw) || raw >= LibCpp2IlMain.Binary.RawLength) - return null; - - var encoded = LibCpp2IlMain.Binary.ReadPointerAtVirtualAddress(address); - var metadataUsage = MetadataUsage.DecodeMetadataUsage(encoded, address); - - if (metadataUsage?.IsValid != true) - return null; - - return metadataUsage; - } -} diff --git a/LibCpp2IL/LibCpp2IlMain.cs b/LibCpp2IL/LibCpp2IlMain.cs index 9f2c579f1..ba692bd02 100644 --- a/LibCpp2IL/LibCpp2IlMain.cs +++ b/LibCpp2IL/LibCpp2IlMain.cs @@ -14,7 +14,7 @@ namespace LibCpp2IL; public static class LibCpp2IlMain { public delegate byte[]? MetadataFixupFunc(byte[] originalBytes, UnityVersion unityVersion); - + private static readonly Regex UnityVersionRegex = new Regex(@"^[0-9]+\.[0-9]+\.[0-9]+[abcfxp][0-9]+$", RegexOptions.Compiled); public class LibCpp2IlSettings @@ -28,181 +28,16 @@ public class LibCpp2IlSettings public static readonly LibCpp2IlSettings Settings = new(); /// - /// Backwards-compatible default context. Existing static APIs are effectively wrappers around this. - /// New code should prefer creating and passing around a . + /// Initialize the metadata and binary from a pair of byte arrays, returning a context. /// - public static LibCpp2IlContext? DefaultContext { get; set; } - - public static bool Il2CppTypeHasNumMods5Bits; - public static float MetadataVersion => DefaultContext?.MetadataVersion ?? TheMetadata!.MetadataVersion; - - public static Il2CppBinary? Binary; - public static Il2CppMetadata? TheMetadata; - - public static readonly Dictionary> MethodsByPtr = new(); - - public static void Reset() - { - LibCpp2IlGlobalMapper.Reset(); - MethodsByPtr.Clear(); - - DefaultContext = null; - Binary = null; - TheMetadata = null; - - // Note: reflection caches are per-context now; legacy static caches are not reset here. - } - - public static List? GetManagedMethodImplementationsAtAddress(ulong addr) - { - MethodsByPtr.TryGetValue(addr, out var ret); - - return ret; - } - - public static MetadataUsage? GetAnyGlobalByAddress(ulong address) - { - if (MetadataVersion >= 27f) - return LibCpp2IlGlobalMapper.CheckForPost27GlobalAt(address); - - //Pre-27 - var glob = GetLiteralGlobalByAddress(address); - glob ??= GetMethodGlobalByAddress(address); - glob ??= GetRawFieldGlobalByAddress(address); - glob ??= GetRawTypeGlobalByAddress(address); - - return glob; - } - - public static MetadataUsage? GetLiteralGlobalByAddress(ulong address) - { - if (MetadataVersion < 27f) - return LibCpp2IlGlobalMapper.LiteralsByAddress.GetOrDefault(address); - - return GetAnyGlobalByAddress(address); - } - - public static string? GetLiteralByAddress(ulong address) - { - var literal = GetLiteralGlobalByAddress(address); - if (literal?.Type != MetadataUsageType.StringLiteral) - return null; - - return literal.AsLiteral(); - } - - public static MetadataUsage? GetRawTypeGlobalByAddress(ulong address) - { - if (MetadataVersion < 27f) - return LibCpp2IlGlobalMapper.TypeRefsByAddress.GetOrDefault(address); - - return GetAnyGlobalByAddress(address); - } - - public static Il2CppTypeReflectionData? GetTypeGlobalByAddress(ulong address) - { - if (TheMetadata == null) return null; - - var typeGlobal = GetRawTypeGlobalByAddress(address); - - if (typeGlobal?.Type is not (MetadataUsageType.Type or MetadataUsageType.TypeInfo)) - return null; - - return typeGlobal.AsType(); - } - - public static MetadataUsage? GetRawFieldGlobalByAddress(ulong address) - { - if (MetadataVersion < 27f) - return LibCpp2IlGlobalMapper.FieldRefsByAddress.GetOrDefault(address); - return GetAnyGlobalByAddress(address); - } - - public static Il2CppFieldDefinition? GetFieldGlobalByAddress(ulong address) - { - if (TheMetadata == null) return null; - - var typeGlobal = GetRawFieldGlobalByAddress(address); - - return typeGlobal?.AsField(); - } - - public static MetadataUsage? GetMethodGlobalByAddress(ulong address) - { - if (TheMetadata == null) return null; - - if (MetadataVersion < 27f) - return LibCpp2IlGlobalMapper.MethodRefsByAddress.GetOrDefault(address); - - return GetAnyGlobalByAddress(address); - } - - public static Il2CppMethodDefinition? GetMethodDefinitionByGlobalAddress(ulong address) - { - var global = GetMethodGlobalByAddress(address); - - if (global?.Type == MetadataUsageType.MethodRef) - return global.AsGenericMethodRef().BaseMethod; - - return global?.AsMethod(); - } - - /// - /// Initialize the metadata and PE from a pair of byte arrays. - /// - /// The content of the GameAssembly.dll file. - /// The content of the global-metadata.dat file - /// The unity version - /// True if the initialize succeeded, else false - /// if the metadata is invalid (bad magic number, bad version), or if the PE is invalid (bad header signature, bad magic number)
- /// if the PE file specifies it is neither for AMD64 or i386 architecture - public static bool Initialize(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion) - { - DefaultContext = LibCpp2IlContextBuilder.Build(binaryBytes, metadataBytes, unityVersion); - - // Preserve legacy static fields for existing consumers. - TheMetadata = DefaultContext.Metadata; - Binary = DefaultContext.Binary; - Il2CppTypeHasNumMods5Bits = DefaultContext.Il2CppTypeHasNumMods5Bits; - - // Keep legacy MethodsByPtr populated for old call sites. - MethodsByPtr.Clear(); - foreach (var kvp in DefaultContext.MethodsByPtr) - MethodsByPtr[kvp.Key] = kvp.Value; - - return true; - } - public static LibCpp2IlContext InitializeAsContext(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion) => LibCpp2IlContextBuilder.Build(binaryBytes, metadataBytes, unityVersion); - public static LibCpp2IlContext LoadFromFileAsContext(string pePath, string metadataPath, UnityVersion unityVersion) - => LibCpp2IlContextBuilder.BuildFromFiles(pePath, metadataPath, unityVersion); - /// - /// Initialize the metadata and PE from their respective file locations. + /// Initialize the metadata and binary from file paths, returning a context. /// - /// The path to the GameAssembly.dll file - /// The path to the global-metadata.dat file - /// The unity version, split on periods, with the patch version (e.g. f1) stripped out. For example, [2018, 2, 0] - /// True if the initialize succeeded, else false - /// if the metadata is invalid (bad magic number, bad version), or if the PE is invalid (bad header signature, bad magic number)
- /// if the PE file specifies it is neither for AMD64 or i386 architecture - public static bool LoadFromFile(string pePath, string metadataPath, UnityVersion unityVersion) - { - var ctx = LibCpp2IlContextBuilder.BuildFromFiles(pePath, metadataPath, unityVersion); - DefaultContext = ctx; - - TheMetadata = ctx.Metadata; - Binary = ctx.Binary; - Il2CppTypeHasNumMods5Bits = ctx.Il2CppTypeHasNumMods5Bits; - - MethodsByPtr.Clear(); - foreach (var kvp in ctx.MethodsByPtr) - MethodsByPtr[kvp.Key] = kvp.Value; - - return true; - } + public static LibCpp2IlContext LoadFromFileAsContext(string pePath, string metadataPath, UnityVersion unityVersion) + => LibCpp2IlContextBuilder.BuildFromFiles(pePath, metadataPath, unityVersion); /// /// Attempts to determine the Unity version from the given binary path and game data path @@ -240,7 +75,7 @@ public static UnityVersion DetermineUnityVersion(string? unityPlayerPath, string LibLogger.VerboseNewline($"DetermineUnityVersion: No globalgamemanagers or data.unity3d found in game data path."); } - + if (Environment.OSVersion.Platform == PlatformID.Win32NT && !string.IsNullOrEmpty(unityPlayerPath)) { LibLogger.VerboseNewline($"DetermineUnityVersion: Running on windows so have FileVersionInfo, trying to pull version from unity player {unityPlayerPath}"); @@ -328,4 +163,87 @@ public static UnityVersion GetVersionFromDataUnity3D(Stream fileStream) return UnityVersion.Parse(unityVer); } + + #region Legacy static API — kept for backwards compatibility during migration + + // These fields exist solely to allow external consumers to keep working during the transition to context-based APIs. + // New code should use LibCpp2IlContext directly. + + private static LibCpp2IlContext? _defaultContext; + + [Obsolete("Use LibCpp2IlContext instead.")] + public static LibCpp2IlContext DefaultContext + { + get => _defaultContext ?? throw new InvalidOperationException("LibCpp2IL is not Initialized"); + set => _defaultContext = value; + } + + [Obsolete("Use LibCpp2IlContext.Binary instead.")] + public static Il2CppBinary Binary => DefaultContext.Binary; + + [Obsolete("Use LibCpp2IlContext.Metadata instead.")] + public static Il2CppMetadata TheMetadata => DefaultContext.Metadata; + + [Obsolete("Use context.Il2CppTypeHasNumMods5Bits instead.")] + public static bool Il2CppTypeHasNumMods5Bits => DefaultContext.Il2CppTypeHasNumMods5Bits; + + [Obsolete("Use LibCpp2IlContext.MetadataVersion instead.")] + public static float MetadataVersion => DefaultContext.Metadata.MetadataVersion; + + [Obsolete("Use LibCpp2IlContext.MethodsByPtr instead.")] + public static Dictionary> MethodsByPtr => DefaultContext.MethodsByPtr; + + [Obsolete("Use LibCpp2IlContextBuilder directly.")] + public static bool Initialize(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion) + { + _defaultContext = LibCpp2IlContextBuilder.Build(binaryBytes, metadataBytes, unityVersion); + + return true; + } + + [Obsolete("Use LibCpp2IlContextBuilder directly.")] + public static bool LoadFromFile(string pePath, string metadataPath, UnityVersion unityVersion) + { + _defaultContext = LibCpp2IlContextBuilder.BuildFromFiles(pePath, metadataPath, unityVersion); + + return true; + } + + [Obsolete("Use context.GetManagedMethodImplementationsAtAddress instead.")] + public static List? GetManagedMethodImplementationsAtAddress(ulong addr) => DefaultContext.GetManagedMethodImplementationsAtAddress(addr); + + [Obsolete("Use context.GetAnyGlobalByAddress instead.")] + public static MetadataUsage? GetAnyGlobalByAddress(ulong address) => DefaultContext.GetAnyGlobalByAddress(address); + + [Obsolete("Use context.GetLiteralGlobalByAddress instead.")] + public static MetadataUsage? GetLiteralGlobalByAddress(ulong address) => DefaultContext.GetLiteralGlobalByAddress(address); + + [Obsolete("Use context.GetLiteralByAddress instead.")] + public static string? GetLiteralByAddress(ulong address) => DefaultContext.GetLiteralByAddress(address); + + [Obsolete("Use context.GetRawTypeGlobalByAddress instead.")] + public static MetadataUsage? GetRawTypeGlobalByAddress(ulong address) => DefaultContext.GetRawTypeGlobalByAddress(address); + + [Obsolete("Use context.GetTypeGlobalByAddress instead.")] + public static Il2CppTypeReflectionData? GetTypeGlobalByAddress(ulong address) => DefaultContext.GetTypeGlobalByAddress(address); + + [Obsolete("Use context.GetRawFieldGlobalByAddress instead.")] + public static MetadataUsage? GetRawFieldGlobalByAddress(ulong address) => DefaultContext.GetRawFieldGlobalByAddress(address); + + [Obsolete("Use context.GetFieldGlobalByAddress instead.")] + public static Il2CppFieldDefinition? GetFieldGlobalByAddress(ulong address) => DefaultContext.GetFieldGlobalByAddress(address); + + [Obsolete("Use context.GetMethodGlobalByAddress instead.")] + public static MetadataUsage? GetMethodGlobalByAddress(ulong address) => DefaultContext.GetMethodGlobalByAddress(address); + + [Obsolete("Use context.GetMethodDefinitionByGlobalAddress instead.")] + public static Il2CppMethodDefinition? GetMethodDefinitionByGlobalAddress(ulong address) => DefaultContext.GetMethodDefinitionByGlobalAddress(address); + + [Obsolete("Use LibCpp2IlContext instead.")] + public static void Reset() + { + _defaultContext = null; + } + + #endregion } diff --git a/LibCpp2IL/LibCpp2IlUtils.cs b/LibCpp2IL/LibCpp2IlUtils.cs index b0537e671..1662ea88f 100644 --- a/LibCpp2IL/LibCpp2IlUtils.cs +++ b/LibCpp2IL/LibCpp2IlUtils.cs @@ -52,8 +52,11 @@ public static class LibCpp2ILUtils _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; - internal static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssembly, Il2CppTypeDefinition typeDef, bool fullName = false) + internal static string GetTypeName(LibCpp2IlContext context, Il2CppTypeDefinition typeDef, bool fullName = false) { + var metadata = context.Metadata; + var binary = context.Binary; + var ret = string.Empty; if (fullName) { @@ -66,14 +69,14 @@ internal static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAsse if (typeDef.DeclaringTypeIndex.IsNonNull) { - ret += GetTypeName(metadata, cppAssembly, cppAssembly.GetType(typeDef.DeclaringTypeIndex)) + "."; + ret += GetTypeName(context, binary.GetType(typeDef.DeclaringTypeIndex)) + "."; } ret += metadata.GetStringFromIndex(typeDef.NameIndex); var names = new List(); - if (typeDef.GenericContainer is not {} genericContainer) + if (typeDef.GenericContainer is not {} genericContainer) return ret; - + foreach (var parameter in genericContainer.GenericParameters) { names.Add(metadata.GetStringFromIndex(parameter.nameIndex)); @@ -85,30 +88,33 @@ internal static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAsse return ret; } - internal static Il2CppTypeReflectionData[]? GetGenericTypeParams(Il2CppGenericInst genericInst) + internal static Il2CppTypeReflectionData[] GetGenericTypeParams(Il2CppGenericInst genericInst) { - if (LibCpp2IlMain.Binary == null || LibCpp2IlMain.TheMetadata == null) return null; + var binary = genericInst.OwningContext.Binary; var types = new Il2CppTypeReflectionData[genericInst.pointerCount]; - var pointers = LibCpp2IlMain.Binary.ReadNUintArrayAtVirtualAddress(genericInst.pointerStart, (long)genericInst.pointerCount); + var pointers = binary.ReadNUintArrayAtVirtualAddress(genericInst.pointerStart, (long)genericInst.pointerCount); for (uint i = 0; i < genericInst.pointerCount; ++i) { - var oriType = LibCpp2IlMain.Binary.GetIl2CppTypeFromPointer(pointers[i]); + var oriType = binary.GetIl2CppTypeFromPointer(pointers[i]); types[i] = GetTypeReflectionData(oriType); } return types; } - internal static string GetGenericTypeParamNames(Il2CppMetadata metadata, Il2CppBinary cppAssembly, Il2CppGenericInst genericInst) + internal static string GetGenericTypeParamNames(LibCpp2IlContext context, Il2CppGenericInst genericInst) { - var typeNames = genericInst.Types.Select(t => GetTypeName(metadata, cppAssembly, t)).ToArray(); + var typeNames = genericInst.Types.Select(t => GetTypeName(context, t)).ToArray(); return $"<{string.Join(", ", typeNames)}>"; } - public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssembly, Il2CppType type, bool fullName = false) + public static string GetTypeName(LibCpp2IlContext context, Il2CppType type, bool fullName = false) { + var metadata = context.Metadata; + var binary = context.Binary; + string ret; switch (type.Type) { @@ -118,17 +124,17 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb var typeDef = type.AsClass(); ret = string.Empty; - ret += GetTypeName(metadata, cppAssembly, typeDef, fullName); + ret += GetTypeName(context, typeDef, fullName); break; } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { - var genericClass = cppAssembly.ReadReadableAtVirtualAddress(type.Data.GenericClass); + var genericClass = binary.ReadReadableAtVirtualAddress(type.Data.GenericClass); var typeDef = genericClass.TypeDefinition; ret = typeDef.Name!; - var genericInst = genericClass.Context.ClassInst; + var genericInst = genericClass.Context.ClassInst!; ret = ret.Replace($"`{genericInst.pointerCount}", ""); - ret += GetGenericTypeParamNames(metadata, cppAssembly, genericInst); + ret += GetGenericTypeParamNames(context, genericInst); break; } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: @@ -140,21 +146,21 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { - var arrayType = cppAssembly.ReadReadableAtVirtualAddress(type.Data.Array); + var arrayType = binary.ReadReadableAtVirtualAddress(type.Data.Array); var oriType = arrayType.ElementType; - ret = $"{GetTypeName(metadata, cppAssembly, oriType)}[{new string(',', arrayType.rank - 1)}]"; + ret = $"{GetTypeName(context, oriType)}[{new string(',', arrayType.rank - 1)}]"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { - var oriType = cppAssembly.GetIl2CppTypeFromPointer(type.Data.Type); - ret = $"{GetTypeName(metadata, cppAssembly, oriType)}[]"; + var oriType = binary.GetIl2CppTypeFromPointer(type.Data.Type); + ret = $"{GetTypeName(context, oriType)}[]"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { - var oriType = cppAssembly.GetIl2CppTypeFromPointer(type.Data.Type); - ret = $"{GetTypeName(metadata, cppAssembly, oriType)}*"; + var oriType = binary.GetIl2CppTypeFromPointer(type.Data.Type); + ret = $"{GetTypeName(context, oriType)}*"; break; } default: @@ -165,10 +171,9 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb return ret; } - internal static object? GetDefaultValue(Il2CppVariableWidthIndex dataIndex, Il2CppVariableWidthIndex typeIndex) + internal static object? GetDefaultValue(Il2CppVariableWidthIndex dataIndex, Il2CppVariableWidthIndex typeIndex, LibCpp2IlContext context) { - var metadata = LibCpp2IlMain.TheMetadata!; - var theDll = LibCpp2IlMain.Binary!; + var metadata = context.Metadata; if (dataIndex.IsNull) return null; //Literally null. @@ -176,7 +181,7 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb var pointer = metadata.GetDefaultValueFromIndex(dataIndex); if (pointer <= 0) return null; - var defaultValueType = theDll.GetType(typeIndex); + var defaultValueType = context.Binary.GetType(typeIndex); metadata.GetLockOrThrow(); metadata.Position = pointer; try @@ -196,11 +201,11 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb case Il2CppTypeEnum.IL2CPP_TYPE_I2: return metadata.ReadInt16(); case Il2CppTypeEnum.IL2CPP_TYPE_U4: - if (LibCpp2IlMain.MetadataVersion < 29) + if (metadata.MetadataVersion < 29) return metadata.ReadUInt32(); return metadata.ReadUnityCompressedUIntAtRawAddrNoLock(pointer, out _); case Il2CppTypeEnum.IL2CPP_TYPE_I4: - if (LibCpp2IlMain.MetadataVersion < 29) + if (metadata.MetadataVersion < 29) return metadata.ReadInt32(); return metadata.ReadUnityCompressedIntAtRawAddr(pointer, false, out _); case Il2CppTypeEnum.IL2CPP_TYPE_U8: @@ -214,7 +219,7 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb case Il2CppTypeEnum.IL2CPP_TYPE_STRING: int len; var lenLen = 4; - if (LibCpp2IlMain.MetadataVersion < 29) + if (metadata.MetadataVersion < 29) len = metadata.ReadInt32(); else len = metadata.ReadUnityCompressedIntAtRawAddr(pointer, false, out lenLen); @@ -233,101 +238,109 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb public static Il2CppTypeReflectionData WrapType(Il2CppTypeDefinition what) { - return new() + return new(what.OwningContext) { - baseType = what, genericParams = [], isGenericType = false, isType = true, + baseType = what, genericParams = [], isGenericType = false, isType = true }; } public static Il2CppTypeReflectionData GetTypeReflectionData(Il2CppType forWhat) { - if (LibCpp2IlMain.Binary == null || LibCpp2IlMain.TheMetadata == null) - throw new Exception("Can't get type reflection data when not initialized. How did you even get the type?"); + var context = forWhat.OwningContext; + var binary = context.Binary; + var metadata = context.Metadata; + var reflectionCache = context.ReflectionCache; switch (forWhat.Type) { case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT: - return WrapType(LibCpp2IlReflection.GetType("Object", "System")!); + return WrapType(reflectionCache.GetType("Object", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_VOID: - return WrapType(LibCpp2IlReflection.GetType("Void", "System")!); + return WrapType(reflectionCache.GetType("Void", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: - return WrapType(LibCpp2IlReflection.GetType("Boolean", "System")!); + return WrapType(reflectionCache.GetType("Boolean", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: - return WrapType(LibCpp2IlReflection.GetType("Char", "System")!); + return WrapType(reflectionCache.GetType("Char", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_I1: - return WrapType(LibCpp2IlReflection.GetType("SByte", "System")!); + return WrapType(reflectionCache.GetType("SByte", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_U1: - return WrapType(LibCpp2IlReflection.GetType("Byte", "System")!); + return WrapType(reflectionCache.GetType("Byte", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_I2: - return WrapType(LibCpp2IlReflection.GetType("Int16", "System")!); + return WrapType(reflectionCache.GetType("Int16", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_U2: - return WrapType(LibCpp2IlReflection.GetType("UInt16", "System")!); + return WrapType(reflectionCache.GetType("UInt16", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_I4: - return WrapType(LibCpp2IlReflection.GetType("Int32", "System")!); + return WrapType(reflectionCache.GetType("Int32", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_U4: - return WrapType(LibCpp2IlReflection.GetType("UInt32", "System")!); + return WrapType(reflectionCache.GetType("UInt32", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_I: - return WrapType(LibCpp2IlReflection.GetType("IntPtr", "System")!); + return WrapType(reflectionCache.GetType("IntPtr", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_U: - return WrapType(LibCpp2IlReflection.GetType("UIntPtr", "System")!); + return WrapType(reflectionCache.GetType("UIntPtr", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_I8: - return WrapType(LibCpp2IlReflection.GetType("Int64", "System")!); + return WrapType(reflectionCache.GetType("Int64", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_U8: - return WrapType(LibCpp2IlReflection.GetType("UInt64", "System")!); + return WrapType(reflectionCache.GetType("UInt64", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_R4: - return WrapType(LibCpp2IlReflection.GetType("Single", "System")!); + return WrapType(reflectionCache.GetType("Single", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_R8: - return WrapType(LibCpp2IlReflection.GetType("Double", "System")!); + return WrapType(reflectionCache.GetType("Double", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_STRING: - return WrapType(LibCpp2IlReflection.GetType("String", "System")!); + return WrapType(reflectionCache.GetType("String", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF: - return WrapType(LibCpp2IlReflection.GetType("TypedReference", "System")!); + return WrapType(reflectionCache.GetType("TypedReference", "System")!); case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: //"normal" type - return new Il2CppTypeReflectionData + return new(context) { - baseType = forWhat.AsClass(), genericParams = [], isType = true, isGenericType = false, + baseType = forWhat.AsClass(), + genericParams = [], + isType = true, + isGenericType = false }; case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { //Generic type - var genericClass = LibCpp2IlMain.Binary.ReadReadableAtVirtualAddress(forWhat.Data.GenericClass); + var genericClass = binary.ReadReadableAtVirtualAddress(forWhat.Data.GenericClass); //CHANGED IN v27: typeDefinitionIndex is a ptr to the type in the file. var typeDefinition = genericClass.TypeDefinition; - var genericInst = genericClass.Context.ClassInst; + var genericInst = genericClass.Context.ClassInst!; var genericParams = genericInst.Types .Select(GetTypeReflectionData) //Recursive call here .ToList(); - return new() + return new(context) { - baseType = typeDefinition, genericParams = genericParams.ToArray(), isType = true, isGenericType = true, + baseType = typeDefinition, + genericParams = genericParams.ToArray(), + isType = true, + isGenericType = true }; } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { - var param = LibCpp2IlMain.TheMetadata.GetGenericParameterFromIndex(forWhat.Data.GenericParameterIndex); - var genericName = LibCpp2IlMain.TheMetadata.GetStringFromIndex(param.nameIndex); + var param = metadata.GetGenericParameterFromIndex(forWhat.Data.GenericParameterIndex); + var genericName = metadata.GetStringFromIndex(param.nameIndex); - return new() + return new(context) { baseType = null, genericParams = [], isType = false, isGenericType = false, variableGenericParamName = genericName, - variableGenericParamIndex = forWhat.Data.GenericParameterIndex, + variableGenericParamIndex = forWhat.Data.GenericParameterIndex }; } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { - var oriType = LibCpp2IlMain.Binary.GetIl2CppTypeFromPointer(forWhat.Data.Type); - return new() + var oriType = binary.GetIl2CppTypeFromPointer(forWhat.Data.Type); + return new(context) { baseType = null, arrayType = GetTypeReflectionData(oriType), @@ -340,9 +353,9 @@ public static Il2CppTypeReflectionData GetTypeReflectionData(Il2CppType forWhat) } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { - var arrayType = LibCpp2IlMain.Binary.ReadReadableAtVirtualAddress(forWhat.Data.Array); + var arrayType = binary.ReadReadableAtVirtualAddress(forWhat.Data.Array); var oriType = arrayType.ElementType; - return new() + return new(context) { baseType = null, arrayType = GetTypeReflectionData(oriType), @@ -355,7 +368,7 @@ public static Il2CppTypeReflectionData GetTypeReflectionData(Il2CppType forWhat) } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { - var oriType = LibCpp2IlMain.Binary.GetIl2CppTypeFromPointer(forWhat.Data.Type); + var oriType = binary.GetIl2CppTypeFromPointer(forWhat.Data.Type); var ret = GetTypeReflectionData(oriType); ret.isPointer = true; return ret; @@ -373,9 +386,9 @@ internal static IEnumerable Range(int start, int count) } } - internal static void PopulateDeclaringAssemblyCache() + internal static void PopulateDeclaringAssemblyCache(Il2CppMetadata metadata) { - foreach (var assembly in LibCpp2IlMain.TheMetadata!.imageDefinitions) + foreach (var assembly in metadata.imageDefinitions) { foreach (var il2CppTypeDefinition in assembly.Types!) { diff --git a/LibCpp2IL/MachO/MachODynamicLinkerCommand.cs b/LibCpp2IL/MachO/MachODynamicLinkerCommand.cs index f156aa2b2..ab3768fc4 100644 --- a/LibCpp2IL/MachO/MachODynamicLinkerCommand.cs +++ b/LibCpp2IL/MachO/MachODynamicLinkerCommand.cs @@ -1,5 +1,3 @@ -using System; - namespace LibCpp2IL.MachO; public class MachODynamicLinkerCommand : ReadableClass diff --git a/LibCpp2IL/MachO/MachOLoadCommand.cs b/LibCpp2IL/MachO/MachOLoadCommand.cs index 8fa70333b..b5517c97f 100644 --- a/LibCpp2IL/MachO/MachOLoadCommand.cs +++ b/LibCpp2IL/MachO/MachOLoadCommand.cs @@ -1,4 +1,3 @@ -using System; using System.Text; namespace LibCpp2IL.MachO; diff --git a/LibCpp2IL/MachO/MachOSegmentCommand.cs b/LibCpp2IL/MachO/MachOSegmentCommand.cs index c5b4fccee..c77743c85 100644 --- a/LibCpp2IL/MachO/MachOSegmentCommand.cs +++ b/LibCpp2IL/MachO/MachOSegmentCommand.cs @@ -1,4 +1,3 @@ -using System; using System.Text; namespace LibCpp2IL.MachO; diff --git a/LibCpp2IL/MachO/MachOSymtabCommand.cs b/LibCpp2IL/MachO/MachOSymtabCommand.cs index 2d122f6f7..ccc25b984 100644 --- a/LibCpp2IL/MachO/MachOSymtabCommand.cs +++ b/LibCpp2IL/MachO/MachOSymtabCommand.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - namespace LibCpp2IL.MachO; public class MachOSymtabCommand : ReadableClass diff --git a/LibCpp2IL/Metadata/Il2CppAssemblyDefinition.cs b/LibCpp2IL/Metadata/Il2CppAssemblyDefinition.cs index e09df4d47..ccb358142 100644 --- a/LibCpp2IL/Metadata/Il2CppAssemblyDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppAssemblyDefinition.cs @@ -1,4 +1,3 @@ -using System; using System.Linq; namespace LibCpp2IL.Metadata; @@ -13,12 +12,12 @@ public class Il2CppAssemblyDefinition : ReadableClass public int ReferencedAssemblyCount; public Il2CppAssemblyNameDefinition AssemblyName = null!; //Late-read - public Il2CppImageDefinition Image => LibCpp2IlMain.TheMetadata!.imageDefinitions[ImageIndex]; + public Il2CppImageDefinition Image => OwningContext.Metadata.imageDefinitions[ImageIndex]; public Il2CppAssemblyDefinition[] ReferencedAssemblies => ReferencedAssemblyStart < 0 ? [] - : LibCpp2IlMain.TheMetadata!.referencedAssemblies.SubArray(ReferencedAssemblyStart, ReferencedAssemblyCount) - .Select(idx => LibCpp2IlMain.TheMetadata.AssemblyDefinitions[idx]) + : OwningContext.Metadata.referencedAssemblies.SubArray(ReferencedAssemblyStart, ReferencedAssemblyCount) + .Select(idx => OwningContext.Metadata.AssemblyDefinitions[idx]) .ToArray(); public override string ToString() => AssemblyName.ToString(); diff --git a/LibCpp2IL/Metadata/Il2CppAssemblyNameDefinition.cs b/LibCpp2IL/Metadata/Il2CppAssemblyNameDefinition.cs index 8d613a3b0..3b97e1680 100644 --- a/LibCpp2IL/Metadata/Il2CppAssemblyNameDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppAssemblyNameDefinition.cs @@ -23,8 +23,8 @@ public class Il2CppAssemblyNameDefinition : ReadableClass public int revision; public ulong publicKeyToken; - public string Name => LibCpp2IlMain.TheMetadata!.GetStringFromIndex(nameIndex); - public string Culture => LibCpp2IlMain.TheMetadata!.GetStringFromIndex(cultureIndex); + public string Name => OwningContext.Metadata.GetStringFromIndex(nameIndex); + public string Culture => OwningContext.Metadata.GetStringFromIndex(cultureIndex); public byte[]? PublicKey { @@ -40,12 +40,12 @@ public byte[]? PublicKey // 2019.4.15 until 2020 (24.4) // 2020.1.11 until 2020.2.0 (24.4) // 2020.2.0b7 and later (27+) - var result = LibCpp2IlMain.TheMetadata!.GetByteArrayFromIndex(publicKeyIndex); + var result = OwningContext.Metadata.GetByteArrayFromIndex(publicKeyIndex); return result.Length == 0 ? null : result; } else { - var str = LibCpp2IlMain.TheMetadata!.GetStringFromIndex(publicKeyIndex); + var str = OwningContext.Metadata.GetStringFromIndex(publicKeyIndex); if (str is "NULL") return null; // No public key @@ -141,7 +141,7 @@ public byte[]? PublicKeyToken } } - public string HashValue => LibCpp2IlMain.MetadataVersion > 24.3f ? "NULL" : LibCpp2IlMain.TheMetadata!.GetStringFromIndex(hashValueIndex); + public string HashValue => MetadataVersion > 24.3f ? "NULL" : OwningContext.Metadata.GetStringFromIndex(hashValueIndex); public override string ToString() { diff --git a/LibCpp2IL/Metadata/Il2CppEventDefinition.cs b/LibCpp2IL/Metadata/Il2CppEventDefinition.cs index 598991b77..a3648e40f 100644 --- a/LibCpp2IL/Metadata/Il2CppEventDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppEventDefinition.cs @@ -23,9 +23,7 @@ public Il2CppTypeDefinition? DeclaringType get { if (_type != null) return _type; - if (LibCpp2IlMain.TheMetadata == null) return null; - - _type = LibCpp2IlMain.TheMetadata.typeDefs.FirstOrDefault(t => t.Events!.Contains(this)); + _type = OwningContext.Metadata.typeDefs.FirstOrDefault(t => t.Events!.Contains(this)); return _type; } internal set => _type = value; @@ -33,17 +31,17 @@ public Il2CppTypeDefinition? DeclaringType public string? Name { get; private set; } - public Il2CppType? RawType => LibCpp2IlMain.Binary?.GetType(typeIndex); + public Il2CppType? RawType => OwningContext.Binary.GetType(typeIndex); - public Il2CppTypeReflectionData? EventType => LibCpp2IlMain.Binary == null ? null : LibCpp2ILUtils.GetTypeReflectionData(RawType!); + public Il2CppTypeReflectionData? EventType => LibCpp2ILUtils.GetTypeReflectionData(RawType!); public EventAttributes EventAttributes => (EventAttributes)RawType!.Attrs; - public Il2CppMethodDefinition? Adder => LibCpp2IlMain.TheMetadata == null || add.IsNull || DeclaringType == null ? null : LibCpp2IlMain.TheMetadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + add); + public Il2CppMethodDefinition? Adder => add.IsNull || DeclaringType == null ? null : OwningContext.Metadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + add); - public Il2CppMethodDefinition? Remover => LibCpp2IlMain.TheMetadata == null || remove.IsNull || DeclaringType == null ? null : LibCpp2IlMain.TheMetadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + remove); + public Il2CppMethodDefinition? Remover => remove.IsNull || DeclaringType == null ? null : OwningContext.Metadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + remove); - public Il2CppMethodDefinition? Invoker => LibCpp2IlMain.TheMetadata == null || raise.IsNull || DeclaringType == null ? null : LibCpp2IlMain.TheMetadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + raise); + public Il2CppMethodDefinition? Invoker => raise.IsNull || DeclaringType == null ? null : OwningContext.Metadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + raise); public bool IsStatic { diff --git a/LibCpp2IL/Metadata/Il2CppFieldDefaultValue.cs b/LibCpp2IL/Metadata/Il2CppFieldDefaultValue.cs index 53a19ca09..502e1d884 100644 --- a/LibCpp2IL/Metadata/Il2CppFieldDefaultValue.cs +++ b/LibCpp2IL/Metadata/Il2CppFieldDefaultValue.cs @@ -8,7 +8,7 @@ public class Il2CppFieldDefaultValue : ReadableClass public Il2CppVariableWidthIndex typeIndex; public Il2CppVariableWidthIndex dataIndex; - public object? Value => dataIndex.IsNull ? null : LibCpp2ILUtils.GetDefaultValue(dataIndex, typeIndex); + public object? Value => dataIndex.IsNull ? null : LibCpp2ILUtils.GetDefaultValue(dataIndex, typeIndex, OwningContext); public override void Read(ClassReadingBinaryReader reader) { diff --git a/LibCpp2IL/Metadata/Il2CppFieldDefinition.cs b/LibCpp2IL/Metadata/Il2CppFieldDefinition.cs index 4fe06cef6..153cb1a8e 100644 --- a/LibCpp2IL/Metadata/Il2CppFieldDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppFieldDefinition.cs @@ -1,4 +1,3 @@ -using System; using LibCpp2IL.BinaryStructures; using LibCpp2IL.Reflection; @@ -13,20 +12,17 @@ public class Il2CppFieldDefinition : ReadableClass public string? Name { get; private set; } - public Il2CppType? RawFieldType => LibCpp2IlMain.Binary?.GetType(typeIndex); + public Il2CppType? RawFieldType => OwningContext.Binary.GetType(typeIndex); public Il2CppTypeReflectionData? FieldType => RawFieldType == null ? null : LibCpp2ILUtils.GetTypeReflectionData(RawFieldType); - public Il2CppVariableWidthIndex FieldIndex => LibCpp2IlReflection.GetFieldIndexFromField(this); + public Il2CppVariableWidthIndex FieldIndex => OwningContext.ReflectionCache.GetFieldIndexFromField(this); - public Il2CppFieldDefaultValue? DefaultValue => LibCpp2IlMain.TheMetadata?.GetFieldDefaultValue(this); + public Il2CppFieldDefaultValue? DefaultValue => OwningContext.Metadata.GetFieldDefaultValue(this); - public Il2CppTypeDefinition DeclaringType => LibCpp2IlReflection.GetDeclaringTypeFromField(this); + public Il2CppTypeDefinition DeclaringType => OwningContext.ReflectionCache.GetDeclaringTypeFromField(this); public override string? ToString() { - if (LibCpp2IlMain.TheMetadata == null) - return base.ToString(); - return $"Il2CppFieldDefinition[Name={Name}, FieldType={FieldType}]"; } @@ -41,13 +37,13 @@ public byte[] StaticArrayInitialValue return []; var length = int.Parse(FieldType.baseType!.Name.Replace("__StaticArrayInitTypeSize=", "")); - var (dataIndex, _) = LibCpp2IlMain.TheMetadata!.GetFieldDefaultValue(FieldIndex); + var (dataIndex, _) = OwningContext.Metadata.GetFieldDefaultValue(FieldIndex); - var pointer = LibCpp2IlMain.TheMetadata!.GetDefaultValueFromIndex(dataIndex); + var pointer = OwningContext.Metadata.GetDefaultValueFromIndex(dataIndex); if (pointer <= 0) return []; - var results = LibCpp2IlMain.TheMetadata.ReadByteArrayAtRawAddress(pointer, length); + var results = OwningContext.Metadata.ReadByteArrayAtRawAddress(pointer, length); return results; } diff --git a/LibCpp2IL/Metadata/Il2CppFieldRef.cs b/LibCpp2IL/Metadata/Il2CppFieldRef.cs index 2dc3082c3..0b210d1db 100644 --- a/LibCpp2IL/Metadata/Il2CppFieldRef.cs +++ b/LibCpp2IL/Metadata/Il2CppFieldRef.cs @@ -10,11 +10,11 @@ public class Il2CppFieldRef : ReadableClass public Il2CppVariableWidthIndex typeIndex; public Il2CppVariableWidthIndex fieldIndex; // local offset into type fields - public Il2CppType? DeclaringType => LibCpp2IlMain.Binary?.GetType(typeIndex); + public Il2CppType? DeclaringType => OwningContext.Binary.GetType(typeIndex); - public Il2CppTypeDefinition? DeclaringTypeDefinition => LibCpp2IlMain.TheMetadata?.GetTypeDefinitionFromIndex(DeclaringType!.Data.ClassIndex); + public Il2CppTypeDefinition? DeclaringTypeDefinition => OwningContext.Metadata.GetTypeDefinitionFromIndex(DeclaringType!.Data.ClassIndex); - public Il2CppFieldDefinition? FieldDefinition => LibCpp2IlMain.TheMetadata?.GetFieldDefinitionFromIndex(DeclaringTypeDefinition!.FirstFieldIdx + fieldIndex); + public Il2CppFieldDefinition? FieldDefinition => OwningContext.Metadata.GetFieldDefinitionFromIndex(DeclaringTypeDefinition!.FirstFieldIdx + fieldIndex); public override void Read(ClassReadingBinaryReader reader) { diff --git a/LibCpp2IL/Metadata/Il2CppGenericContainer.cs b/LibCpp2IL/Metadata/Il2CppGenericContainer.cs index f4773a64f..1164137f7 100644 --- a/LibCpp2IL/Metadata/Il2CppGenericContainer.cs +++ b/LibCpp2IL/Metadata/Il2CppGenericContainer.cs @@ -27,7 +27,7 @@ public IEnumerable GenericParameters for (var i = 0; i < genericParameterCount; i++) { var index = Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(genericParameterStart.Value + i); //DynWidth: computed, not read, so temp is fine - var p = LibCpp2IlMain.TheMetadata!.GetGenericParameterFromIndex(index); + var p = OwningContext.Metadata.GetGenericParameterFromIndex(index); p.Index = index; Debug.Assert(p.genericParameterIndexInOwner == i); yield return p; @@ -36,10 +36,10 @@ public IEnumerable GenericParameters } //DynWidth: ownerIndex is always int, so making temp is ok - public Il2CppTypeDefinition? TypeOwner => isGenericMethod ? null : LibCpp2IlMain.TheMetadata!.GetTypeDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ownerIndex)); + public Il2CppTypeDefinition? TypeOwner => isGenericMethod ? null : OwningContext.Metadata.GetTypeDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ownerIndex)); //DynWidth: ownerIndex is always int, so making temp is ok - public Il2CppMethodDefinition? MethodOwner => isGenericMethod ? LibCpp2IlMain.TheMetadata!.GetMethodDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ownerIndex)) : null; + public Il2CppMethodDefinition? MethodOwner => isGenericMethod ? OwningContext.Metadata.GetMethodDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ownerIndex)) : null; public Il2CppTypeDefinition? DeclaringType => TypeOwner ?? MethodOwner?.DeclaringType; diff --git a/LibCpp2IL/Metadata/Il2CppGenericParameter.cs b/LibCpp2IL/Metadata/Il2CppGenericParameter.cs index a093e343e..df818f9b4 100644 --- a/LibCpp2IL/Metadata/Il2CppGenericParameter.cs +++ b/LibCpp2IL/Metadata/Il2CppGenericParameter.cs @@ -15,14 +15,14 @@ public class Il2CppGenericParameter : ReadableClass public GenericParameterAttributes Attributes => (GenericParameterAttributes)flags; - public string? Name => LibCpp2IlMain.TheMetadata?.GetStringFromIndex(nameIndex); + public string? Name => OwningContext.Metadata.GetStringFromIndex(nameIndex); public Il2CppType[] ConstraintTypes => constraintsCount == 0 ? [] - : LibCpp2IlMain.TheMetadata!.constraintIndices + : OwningContext.Metadata.constraintIndices .Skip(constraintsStart) .Take(constraintsCount) - .Select(LibCpp2IlMain.Binary!.GetType) + .Select(OwningContext.Binary.GetType) .ToArray(); /// @@ -30,7 +30,7 @@ public class Il2CppGenericParameter : ReadableClass /// public Il2CppVariableWidthIndex Index { get; internal set; } - public Il2CppGenericContainer Owner => LibCpp2IlMain.TheMetadata!.GetGenericContainerFromIndex(ownerIndex); + public Il2CppGenericContainer Owner => OwningContext.Metadata.GetGenericContainerFromIndex(ownerIndex); public Il2CppTypeEnum Type => Owner.isGenericMethod ? Il2CppTypeEnum.IL2CPP_TYPE_MVAR : Il2CppTypeEnum.IL2CPP_TYPE_VAR; diff --git a/LibCpp2IL/Metadata/Il2CppImageDefinition.cs b/LibCpp2IL/Metadata/Il2CppImageDefinition.cs index 02acdb77b..25ab0ee5d 100644 --- a/LibCpp2IL/Metadata/Il2CppImageDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppImageDefinition.cs @@ -19,13 +19,12 @@ public class Il2CppImageDefinition : ReadableClass [Version(Min = 24.1f)] public int customAttributeStart; [Version(Min = 24.1f)] public uint customAttributeCount; - public string? Name => LibCpp2IlMain.TheMetadata == null ? null : LibCpp2IlMain.TheMetadata.GetStringFromIndex(nameIndex); + public string? Name => OwningContext.Metadata.GetStringFromIndex(nameIndex); - public Il2CppTypeDefinition[]? Types => LibCpp2IlMain.TheMetadata == null ? null - : Enumerable + public Il2CppTypeDefinition[]? Types => Enumerable .Range(firstTypeIndex.Value, (int)typeCount) .Select(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage) // DynWidth: using Enumerable.Range, not read from file, so making temp is ok - .Select(LibCpp2IlMain.TheMetadata.GetTypeDefinitionFromIndex) + .Select(OwningContext.Metadata.GetTypeDefinitionFromIndex) .ToArray(); public override string ToString() diff --git a/LibCpp2IL/Metadata/Il2CppInterfaceOffset.cs b/LibCpp2IL/Metadata/Il2CppInterfaceOffset.cs index 7a5a3c86a..8503f54ec 100644 --- a/LibCpp2IL/Metadata/Il2CppInterfaceOffset.cs +++ b/LibCpp2IL/Metadata/Il2CppInterfaceOffset.cs @@ -8,7 +8,7 @@ public class Il2CppInterfaceOffset : ReadableClass public Il2CppVariableWidthIndex typeIndex; public int offset; - public Il2CppTypeReflectionData Type => LibCpp2ILUtils.GetTypeReflectionData(LibCpp2IlMain.Binary!.GetType(typeIndex)); + public Il2CppTypeReflectionData Type => LibCpp2ILUtils.GetTypeReflectionData(OwningContext.Binary.GetType(typeIndex)); public override string ToString() { diff --git a/LibCpp2IL/Metadata/Il2CppMetadata.cs b/LibCpp2IL/Metadata/Il2CppMetadata.cs index 2830e42b4..76796f90f 100644 --- a/LibCpp2IL/Metadata/Il2CppMetadata.cs +++ b/LibCpp2IL/Metadata/Il2CppMetadata.cs @@ -55,6 +55,11 @@ public class Il2CppMetadata : ClassReadingBinaryReader public int[] referencedAssemblies; + /// + /// Set by after construction. + /// + public LibCpp2IlContext OwningContext { get; internal set; } + private readonly Dictionary, Il2CppFieldDefaultValue> _fieldDefaultValueLookup = new(); private readonly Dictionary _fieldDefaultLookupNew = new(); @@ -429,6 +434,7 @@ private Il2CppMetadata(MemoryStream stream, UnityVersion unityVersion, float met } LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)"); + _hasFinishedInitialRead = true; } finally @@ -451,6 +457,40 @@ private Il2CppMetadata(MemoryStream stream, UnityVersion unityVersion, float met } #pragma warning restore 8618 + internal void SetOwningContext(LibCpp2IlContext context) + { + OwningContext = context; + + SetOwningContext(imageDefinitions, context); + SetOwningContext(AssemblyDefinitions, context); + SetOwningContext(typeDefs, context); + SetOwningContext(interfaceOffsets, context); + SetOwningContext(methodDefs, context); + SetOwningContext(parameterDefs, context); + SetOwningContext(fieldDefs, context); + SetOwningContext(fieldDefaultValues, context); + SetOwningContext(parameterDefaultValues, context); + SetOwningContext(propertyDefs, context); + SetOwningContext(eventDefs, context); + SetOwningContext(genericContainers, context); + SetOwningContext(genericParameters, context); + SetOwningContext(stringLiterals, context); + SetOwningContext(fieldRefs, context); + + if (RgctxDefinitions != null) + SetOwningContext(RgctxDefinitions, context); + + // Set on sub-objects not directly in arrays + foreach (var asm in AssemblyDefinitions) + asm.AssemblyName.OwningContext = context; + } + + private static void SetOwningContext(T[] items, LibCpp2IlContext context) where T : ReadableClass + { + foreach (var item in items) + item.OwningContext = context; + } + private T[] ReadMetadataClassArray(Il2CppGlobalMetadataSectionHeader section) where T : ReadableClass, new() { //First things first, we're going to be moving the position around a lot, so we need to lock. @@ -551,7 +591,7 @@ private uint GetDecodedMethodIndex(uint index) public (Il2CppVariableWidthIndex ptr, Il2CppVariableWidthIndex type) GetFieldDefaultValue(Il2CppVariableWidthIndex fieldIdx) { var fieldDef = GetFieldDefinitionFromIndex(fieldIdx); - var fieldType = LibCpp2IlMain.Binary!.GetType(fieldDef.typeIndex); + var fieldType = OwningContext.Binary.GetType(fieldDef.typeIndex); if ((fieldType.Attrs & (int)FieldAttributes.HasFieldRVA) != 0) { var fieldDefault = GetFieldDefaultValueFromIndex(fieldIdx); diff --git a/LibCpp2IL/Metadata/Il2CppMethodDefinition.cs b/LibCpp2IL/Metadata/Il2CppMethodDefinition.cs index aa059fb1d..d7bde0c8e 100644 --- a/LibCpp2IL/Metadata/Il2CppMethodDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppMethodDefinition.cs @@ -1,5 +1,3 @@ -using System; -using System.Diagnostics; using System.Linq; using System.Reflection; using LibCpp2IL.BinaryStructures; @@ -32,17 +30,17 @@ public class Il2CppMethodDefinition : ReadableClass public bool IsStatic => (Attributes & MethodAttributes.Static) != 0; - public Il2CppVariableWidthIndex MethodIndex => LibCpp2IlReflection.GetMethodIndexFromMethod(this); + public Il2CppVariableWidthIndex MethodIndex => OwningContext.ReflectionCache.GetMethodIndexFromMethod(this); public string? Name { get; private set; } public string? GlobalKey => DeclaringType == null ? null : DeclaringType.Name + "." + Name + "()"; - public Il2CppType? RawReturnType => LibCpp2IlMain.Binary?.GetType(returnTypeIdx); + public Il2CppType? RawReturnType => OwningContext.Binary.GetType(returnTypeIdx); - public Il2CppTypeReflectionData? ReturnType => LibCpp2IlMain.Binary == null ? null : LibCpp2ILUtils.GetTypeReflectionData(LibCpp2IlMain.Binary.GetType(returnTypeIdx)); + public Il2CppTypeReflectionData? ReturnType => LibCpp2ILUtils.GetTypeReflectionData(OwningContext.Binary.GetType(returnTypeIdx)); - public Il2CppTypeDefinition? DeclaringType => LibCpp2IlMain.TheMetadata == null ? null : LibCpp2IlMain.TheMetadata.GetTypeDefinitionFromIndex(declaringTypeIdx); + public Il2CppTypeDefinition? DeclaringType => OwningContext.Metadata.GetTypeDefinitionFromIndex(declaringTypeIdx); private ulong? _methodPointer = null; @@ -52,32 +50,32 @@ public ulong MethodPointer { if (!_methodPointer.HasValue) { - if (LibCpp2IlMain.Binary == null || LibCpp2IlMain.TheMetadata == null || DeclaringType == null) + if (DeclaringType == null) { - LibLogger.WarnNewline($"Couldn't get method pointer for {Name}. Binary is {LibCpp2IlMain.Binary}, Meta is {LibCpp2IlMain.TheMetadata}, DeclaringType is {DeclaringType}"); + LibLogger.WarnNewline($"Couldn't get method pointer for {Name}. DeclaringType is null"); return 0; } var asmIdx = 0; //Not needed pre-24.2 - if (LibCpp2IlMain.MetadataVersion >= 27) + if (MetadataVersion >= 27) { - asmIdx = LibCpp2IlMain.Binary.GetCodegenModuleIndexByName(DeclaringType!.DeclaringAssembly!.Name!); + asmIdx = OwningContext.Binary.GetCodegenModuleIndexByName(DeclaringType!.DeclaringAssembly!.Name!); } - else if (LibCpp2IlMain.MetadataVersion >= 24.2f) + else if (MetadataVersion >= 24.2f) { asmIdx = DeclaringType!.DeclaringAssembly!.assemblyIndex; } - _methodPointer = LibCpp2IlMain.Binary.GetMethodPointer(methodIndex, MethodIndex, asmIdx, token); + _methodPointer = OwningContext.Binary.GetMethodPointer(methodIndex, MethodIndex, asmIdx, token); } return _methodPointer.Value; } } - public long MethodOffsetInFile => MethodPointer == 0 || LibCpp2IlMain.Binary == null ? 0 : LibCpp2IlMain.Binary.TryMapVirtualAddressToRaw(MethodPointer, out var ret) ? ret : 0; + public long MethodOffsetInFile => MethodPointer == 0 ? 0 : OwningContext.Binary.TryMapVirtualAddressToRaw(MethodPointer, out var ret) ? ret : 0; - public ulong Rva => MethodPointer == 0 || LibCpp2IlMain.Binary == null ? 0 : LibCpp2IlMain.Binary.GetRva(MethodPointer); + public ulong Rva => MethodPointer == 0 ? 0 : OwningContext.Binary.GetRva(MethodPointer); public string? HumanReadableSignature => ReturnType == null || Parameters == null || Name == null ? null : $"{ReturnType} {Name}({string.Join(", ", Parameters.AsEnumerable())})"; @@ -85,9 +83,6 @@ public Il2CppParameterDefinition[]? InternalParameterData { get { - if (LibCpp2IlMain.TheMetadata == null || LibCpp2IlMain.Binary == null) - return null; - if (parameterStart.IsNull || parameterCount == 0) return []; @@ -95,7 +90,7 @@ public Il2CppParameterDefinition[]? InternalParameterData for (var i = 0; i < parameterCount; i++) { - ret[i] = LibCpp2IlMain.TheMetadata.GetParameterDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(parameterStart.Value + i)); + ret[i] = OwningContext.Metadata.GetParameterDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(parameterStart.Value + i)); } return ret; @@ -104,7 +99,7 @@ public Il2CppParameterDefinition[]? InternalParameterData public Il2CppType[]? InternalParameterTypes => InternalParameterData == null ? null - : InternalParameterData.Select(paramDef => LibCpp2IlMain.Binary!.GetType(paramDef.typeIndex)) + : InternalParameterData.Select(paramDef => OwningContext.Binary.GetType(paramDef.typeIndex)) .ToArray(); private Il2CppParameterReflectionData[]? _cachedParameters; @@ -118,18 +113,18 @@ public Il2CppParameterReflectionData[]? Parameters _cachedParameters = InternalParameterData .Select((paramDef, idx) => { - var paramType = LibCpp2IlMain.Binary!.GetType(paramDef.typeIndex); + var paramType = OwningContext.Binary.GetType(paramDef.typeIndex); var paramFlags = (ParameterAttributes)paramType.Attrs; var paramDefaultData = (paramFlags & ParameterAttributes.HasDefault) != 0 - ? LibCpp2IlMain.TheMetadata!.GetParameterDefaultValueFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(parameterStart.Value + idx)) //DynamicWidth: value is computed so temp usage is ok + ? OwningContext.Metadata.GetParameterDefaultValueFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(parameterStart.Value + idx)) //DynamicWidth: value is computed so temp usage is ok : null; return new Il2CppParameterReflectionData { Type = LibCpp2ILUtils.GetTypeReflectionData(paramType)!, - ParameterName = LibCpp2IlMain.TheMetadata!.GetStringFromIndex(paramDef.nameIndex), + ParameterName = OwningContext.Metadata.GetStringFromIndex(paramDef.nameIndex), Attributes = paramFlags, RawType = paramType, - DefaultValue = paramDefaultData == null ? null : LibCpp2ILUtils.GetDefaultValue(paramDefaultData.dataIndex, paramDefaultData.typeIndex), + DefaultValue = paramDefaultData == null ? null : LibCpp2ILUtils.GetDefaultValue(paramDefaultData.dataIndex, paramDefaultData.typeIndex, OwningContext), ParameterIndex = idx, }; }).ToArray(); @@ -139,7 +134,7 @@ public Il2CppParameterReflectionData[]? Parameters } } - public Il2CppGenericContainer? GenericContainer => genericContainerIndex.IsNull ? null : LibCpp2IlMain.TheMetadata?.GetGenericContainerFromIndex(genericContainerIndex); + public Il2CppGenericContainer? GenericContainer => genericContainerIndex.IsNull ? null : OwningContext.Metadata.GetGenericContainerFromIndex(genericContainerIndex); public bool IsUnmanagedCallersOnly => (iflags & 0xF000) != 0; @@ -147,9 +142,6 @@ public Il2CppParameterReflectionData[]? Parameters public override string? ToString() { - if (LibCpp2IlMain.TheMetadata == null) - return base.ToString(); - return $"Il2CppMethodDefinition[Name='{Name}', ReturnType={ReturnType}, DeclaringType={DeclaringType}]"; } diff --git a/LibCpp2IL/Metadata/Il2CppParameterDefaultValue.cs b/LibCpp2IL/Metadata/Il2CppParameterDefaultValue.cs index f03063a44..9af8b7083 100644 --- a/LibCpp2IL/Metadata/Il2CppParameterDefaultValue.cs +++ b/LibCpp2IL/Metadata/Il2CppParameterDefaultValue.cs @@ -8,7 +8,7 @@ public class Il2CppParameterDefaultValue : ReadableClass public Il2CppVariableWidthIndex typeIndex; public Il2CppVariableWidthIndex dataIndex; - public object? ContainedDefaultValue => LibCpp2ILUtils.GetDefaultValue(dataIndex, typeIndex); + public object? ContainedDefaultValue => LibCpp2ILUtils.GetDefaultValue(dataIndex, typeIndex, OwningContext); public override void Read(ClassReadingBinaryReader reader) { diff --git a/LibCpp2IL/Metadata/Il2CppParameterDefinition.cs b/LibCpp2IL/Metadata/Il2CppParameterDefinition.cs index e48ffee92..a0b69f671 100644 --- a/LibCpp2IL/Metadata/Il2CppParameterDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppParameterDefinition.cs @@ -11,7 +11,7 @@ public class Il2CppParameterDefinition : ReadableClass, IIl2CppTokenProvider public uint Token => token; - public Il2CppType? RawType => LibCpp2IlMain.Binary?.GetType(typeIndex); + public Il2CppType? RawType => OwningContext.Binary.GetType(typeIndex); public string? Name { get; private set; } diff --git a/LibCpp2IL/Metadata/Il2CppPropertyDefinition.cs b/LibCpp2IL/Metadata/Il2CppPropertyDefinition.cs index 2d1b598d4..b44790516 100644 --- a/LibCpp2IL/Metadata/Il2CppPropertyDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppPropertyDefinition.cs @@ -16,7 +16,7 @@ public class Il2CppPropertyDefinition : ReadableClass, IIl2CppTokenProvider [NonSerialized] private Il2CppTypeDefinition? _type; - public int PropertyIndex => LibCpp2IlReflection.GetPropertyIndexFromProperty(this); + public int PropertyIndex => OwningContext.ReflectionCache.GetPropertyIndexFromProperty(this); public Il2CppTypeDefinition? DeclaringType { @@ -25,9 +25,7 @@ public Il2CppTypeDefinition? DeclaringType if (_type != null) return _type; - if (LibCpp2IlMain.TheMetadata == null) return null; - - _type = LibCpp2IlMain.TheMetadata.typeDefs.FirstOrDefault(t => t.Properties!.Contains(this)); + _type = OwningContext.Metadata.typeDefs.FirstOrDefault(t => t.Properties!.Contains(this)); return _type; } internal set => _type = value; @@ -35,13 +33,13 @@ public Il2CppTypeDefinition? DeclaringType public string? Name { get; private set; } - public Il2CppMethodDefinition? Getter => LibCpp2IlMain.TheMetadata == null || get.IsNull || DeclaringType == null ? null : LibCpp2IlMain.TheMetadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + get); + public Il2CppMethodDefinition? Getter => get.IsNull || DeclaringType == null ? null : OwningContext.Metadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + get); - public Il2CppMethodDefinition? Setter => LibCpp2IlMain.TheMetadata == null || set.IsNull || DeclaringType == null ? null : LibCpp2IlMain.TheMetadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + set); + public Il2CppMethodDefinition? Setter => set.IsNull || DeclaringType == null ? null : OwningContext.Metadata.GetMethodDefinitionFromIndex(DeclaringType.FirstMethodIdx + set); - public Il2CppTypeReflectionData? PropertyType => LibCpp2IlMain.TheMetadata == null ? null : Getter == null ? Setter!.Parameters![0].Type : Getter!.ReturnType; + public Il2CppTypeReflectionData? PropertyType => Getter == null ? Setter!.Parameters![0].Type : Getter!.ReturnType; - public Il2CppType? RawPropertyType => LibCpp2IlMain.TheMetadata == null ? null : Getter == null ? Setter!.Parameters![0].RawType : Getter!.RawReturnType; + public Il2CppType? RawPropertyType => Getter == null ? Setter!.Parameters![0].RawType : Getter!.RawReturnType; public bool IsStatic => Getter == null ? Setter!.IsStatic : Getter!.IsStatic; public uint Token => token; diff --git a/LibCpp2IL/Metadata/Il2CppTypeDefinition.cs b/LibCpp2IL/Metadata/Il2CppTypeDefinition.cs index c63b128b5..bc18553e7 100644 --- a/LibCpp2IL/Metadata/Il2CppTypeDefinition.cs +++ b/LibCpp2IL/Metadata/Il2CppTypeDefinition.cs @@ -13,12 +13,12 @@ public class Il2CppTypeDefinition : ReadableClass [Version(Max = 24)] public int CustomAttributeIndex; public Il2CppVariableWidthIndex ByvalTypeIndex; - [Version(Max = 24.5f)] //Removed in v27 + [Version(Max = 24.5f)] //Removed in v27 public int ByrefTypeIndex; public Il2CppVariableWidthIndex DeclaringTypeIndex; public Il2CppVariableWidthIndex ParentIndex; - + [Version(Max = 34f)] //Removed in v35 public int ElementTypeIndex; // we can probably remove this one. Only used for enums @@ -78,14 +78,14 @@ public class Il2CppTypeDefinition : ReadableClass public TypeAttributes Attributes => (TypeAttributes)Flags; - public Il2CppType RawType => LibCpp2IlMain.Binary!.GetType(ByvalTypeIndex); + public Il2CppType RawType => OwningContext.Binary.GetType(ByvalTypeIndex); public Il2CppTypeDefinitionSizes RawSizes { get { - var sizePtr = LibCpp2IlMain.Binary!.TypeDefinitionSizePointers[TypeIndex.Value]; - return LibCpp2IlMain.Binary.ReadReadableAtVirtualAddress(sizePtr); + var sizePtr = OwningContext.Binary.TypeDefinitionSizePointers[TypeIndex.Value]; + return OwningContext.Binary.ReadReadableAtVirtualAddress(sizePtr); } } @@ -97,7 +97,7 @@ public Il2CppInterfaceOffset[] InterfaceOffsets { if (InterfaceOffsetsStart.IsNull) return []; - return LibCpp2IlMain.TheMetadata!.GetInterfaceOffsetsFromIndexAndCount(InterfaceOffsetsStart, InterfaceOffsetsCount); + return OwningContext.Metadata.GetInterfaceOffsetsFromIndexAndCount(InterfaceOffsetsStart, InterfaceOffsetsCount); } } @@ -107,11 +107,11 @@ public MetadataUsage?[] VTable { if (VtableStart < 0) return []; - return LibCpp2IlMain.TheMetadata!.VTableMethodIndices.SubArray(VtableStart, VtableCount).Select(v => MetadataUsage.DecodeMetadataUsage(v, 0)).ToArray(); + return OwningContext.Metadata.VTableMethodIndices.SubArray(VtableStart, VtableCount).Select(v => MetadataUsage.DecodeMetadataUsage(v, 0, OwningContext)).ToArray(); } } - public Il2CppVariableWidthIndex TypeIndex => LibCpp2IlReflection.GetTypeIndexFromType(this); + public Il2CppVariableWidthIndex TypeIndex => OwningContext.ReflectionCache.GetTypeIndexFromType(this); public bool IsAbstract => ((TypeAttributes)Flags & TypeAttributes.Abstract) != 0; @@ -125,9 +125,7 @@ public Il2CppImageDefinition? DeclaringAssembly { if (_cachedDeclaringAssembly == null) { - if (LibCpp2IlMain.TheMetadata == null) return null; - - LibCpp2ILUtils.PopulateDeclaringAssemblyCache(); + LibCpp2ILUtils.PopulateDeclaringAssemblyCache(OwningContext.Metadata); } return _cachedDeclaringAssembly; @@ -135,16 +133,16 @@ public Il2CppImageDefinition? DeclaringAssembly internal set => _cachedDeclaringAssembly = value; } - public Il2CppCodeGenModule? CodeGenModule => LibCpp2IlMain.Binary == null ? null : LibCpp2IlMain.Binary.GetCodegenModuleByName(DeclaringAssembly!.Name!); + public Il2CppCodeGenModule? CodeGenModule => OwningContext.Binary.GetCodegenModuleByName(DeclaringAssembly!.Name!); public Il2CppRGCTXDefinition[] RgctXs { get { - if (LibCpp2IlMain.MetadataVersion < 24.2f) + if (MetadataVersion < 24.2f) { //No codegen modules here. - return LibCpp2IlMain.TheMetadata!.RgctxDefinitions!.Skip(RgctxStartIndex).Take(RgctxCount).ToArray(); + return OwningContext.Metadata.RgctxDefinitions!.Skip(RgctxStartIndex).Take(RgctxCount).ToArray(); } var cgm = CodeGenModule; @@ -157,7 +155,7 @@ public Il2CppRGCTXDefinition[] RgctXs if (rangePair == null) return []; - return LibCpp2IlMain.Binary!.GetRgctxDataForPair(cgm, rangePair); + return OwningContext.Binary.GetRgctxDataForPair(cgm, rangePair); } } @@ -165,12 +163,12 @@ public ulong[] RgctxMethodPointers { get { - var index = LibCpp2IlMain.Binary!.GetCodegenModuleIndexByName(DeclaringAssembly!.Name!); + var index = OwningContext.Binary.GetCodegenModuleIndexByName(DeclaringAssembly!.Name!); if (index < 0) return []; - var pointers = LibCpp2IlMain.Binary!.GetCodegenModuleMethodPointers(index); + var pointers = OwningContext.Binary.GetCodegenModuleMethodPointers(index); return RgctXs .Where(r => r.type == Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_METHOD) @@ -186,7 +184,7 @@ public string? Namespace get { if (_cachedNamespace == null) - _cachedNamespace = LibCpp2IlMain.TheMetadata == null ? null : LibCpp2IlMain.TheMetadata.GetStringFromIndex(NamespaceIndex); + _cachedNamespace = OwningContext.Metadata.GetStringFromIndex(NamespaceIndex); return _cachedNamespace; } @@ -199,7 +197,7 @@ public string? Name get { if (_cachedName == null) - _cachedName = LibCpp2IlMain.TheMetadata == null ? null : LibCpp2IlMain.TheMetadata.GetStringFromIndex(NameIndex); + _cachedName = OwningContext.Metadata.GetStringFromIndex(NameIndex); return _cachedName; } @@ -209,9 +207,6 @@ public string? FullName { get { - if (LibCpp2IlMain.TheMetadata == null) - return null; - if (DeclaringType != null) return $"{DeclaringType.FullName}+{Name}"; @@ -219,34 +214,31 @@ public string? FullName } } - public Il2CppType? RawBaseType => ParentIndex.IsNull ? null : LibCpp2IlMain.Binary!.GetType(ParentIndex); + public Il2CppType? RawBaseType => ParentIndex.IsNull ? null : OwningContext.Binary.GetType(ParentIndex); - public Il2CppTypeReflectionData? BaseType => ParentIndex.IsNull || LibCpp2IlMain.Binary == null ? null : LibCpp2ILUtils.GetTypeReflectionData(LibCpp2IlMain.Binary!.GetType(ParentIndex)); + public Il2CppTypeReflectionData? BaseType => ParentIndex.IsNull ? null : LibCpp2ILUtils.GetTypeReflectionData(OwningContext.Binary.GetType(ParentIndex)); public Il2CppFieldDefinition[]? Fields { get { - if (LibCpp2IlMain.TheMetadata == null) - return null; - if (FirstFieldIdx.IsNull || FieldCount == 0) return []; - return LibCpp2IlMain.TheMetadata.GetFieldDefinitionsFromIndexAndCount(FirstFieldIdx, FieldCount); + return OwningContext.Metadata.GetFieldDefinitionsFromIndexAndCount(FirstFieldIdx, FieldCount); } } public FieldAttributes[]? FieldAttributes => Fields? .Select(f => f.typeIndex) - .Select(idx => LibCpp2IlMain.Binary!.GetType(idx)) + .Select(idx => OwningContext.Binary.GetType(idx)) .Select(t => (FieldAttributes)t.Attrs) .ToArray(); public object?[]? FieldDefaults => Fields? .Select((f, idx) => (f.FieldIndex, FieldAttributes![idx])) - .Select(tuple => (tuple.Item2 & System.Reflection.FieldAttributes.HasDefault) != 0 ? LibCpp2IlMain.TheMetadata!.GetFieldDefaultValueFromIndex(tuple.FieldIndex) : null) - .Select(def => def == null ? null : LibCpp2ILUtils.GetDefaultValue(def.dataIndex, def.typeIndex)) + .Select(tuple => (tuple.Item2 & System.Reflection.FieldAttributes.HasDefault) != 0 ? OwningContext.Metadata.GetFieldDefaultValueFromIndex(tuple.FieldIndex) : null) + .Select(def => def == null ? null : LibCpp2ILUtils.GetDefaultValue(def.dataIndex, def.typeIndex, OwningContext)) .ToArray(); public Il2CppFieldReflectionData[]? FieldInfos @@ -268,7 +260,7 @@ public Il2CppFieldReflectionData[]? FieldInfos attributes![i], defaults![i], i, - LibCpp2IlMain.Binary!.GetFieldOffsetFromIndex(TypeIndex, i, fields[i].FieldIndex, IsValueType, attributes[i].HasFlag(System.Reflection.FieldAttributes.Static)) + OwningContext.Binary.GetFieldOffsetFromIndex(TypeIndex, i, fields[i].FieldIndex, IsValueType, attributes[i].HasFlag(System.Reflection.FieldAttributes.Static)) ); } @@ -280,13 +272,10 @@ public Il2CppMethodDefinition[]? Methods { get { - if (LibCpp2IlMain.TheMetadata == null) - return null; - if (FirstMethodIdx.IsNull || MethodCount == 0) return []; - return LibCpp2IlMain.TheMetadata.GetMethodDefinitionsFromIndexAndCount(FirstMethodIdx, MethodCount); + return OwningContext.Metadata.GetMethodDefinitionsFromIndexAndCount(FirstMethodIdx, MethodCount); } } @@ -294,15 +283,12 @@ public Il2CppPropertyDefinition[]? Properties { get { - if (LibCpp2IlMain.TheMetadata == null) - return null; - if (FirstPropertyId.IsNull || PropertyCount == 0) return []; - var ret = LibCpp2IlMain.TheMetadata.GetPropertyDefinitionsFromIndexAndCount(FirstPropertyId, PropertyCount); - - foreach (var definition in ret) + var ret = OwningContext.Metadata.GetPropertyDefinitionsFromIndexAndCount(FirstPropertyId, PropertyCount); + + foreach (var definition in ret) definition.DeclaringType = this; return ret; @@ -313,46 +299,37 @@ public Il2CppEventDefinition[]? Events { get { - if (LibCpp2IlMain.TheMetadata == null) - return null; - if (FirstEventId.IsNull || EventCount == 0) return []; - var ret = LibCpp2IlMain.TheMetadata.GetEventDefinitionsFromIndexAndCount(FirstEventId, EventCount); - foreach (var def in ret) + var ret = OwningContext.Metadata.GetEventDefinitionsFromIndexAndCount(FirstEventId, EventCount); + foreach (var def in ret) def.DeclaringType = this; - + return ret; } } - public Il2CppTypeDefinition[]? NestedTypes => LibCpp2IlMain.TheMetadata == null - ? null - : LibCpp2IlMain.TheMetadata.GetNestedTypeIndicesFromIndexAndCount(NestedTypesStart, NestedTypeCount) + public Il2CppTypeDefinition[]? NestedTypes => OwningContext.Metadata.GetNestedTypeIndicesFromIndexAndCount(NestedTypesStart, NestedTypeCount) .Select(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage) //DynWidth: nestedTypeIndices is always int, so making temp is ok - .Select(LibCpp2IlMain.TheMetadata.GetTypeDefinitionFromIndex) + .Select(OwningContext.Metadata.GetTypeDefinitionFromIndex) .ToArray(); - public Il2CppType[] RawInterfaces => LibCpp2IlMain.TheMetadata == null || LibCpp2IlMain.Binary == null - ? [] - : LibCpp2IlMain.TheMetadata.GetInterfaceIndicesFromIndexAndCount(InterfacesStart, InterfacesCount) - .Select(LibCpp2IlMain.Binary.GetType) + public Il2CppType[] RawInterfaces => OwningContext.Metadata.GetInterfaceIndicesFromIndexAndCount(InterfacesStart, InterfacesCount) + .Select(OwningContext.Binary.GetType) .ToArray(); - public Il2CppTypeReflectionData[]? Interfaces => LibCpp2IlMain.TheMetadata == null || LibCpp2IlMain.Binary == null - ? null - : RawInterfaces + public Il2CppTypeReflectionData[]? Interfaces => RawInterfaces .Select(LibCpp2ILUtils.GetTypeReflectionData) .ToArray(); - public Il2CppTypeDefinition? DeclaringType => LibCpp2IlMain.TheMetadata == null || LibCpp2IlMain.Binary == null || DeclaringTypeIndex.IsNull ? null : LibCpp2IlMain.Binary.GetType(DeclaringTypeIndex).CoerceToUnderlyingTypeDefinition(); + public Il2CppTypeDefinition? DeclaringType => DeclaringTypeIndex.IsNull ? null : OwningContext.Binary.GetType(DeclaringTypeIndex).CoerceToUnderlyingTypeDefinition(); - public Il2CppTypeDefinition? ElementType => LibCpp2IlMain.TheMetadata == null || LibCpp2IlMain.Binary == null || ElementTypeIndex < 0 - ? null - : LibCpp2IlMain.Binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ElementTypeIndex)).CoerceToUnderlyingTypeDefinition(); //DynWidth: ElementTypeIndex was removed in v35, so it's never dynamic + public Il2CppTypeDefinition? ElementType => ElementTypeIndex < 0 + ? null + : OwningContext.Binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ElementTypeIndex)).CoerceToUnderlyingTypeDefinition(); //DynWidth: ElementTypeIndex was removed in v35, so it's never dynamic - public Il2CppGenericContainer? GenericContainer => GenericContainerIndex.IsNull ? null : LibCpp2IlMain.TheMetadata?.GetGenericContainerFromIndex(GenericContainerIndex); + public Il2CppGenericContainer? GenericContainer => GenericContainerIndex.IsNull ? null : OwningContext.Metadata.GetGenericContainerFromIndex(GenericContainerIndex); public Il2CppType EnumUnderlyingType { @@ -364,17 +341,14 @@ public Il2CppType EnumUnderlyingType if (IsAtLeast(35f)) //v35: ElementTypeIndex removed, enum base type is just normal base type return RawBaseType!; - + //pre-v35: ElementTypeIndex is used for enums to store the underlying type, so we need to get the type from there instead of the parent index (which is just System.Enum) - return LibCpp2IlMain.Binary!.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ElementTypeIndex)); + return OwningContext.Binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(ElementTypeIndex)); } } public override string? ToString() { - if (LibCpp2IlMain.TheMetadata == null) - return base.ToString(); - return $"Il2CppTypeDefinition[namespace='{Namespace}', name='{Name}', parentType={BaseType?.ToString() ?? "null"}, assembly={DeclaringAssembly}]"; } @@ -393,7 +367,7 @@ public override void Read(ClassReadingBinaryReader reader) DeclaringTypeIndex = Il2CppVariableWidthIndex.Read(reader); ParentIndex = Il2CppVariableWidthIndex.Read(reader); - + if(IsLessThan(35f)) ElementTypeIndex = reader.ReadInt32(); diff --git a/LibCpp2IL/MetadataUsage.cs b/LibCpp2IL/MetadataUsage.cs index 87a1fe3a1..c562b81e7 100644 --- a/LibCpp2IL/MetadataUsage.cs +++ b/LibCpp2IL/MetadataUsage.cs @@ -1,11 +1,11 @@ -using System; +using System; using LibCpp2IL.BinaryStructures; using LibCpp2IL.Metadata; using LibCpp2IL.Reflection; namespace LibCpp2IL; -public class MetadataUsage(MetadataUsageType type, ulong offset, uint value) +public class MetadataUsage(MetadataUsageType type, ulong offset, uint value, LibCpp2IlContext context) { public readonly MetadataUsageType Type = type; public readonly ulong Offset = offset; @@ -39,11 +39,11 @@ public class MetadataUsage(MetadataUsageType type, ulong offset, uint value) public bool IsValid => Type switch { - MetadataUsageType.Type or MetadataUsageType.TypeInfo => value < LibCpp2IlMain.Binary!.NumTypes, - MetadataUsageType.MethodDef => value < LibCpp2IlMain.TheMetadata!.MethodDefinitionCount, - MetadataUsageType.FieldInfo => value < LibCpp2IlMain.TheMetadata!.fieldRefs.Length, - MetadataUsageType.StringLiteral => value < LibCpp2IlMain.TheMetadata!.stringLiterals.Length, - MetadataUsageType.MethodRef => value < LibCpp2IlMain.Binary!.AllGenericMethodSpecs.Length, + MetadataUsageType.Type or MetadataUsageType.TypeInfo => value < context.Binary.NumTypes, + MetadataUsageType.MethodDef => value < context.Metadata.MethodDefinitionCount, + MetadataUsageType.FieldInfo => value < context.Metadata.fieldRefs.Length, + MetadataUsageType.StringLiteral => value < context.Metadata.stringLiterals.Length, + MetadataUsageType.MethodRef => value < context.Binary.AllGenericMethodSpecs.Length, _ => false }; @@ -57,13 +57,13 @@ public Il2CppTypeReflectionData AsType() case MetadataUsageType.TypeInfo: try { - _cachedType = LibCpp2IlMain.Binary!.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int) value)); //DynWidth: value is always masked out of 32-bits, ok for temp usage + _cachedType = context.Binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int) value)); //DynWidth: value is always masked out of 32-bits, ok for temp usage _cachedTypeReflectionData = LibCpp2ILUtils.GetTypeReflectionData(_cachedType); _cachedName = _cachedTypeReflectionData?.ToString(); } catch (Exception e) { - throw new Exception($"Failed to convert this metadata usage to a type, but it is of type {Type}, with a value of {value} (0x{value:X}). There are {LibCpp2IlMain.Binary!.NumTypes} types", e); + throw new Exception($"Failed to convert this metadata usage to a type, but it is of type {Type}, with a value of {value} (0x{value:X}). There are {context.Binary.NumTypes} types", e); } break; @@ -82,7 +82,7 @@ public Il2CppMethodDefinition AsMethod() switch (Type) { case MetadataUsageType.MethodDef: - _cachedMethod = LibCpp2IlMain.TheMetadata!.GetMethodDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)value)); //DynWidth: value is always masked out of 32-bits, ok for temp usage + _cachedMethod = context.Metadata.GetMethodDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)value)); //DynWidth: value is always masked out of 32-bits, ok for temp usage _cachedName = _cachedMethod.GlobalKey; break; default: @@ -100,7 +100,7 @@ public Il2CppFieldDefinition AsField() switch (Type) { case MetadataUsageType.FieldInfo: - var fieldRef = LibCpp2IlMain.TheMetadata!.fieldRefs[value]; + var fieldRef = context.Metadata.fieldRefs[value]; _cachedField = fieldRef.FieldDefinition; _cachedName = fieldRef.DeclaringTypeDefinition!.FullName + "." + _cachedField!.Name; break; @@ -119,7 +119,7 @@ public string AsLiteral() switch (Type) { case MetadataUsageType.StringLiteral: - _cachedName = _cachedLiteral = LibCpp2IlMain.TheMetadata!.GetStringLiteralFromIndex(value); + _cachedName = _cachedLiteral = context.Metadata.GetStringLiteralFromIndex(value); break; default: throw new Exception($"Cannot cast metadata usage of kind {Type} to a String Literal"); @@ -136,7 +136,7 @@ public Cpp2IlMethodRef AsGenericMethodRef() switch (Type) { case MetadataUsageType.MethodRef: - var methodSpec = LibCpp2IlMain.Binary!.GetMethodSpec((int)value); + var methodSpec = context.Binary.GetMethodSpec((int)value); _cachedGenericMethod = new Cpp2IlMethodRef(methodSpec); _cachedName = _cachedGenericMethod.ToString(); @@ -154,8 +154,7 @@ public override string ToString() return $"Metadata Usage {{type={Type}, Value={Value}}}"; } - - public static MetadataUsage? DecodeMetadataUsage(ulong encoded, ulong address) + public static MetadataUsage? DecodeMetadataUsage(ulong encoded, ulong address, LibCpp2IlContext context) { var encodedType = encoded & 0xE000_0000; var type = (MetadataUsageType)(encodedType >> 29); @@ -163,17 +162,17 @@ public override string ToString() { var index = (uint)(encoded & 0x1FFF_FFFF); - if (LibCpp2IlMain.MetadataVersion >= 27) + if (context.Metadata.MetadataVersion >= 27) index >>= 1; - if (type is MetadataUsageType.Type or MetadataUsageType.TypeInfo && index > LibCpp2IlMain.Binary!.NumTypes) + if (type is MetadataUsageType.Type or MetadataUsageType.TypeInfo && index > context.Binary.NumTypes) return null; - if (type == MetadataUsageType.MethodDef && index > LibCpp2IlMain.TheMetadata!.MethodDefinitionCount) + if (type == MetadataUsageType.MethodDef && index > context.Metadata.MethodDefinitionCount) return null; - return new MetadataUsage(type, address, index); + return new MetadataUsage(type, address, index, context); } return null; diff --git a/LibCpp2IL/NintendoSwitch/NsoHeader.cs b/LibCpp2IL/NintendoSwitch/NsoHeader.cs index 00c315cbb..121d54220 100644 --- a/LibCpp2IL/NintendoSwitch/NsoHeader.cs +++ b/LibCpp2IL/NintendoSwitch/NsoHeader.cs @@ -1,5 +1,3 @@ -using System; - namespace LibCpp2IL.NintendoSwitch; public class NsoHeader diff --git a/LibCpp2IL/ReadableClass.cs b/LibCpp2IL/ReadableClass.cs index 7af15787a..c043e499b 100644 --- a/LibCpp2IL/ReadableClass.cs +++ b/LibCpp2IL/ReadableClass.cs @@ -4,8 +4,16 @@ namespace LibCpp2IL; public abstract class ReadableClass { + private LibCpp2IlContext? _owningContext; + internal float MetadataVersion { get; set; } - + + internal LibCpp2IlContext OwningContext + { + get => _owningContext ?? throw new InvalidOperationException("OwningContext has not been initialized."); + set => _owningContext = value; + } + protected bool IsAtLeast(float vers) => MetadataVersion >= vers; protected bool IsLessThan(float vers) => MetadataVersion < vers; protected bool IsAtMost(float vers) => MetadataVersion <= vers; diff --git a/LibCpp2IL/Reflection/Il2CppTypeReflectionData.cs b/LibCpp2IL/Reflection/Il2CppTypeReflectionData.cs index 1e741c9c3..e2eda517f 100644 --- a/LibCpp2IL/Reflection/Il2CppTypeReflectionData.cs +++ b/LibCpp2IL/Reflection/Il2CppTypeReflectionData.cs @@ -14,7 +14,7 @@ namespace LibCpp2IL.Reflection; ///
/// Calling on this object will return the canonical representation of this object, with generic params such as System.Collections.Generic.List`1<T> or with concrete types, like in the case of a String's interfaces, System.Collections.Generic.IEnumerable`1<System.Char> ///
-public class Il2CppTypeReflectionData +public class Il2CppTypeReflectionData(LibCpp2IlContext owningContext) { public Il2CppTypeDefinition? baseType; public Il2CppTypeReflectionData[] genericParams; @@ -28,7 +28,7 @@ public class Il2CppTypeReflectionData public bool isPointer; #pragma warning restore 8618 - public Il2CppGenericParameter? GenericParameter => isArray || isType ? null : LibCpp2IlMain.TheMetadata?.GetGenericParameterFromIndex(variableGenericParamIndex); + public Il2CppGenericParameter? GenericParameter => isArray || isType ? null : owningContext.Metadata.GetGenericParameterFromIndex(variableGenericParamIndex); private string GetPtrSuffix() { diff --git a/LibCpp2IL/Reflection/LibCpp2IlReflection.cs b/LibCpp2IL/Reflection/LibCpp2IlReflection.cs index 1baee2201..7ee60d196 100644 --- a/LibCpp2IL/Reflection/LibCpp2IlReflection.cs +++ b/LibCpp2IL/Reflection/LibCpp2IlReflection.cs @@ -1,100 +1,49 @@ using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using LibCpp2IL.BinaryStructures; using LibCpp2IL.Metadata; +#pragma warning disable CS0618 // This static facade intentionally uses LibCpp2IlMain.DefaultContext for backwards compatibility + namespace LibCpp2IL.Reflection; public static class LibCpp2IlReflection { - private static LibCpp2IlReflectionCache? DefaultCache => LibCpp2IlMain.DefaultContext?.ReflectionCache; - - public static Dictionary PrimitiveTypeDefinitions - => DefaultCache?.PrimitiveTypeDefinitions ?? throw new("LibCpp2IlReflection has not been initialized - no DefaultContext is set."); - - internal static void ResetCaches() - { - DefaultCache?.Reset(); - } - - internal static void InitCaches() - { - if (LibCpp2IlMain.DefaultContext == null) - throw new("Cannot initialize reflection caches without a DefaultContext."); - - LibCpp2IlMain.DefaultContext.ReflectionCache.Init(LibCpp2IlMain.DefaultContext); - } - - public static Il2CppTypeDefinition? GetType(string name, string? @namespace = null) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return null; - - return ctx.ReflectionCache.GetType(ctx.Metadata, name, @namespace); - } - - public static Il2CppTypeDefinition? GetTypeByFullName(string fullName) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return null; - - return ctx.ReflectionCache.GetTypeByFullName(ctx.Metadata, fullName); - } - - public static Il2CppTypeDefinition? GetTypeDefinitionByTypeIndex(Il2CppVariableWidthIndex index) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return null; - - return ctx.ReflectionCache.GetTypeDefinitionByTypeIndex(ctx.Binary, index); - } + private static LibCpp2IlReflectionCache DefaultCache => + LibCpp2IlMain.DefaultContext.ReflectionCache; - [SuppressMessage("ReSharper", "InconsistentlySynchronizedField")] - public static Il2CppVariableWidthIndex GetTypeIndexFromType(Il2CppTypeDefinition typeDefinition) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return Il2CppVariableWidthIndex.Null; + public static Dictionary PrimitiveTypeDefinitions => + DefaultCache.PrimitiveTypeDefinitions; - return ctx.ReflectionCache.GetTypeIndexFromType(typeDefinition); - } + internal static void ResetCaches() => + DefaultCache.Reset(); - public static Il2CppVariableWidthIndex GetMethodIndexFromMethod(Il2CppMethodDefinition methodDefinition) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return Il2CppVariableWidthIndex.Null; + internal static void InitCaches() => + DefaultCache.Init(LibCpp2IlMain.DefaultContext); - return ctx.ReflectionCache.GetMethodIndexFromMethod(ctx.Metadata, methodDefinition); - } + public static Il2CppTypeDefinition? GetType(string name, string? @namespace = null) => + DefaultCache.GetType(name, @namespace); - public static Il2CppVariableWidthIndex GetFieldIndexFromField(Il2CppFieldDefinition fieldDefinition) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return Il2CppVariableWidthIndex.Null; + public static Il2CppTypeDefinition? GetTypeByFullName(string fullName) => + DefaultCache.GetTypeByFullName(fullName); - return ctx.ReflectionCache.GetFieldIndexFromField(ctx.Metadata, fieldDefinition); - } + public static Il2CppTypeDefinition? GetTypeDefinitionByTypeIndex(Il2CppVariableWidthIndex index) => + DefaultCache.GetTypeDefinitionByTypeIndex(index); - public static int GetPropertyIndexFromProperty(Il2CppPropertyDefinition propertyDefinition) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return -1; + public static Il2CppVariableWidthIndex GetTypeIndexFromType(Il2CppTypeDefinition typeDefinition) => + DefaultCache.GetTypeIndexFromType(typeDefinition); - return ctx.ReflectionCache.GetPropertyIndexFromProperty(ctx.Metadata, propertyDefinition); - } + public static Il2CppVariableWidthIndex GetMethodIndexFromMethod(Il2CppMethodDefinition methodDefinition) => + DefaultCache.GetMethodIndexFromMethod(methodDefinition); - public static Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppFieldDefinition fieldDefinition) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return null!; + public static Il2CppVariableWidthIndex GetFieldIndexFromField(Il2CppFieldDefinition fieldDefinition) => + DefaultCache.GetFieldIndexFromField(fieldDefinition); - return ctx.ReflectionCache.GetDeclaringTypeFromField(ctx.Metadata, fieldDefinition); - } + public static int GetPropertyIndexFromProperty(Il2CppPropertyDefinition propertyDefinition) => + DefaultCache.GetPropertyIndexFromProperty(propertyDefinition); - public static Il2CppType? GetTypeFromDefinition(Il2CppTypeDefinition definition) - { - var ctx = LibCpp2IlMain.DefaultContext; - if (ctx == null) return null; + public static Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppFieldDefinition fieldDefinition) => + DefaultCache.GetDeclaringTypeFromField(fieldDefinition); - return ctx.ReflectionCache.GetTypeFromDefinition(ctx.Binary, definition); - } + public static Il2CppType? GetTypeFromDefinition(Il2CppTypeDefinition definition) => + DefaultCache.GetTypeFromDefinition(definition); } diff --git a/LibCpp2IL/Reflection/LibCpp2IlReflectionCache.cs b/LibCpp2IL/Reflection/LibCpp2IlReflectionCache.cs index 3783b2ea5..46ded77cf 100644 --- a/LibCpp2IL/Reflection/LibCpp2IlReflectionCache.cs +++ b/LibCpp2IL/Reflection/LibCpp2IlReflectionCache.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -26,8 +27,14 @@ public sealed class LibCpp2IlReflectionCache public Dictionary PrimitiveTypeDefinitions { get; } = new(); private readonly Dictionary, Il2CppType> _il2CppTypeCache = new(); + private LibCpp2IlContext? _context; + + private LibCpp2IlContext Context => + _context ?? throw new InvalidOperationException("LibCpp2IlReflectionCache must be initialized before use"); + public void Reset() { + _context = null; _cachedTypes.Clear(); _cachedTypesByFullName.Clear(); @@ -46,24 +53,22 @@ public void Reset() internal void Init(LibCpp2IlContext context) { Reset(); - - var binary = context.Binary; - var metadata = context.Metadata; + _context = context; for (var e = Il2CppTypeEnum.IL2CPP_TYPE_VOID; e <= Il2CppTypeEnum.IL2CPP_TYPE_STRING; e++) - _primitiveTypeCache[e] = binary.AllTypes.First(t => t.Type == e && t.Byref == 0); + _primitiveTypeCache[e] = context.Binary.AllTypes.First(t => t.Type == e && t.Byref == 0); - _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF] = binary.AllTypes.FirstOrDefault(t => t.Type == Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF && t.Byref == 0) - ?? metadata.typeDefs.First(t => t.DeclaringAssembly?.Name is "mscorlib.dll" && t.Namespace is "System" && t.Name is "TypedReference").RawType; + _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF] = context.Binary.AllTypes.FirstOrDefault(t => t.Type == Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF && t.Byref == 0) + ?? context.Metadata.typeDefs.First(t => t.DeclaringAssembly?.Name is "mscorlib.dll" && t.Namespace is "System" && t.Name is "TypedReference").RawType; for (var e = Il2CppTypeEnum.IL2CPP_TYPE_I; e <= Il2CppTypeEnum.IL2CPP_TYPE_U; e++) - _primitiveTypeCache[e] = binary.AllTypes.First(t => t.Type == e && t.Byref == 0); + _primitiveTypeCache[e] = context.Binary.AllTypes.First(t => t.Type == e && t.Byref == 0); - _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_OBJECT] = binary.AllTypes.First(t => t.Type == Il2CppTypeEnum.IL2CPP_TYPE_OBJECT && t.Byref == 0); + _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_OBJECT] = context.Binary.AllTypes.First(t => t.Type == Il2CppTypeEnum.IL2CPP_TYPE_OBJECT && t.Byref == 0); - for (var i = 0; i < metadata.TypeDefinitionCount; i++) + for (var i = 0; i < context.Metadata.TypeDefinitionCount; i++) { - var typeDefinition = metadata.typeDefs[i]; + var typeDefinition = context.Metadata.typeDefs[i]; _typeIndices[typeDefinition] = Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(i); @@ -73,7 +78,7 @@ internal void Init(LibCpp2IlContext context) PrimitiveTypeDefinitions[type.Type] = typeDefinition; } - foreach (var type in binary.AllTypes) + foreach (var type in context.Binary.AllTypes) { if (type.Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) continue; @@ -83,34 +88,34 @@ internal void Init(LibCpp2IlContext context) } } - public Il2CppTypeDefinition? GetType(Il2CppMetadata metadata, string name, string? @namespace = null) + public Il2CppTypeDefinition? GetType(string name, string? @namespace = null) { var key = (name, @namespace); if (!_cachedTypes.ContainsKey(key)) { - var typeDef = metadata.typeDefs.FirstOrDefault(td => td.Name == name && (@namespace == null || @namespace == td.Namespace)); + var typeDef = Context.Metadata.typeDefs.FirstOrDefault(td => td.Name == name && (@namespace == null || @namespace == td.Namespace)); _cachedTypes[key] = typeDef; } return _cachedTypes[key]; } - public Il2CppTypeDefinition? GetTypeByFullName(Il2CppMetadata metadata, string fullName) + public Il2CppTypeDefinition? GetTypeByFullName(string fullName) { if (!_cachedTypesByFullName.ContainsKey(fullName)) { - var typeDef = metadata.typeDefs.FirstOrDefault(td => td.FullName == fullName); + var typeDef = Context.Metadata.typeDefs.FirstOrDefault(td => td.FullName == fullName); _cachedTypesByFullName[fullName] = typeDef; } return _cachedTypesByFullName[fullName]; } - public Il2CppTypeDefinition? GetTypeDefinitionByTypeIndex(Il2CppBinary binary, Il2CppVariableWidthIndex index) + public Il2CppTypeDefinition? GetTypeDefinitionByTypeIndex(Il2CppVariableWidthIndex index) { if (index.IsNull) return null; - var type = binary.GetType(index); + var type = Context.Binary.GetType(index); return type.CoerceToUnderlyingTypeDefinition(); } @@ -118,7 +123,7 @@ internal void Init(LibCpp2IlContext context) public Il2CppVariableWidthIndex GetTypeIndexFromType(Il2CppTypeDefinition typeDefinition) => _typeIndices.GetOrDefault(typeDefinition, Il2CppVariableWidthIndex.Null); - public Il2CppVariableWidthIndex GetMethodIndexFromMethod(Il2CppMetadata metadata, Il2CppMethodDefinition methodDefinition) + public Il2CppVariableWidthIndex GetMethodIndexFromMethod(Il2CppMethodDefinition methodDefinition) { if (_methodIndices.Count == 0) { @@ -126,9 +131,9 @@ public Il2CppVariableWidthIndex GetMethodIndexFromMethod { if (_methodIndices.Count == 0) { - for (var i = 0; i < metadata.MethodDefinitionCount; i++) + for (var i = 0; i < Context.Metadata.MethodDefinitionCount; i++) { - var def = metadata.methodDefs[i]; + var def = Context.Metadata.methodDefs[i]; _methodIndices[def] = Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(i); } } @@ -138,7 +143,7 @@ public Il2CppVariableWidthIndex GetMethodIndexFromMethod return _methodIndices.GetOrDefault(methodDefinition, Il2CppVariableWidthIndex.Null); } - public Il2CppVariableWidthIndex GetFieldIndexFromField(Il2CppMetadata metadata, Il2CppFieldDefinition fieldDefinition) + public Il2CppVariableWidthIndex GetFieldIndexFromField(Il2CppFieldDefinition fieldDefinition) { if (_fieldIndices.Count == 0) { @@ -146,9 +151,9 @@ public Il2CppVariableWidthIndex GetFieldIndexFromField(Il { if (_fieldIndices.Count == 0) { - for (var i = 0; i < metadata.fieldDefs.Length; i++) + for (var i = 0; i < Context.Metadata.fieldDefs.Length; i++) { - var def = metadata.fieldDefs[i]; + var def = Context.Metadata.fieldDefs[i]; _fieldIndices[def] = Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage(i); } } @@ -158,7 +163,7 @@ public Il2CppVariableWidthIndex GetFieldIndexFromField(Il return _fieldIndices[fieldDefinition]; } - public int GetPropertyIndexFromProperty(Il2CppMetadata metadata, Il2CppPropertyDefinition propertyDefinition) + public int GetPropertyIndexFromProperty(Il2CppPropertyDefinition propertyDefinition) { if (_propertyIndices.Count == 0) { @@ -166,8 +171,8 @@ public int GetPropertyIndexFromProperty(Il2CppMetadata metadata, Il2CppPropertyD { if (_propertyIndices.Count == 0) { - for (var i = 0; i < metadata.propertyDefs.Length; i++) - _propertyIndices[metadata.propertyDefs[i]] = i; + for (var i = 0; i < Context.Metadata.propertyDefs.Length; i++) + _propertyIndices[Context.Metadata.propertyDefs[i]] = i; } } } @@ -175,7 +180,7 @@ public int GetPropertyIndexFromProperty(Il2CppMetadata metadata, Il2CppPropertyD return _propertyIndices[propertyDefinition]; } - public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppMetadata metadata, Il2CppFieldDefinition fieldDefinition) + public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppFieldDefinition fieldDefinition) { if (_fieldDeclaringTypes.Count == 0) { @@ -183,7 +188,7 @@ public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppMetadata metadata, I { if (_fieldDeclaringTypes.Count == 0) { - foreach (var declaringType in metadata.typeDefs) + foreach (var declaringType in Context.Metadata.typeDefs) foreach (var field in declaringType.Fields ?? []) _fieldDeclaringTypes[field] = declaringType; } @@ -193,7 +198,7 @@ public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppMetadata metadata, I return _fieldDeclaringTypes[fieldDefinition]; } - public Il2CppType? GetTypeFromDefinition(Il2CppBinary binary, Il2CppTypeDefinition definition) + public Il2CppType? GetTypeFromDefinition(Il2CppTypeDefinition definition) { switch (definition.FullName) { @@ -222,7 +227,7 @@ public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppMetadata metadata, I if (_il2CppTypeCache.TryGetValue(index, out var cachedType)) return cachedType; - foreach (var type in binary.AllTypes) + foreach (var type in Context.Binary.AllTypes) { if (type.Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) continue; @@ -239,4 +244,3 @@ public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppMetadata metadata, I return null; } } - diff --git a/LibCpp2IL/Wasm/WasmFile.cs b/LibCpp2IL/Wasm/WasmFile.cs index b185c4c46..48f217fa0 100644 --- a/LibCpp2IL/Wasm/WasmFile.cs +++ b/LibCpp2IL/Wasm/WasmFile.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using LibCpp2IL.Logging; -using LibCpp2IL.Metadata; using WasmDisassembler; namespace LibCpp2IL.Wasm; diff --git a/LibCpp2ILTests/Tests.cs b/LibCpp2ILTests/Tests.cs index bc386584a..1fc2c8644 100644 --- a/LibCpp2ILTests/Tests.cs +++ b/LibCpp2ILTests/Tests.cs @@ -1,4 +1,3 @@ -using System.Net; using System.Net.Http; using AssetRipper.Primitives; using LibCpp2IL; @@ -14,6 +13,11 @@ public class Tests public Tests(ITestOutputHelper outputHelper) { _outputHelper = outputHelper; + + //Configure the lib. + LibCpp2IlMain.Settings.DisableGlobalResolving = true; + LibCpp2IlMain.Settings.DisableMethodPointerMapping = true; + LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput = false; } private static HttpClient client = new(); @@ -28,17 +32,11 @@ private async void CheckFiles(string metadataUrl, string binaryUrl, UnityVersion var binaryBytes = await client.GetByteArrayAsync(binaryUrl); _outputHelper.WriteLine($"Got {binaryBytes.Length / 1024 / 1024} MB binary file."); - //Configure the lib. - LibCpp2IlMain.Settings.DisableGlobalResolving = true; - LibCpp2IlMain.Settings.DisableMethodPointerMapping = true; - LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput = false; - - //Clean up any previous runs - LibCpp2IlMain.TheMetadata = null; - LibCpp2IlMain.Binary = null; - _outputHelper.WriteLine("Invoking LibCpp2IL..."); - Assert.True(LibCpp2IlMain.Initialize(binaryBytes, metadataBytes, unityVer)); + var context = LibCpp2IlContextBuilder.Build(binaryBytes, metadataBytes, unityVer); + Assert.NotNull(context); + Assert.NotNull(context.Binary); + Assert.NotNull(context.Metadata); _outputHelper.WriteLine("Done."); } diff --git a/StableNameDotNet/StableNameGenerator.cs b/StableNameDotNet/StableNameGenerator.cs index fcbaad71d..6b7df27f6 100644 --- a/StableNameDotNet/StableNameGenerator.cs +++ b/StableNameDotNet/StableNameGenerator.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; diff --git a/StableNameDotNet/UniqueIdentifierGenerator.cs b/StableNameDotNet/UniqueIdentifierGenerator.cs index f3cbe8635..362863250 100644 --- a/StableNameDotNet/UniqueIdentifierGenerator.cs +++ b/StableNameDotNet/UniqueIdentifierGenerator.cs @@ -1,7 +1,6 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace StableNameDotNet;