diff --git a/Il2CppDumper/Il2CppDumper.cs b/Il2CppDumper/Il2CppDumper.cs index e113409..b0b67c4 100644 --- a/Il2CppDumper/Il2CppDumper.cs +++ b/Il2CppDumper/Il2CppDumper.cs @@ -19,6 +19,10 @@ namespace Il2CppInspector model = new Il2CppReflector(proc); } + private string formatAddress(ulong address) => model.Package.BinaryImage.Bits == 32 + ? string.Format($"0x{(uint) address:X8}") + : string.Format($"0x{address:X16}"); + public void WriteFile(string outFile) { using (var writer = new StreamWriter(new FileStream(outFile, FileMode.Create), Encoding.UTF8)) { foreach (var asm in model.Assemblies) { @@ -63,7 +67,7 @@ namespace Il2CppInspector writer.Write("out "); writer.Write($"{param.ParameterType.CSharpName} {param.Name}"); } - writer.Write($"); // TypeDefIndex: {type.Index}; 0x{del.VirtualAddress:X8}\n"); + writer.Write($"); // TypeDefIndex: {type.Index}; {formatAddress(del.VirtualAddress)}\n"); continue; } @@ -128,7 +132,7 @@ namespace Il2CppInspector writer.Write($"{field.FieldType.CSharpName} {field.Name}"); if (field.HasDefaultValue) writer.Write($" = {field.DefaultValueString}"); - writer.Write("; // 0x{0:X2}\n", field.Offset); + writer.Write("; // 0x{0:X2}\n", (uint) field.Offset); } if (type.DeclaredFields.Count > 0) writer.Write("\n"); @@ -152,9 +156,8 @@ namespace Il2CppInspector writer.Write((prop.GetMethod != null ? "get; " : "") + (prop.SetMethod != null ? "set; " : "") + "}"); if ((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0) || (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0)) writer.Write(" // "); - writer.Write((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0? "0x{0:X8} " : "") - + (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0? "0x{1:X8}" : "") + "\n", - prop.GetMethod?.VirtualAddress, prop.SetMethod?.VirtualAddress); + writer.Write((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0? formatAddress(prop.GetMethod.VirtualAddress) + " " : "") + + (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0? formatAddress(prop.SetMethod.VirtualAddress) : "") + "\n"); usedMethods.Add(prop.GetMethod); usedMethods.Add(prop.SetMethod); } @@ -168,11 +171,11 @@ namespace Il2CppInspector foreach (var evt in type.DeclaredEvents) { string modifiers = evt.AddMethod?.GetModifierString(); writer.Write($"\t{modifiers}event {evt.EventHandlerType.CSharpName} {evt.Name} {{\n"); - var m = new Dictionary(); + var m = new Dictionary(); if (evt.AddMethod != null) m.Add("add", evt.AddMethod.VirtualAddress); if (evt.RemoveMethod != null) m.Add("remove", evt.RemoveMethod.VirtualAddress); if (evt.RaiseMethod != null) m.Add("raise", evt.RaiseMethod.VirtualAddress); - writer.Write(string.Join("\n", m.Select(x => $"\t\t{x.Key}; // 0x{x.Value:X8}")) + "\n\t}\n"); + writer.Write(string.Join("\n", m.Select(x => $"\t\t{x.Key}; // {formatAddress(x.Value)}")) + "\n\t}\n"); usedMethods.Add(evt.AddMethod); usedMethods.Add(evt.RemoveMethod); usedMethods.Add(evt.RaiseMethod); @@ -199,7 +202,7 @@ namespace Il2CppInspector writer.Write("out "); writer.Write($"{param.ParameterType.CSharpName} {param.Name}"); } - writer.Write(");" + (method.VirtualAddress != 0? $" // 0x{method.VirtualAddress:X8}" : "") + "\n"); + writer.Write(");" + (method.VirtualAddress != 0? $" // {formatAddress(method.VirtualAddress)}" : "") + "\n"); } writer.Write("}\n"); } diff --git a/Il2CppInspector/Il2CppBinary.cs b/Il2CppInspector/Il2CppBinary.cs index 7797f10..1a8c9d2 100644 --- a/Il2CppInspector/Il2CppBinary.cs +++ b/Il2CppInspector/Il2CppBinary.cs @@ -21,13 +21,13 @@ namespace Il2CppInspector public Il2CppMetadataRegistration MetadataRegistration { get; protected set; } // Only for <=v24.1 - public uint[] GlobalMethodPointers { get; set; } + public ulong[] GlobalMethodPointers { get; set; } // NOTE: In versions <21 and earlier releases of v21, this array has the format: // global field index => field offset // In versions >=22 and later releases of v21, this array has the format: // type index => RVA in image where the list of field offsets for the type start (4 bytes per field) - public int[] FieldOffsetData { get; private set; } + public long[] FieldOffsetData { get; private set; } // Every defined type public List Types { get; private set; } @@ -117,13 +117,19 @@ namespace Il2CppInspector } private void Configure(IFileFormatReader image, ulong codeRegistration, ulong metadataRegistration) { + // Set width of long (convert to sizeof(int) for 32-bit files) + if (image.Bits == 32) { + image.Stream.PrimitiveMappings.Add(typeof(long), typeof(int)); + image.Stream.PrimitiveMappings.Add(typeof(ulong), typeof(uint)); + } + // Root structures from which we find everything else CodeRegistration = image.ReadMappedObject(codeRegistration); MetadataRegistration = image.ReadMappedObject(metadataRegistration); // The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule if (Image.Stream.Version <= 24.1) - GlobalMethodPointers = image.ReadMappedArray(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount); + GlobalMethodPointers = image.ReadMappedArray(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount); // After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules if (Image.Stream.Version >= 24.2) { @@ -139,10 +145,10 @@ namespace Il2CppInspector } // Field offset data. Metadata <=21.x uses a value-type array; >=21.x uses a pointer array - FieldOffsetData = image.ReadMappedArray(MetadataRegistration.pfieldOffsets, MetadataRegistration.fieldOffsetsCount); + FieldOffsetData = image.ReadMappedArray(MetadataRegistration.pfieldOffsets, (int) MetadataRegistration.fieldOffsetsCount); // Type definitions (pointer array) - Types = image.ReadMappedObjectPointerArray(MetadataRegistration.ptypes, MetadataRegistration.typesCount); + Types = image.ReadMappedObjectPointerArray(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount); } } } diff --git a/Il2CppInspector/Il2CppBinaryClasses.cs b/Il2CppInspector/Il2CppBinaryClasses.cs index e4a30bb..e659c3c 100644 --- a/Il2CppInspector/Il2CppBinaryClasses.cs +++ b/Il2CppInspector/Il2CppBinaryClasses.cs @@ -14,96 +14,96 @@ namespace Il2CppInspector { // Moved to Il2CppCodeGenModule in v24.2 [Version(Max = 24.1)] - public uint methodPointersCount; + public ulong methodPointersCount; [Version(Max = 24.1)] - public uint pmethodPointers; + public ulong pmethodPointers; - public uint reversePInvokeWrapperCount; // (was renamed from delegateWrappersFromNativeToManagedCount in v22) - public uint reversePInvokeWrappers; // (was renamed from delegateWrappersFromNativeToManaged in v22) + public ulong reversePInvokeWrapperCount; // (was renamed from delegateWrappersFromNativeToManagedCount in v22) + public ulong reversePInvokeWrappers; // (was renamed from delegateWrappersFromNativeToManaged in v22) // Removed in metadata v23 [Version(Max = 22)] - public uint delegateWrappersFromManagedToNativeCount; + public ulong delegateWrappersFromManagedToNativeCount; [Version(Max = 22)] - public uint delegateWrappersFromManagedToNative; + public ulong delegateWrappersFromManagedToNative; [Version(Max = 22)] - public uint marshalingFunctionsCount; + public ulong marshalingFunctionsCount; [Version(Max = 22)] - public uint marshalingFunctions; + public ulong marshalingFunctions; [Version(Max = 22)] - public uint ccwMarshalingFunctionsCount; + public ulong ccwMarshalingFunctionsCount; [Version(Max = 22)] - public uint ccwMarshalingFunctions; + public ulong ccwMarshalingFunctions; - public uint genericMethodPointersCount; - public uint genericMethodPointers; - public uint invokerPointersCount; - public uint invokerPointers; - public int customAttributeCount; - public uint customAttributeGenerators; + public ulong genericMethodPointersCount; + public ulong genericMethodPointers; + public ulong invokerPointersCount; + public ulong invokerPointers; + public long customAttributeCount; + public ulong customAttributeGenerators; // Removed in metadata v23 [Version(Max = 22)] - public int guidCount; + public long guidCount; [Version(Max = 22)] - public uint guids; // Il2CppGuid + public ulong guids; // Il2CppGuid // Added in metadata v22 [Version(Min = 22)] - public uint unresolvedVirtualCallCount; + public ulong unresolvedVirtualCallCount; [Version(Min = 22)] - public uint unresolvedVirtualCallPointers; + public ulong unresolvedVirtualCallPointers; // Added in metadata v23 [Version(Min = 23)] - public uint interopDataCount; + public ulong interopDataCount; [Version(Min = 23)] - public uint interopData; + public ulong interopData; // Added in metadata v24.2 to replace methodPointers and methodPointersCount [Version(Min = 24.2)] - public uint codeGenModulesCount; + public ulong codeGenModulesCount; [Version(Min = 24.2)] - public uint pcodeGenModules; + public ulong pcodeGenModules; } // Introduced in metadata v24.2 (replaces method pointers in Il2CppCodeRegistration) public class Il2CppCodeGenModule { - public uint moduleName; - public uint methodPointerCount; - public uint methodPointers; - public uint invokerIndices; - public uint reversePInvokeWrapperCount; - public uint reversePInvokeWrapperIndices; - public uint rgctxRangesCount; - public uint rgctxRanges; - public uint rgctxsCount; - public uint rgctxs; - public uint debuggerMetadata; + public ulong moduleName; + public ulong methodPointerCount; + public ulong methodPointers; + public ulong invokerIndices; + public ulong reversePInvokeWrapperCount; + public ulong reversePInvokeWrapperIndices; + public ulong rgctxRangesCount; + public ulong rgctxRanges; + public ulong rgctxsCount; + public ulong rgctxs; + public ulong debuggerMetadata; } #pragma warning disable CS0649 public class Il2CppMetadataRegistration { - public int genericClassesCount; - public uint genericClasses; - public int genericInstsCount; - public uint genericInsts; - public int genericMethodTableCount; - public uint genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions - public int typesCount; - public uint ptypes; - public int methodSpecsCount; - public uint methodSpecs; + public long genericClassesCount; + public ulong genericClasses; + public long genericInstsCount; + public ulong genericInsts; + public long genericMethodTableCount; + public ulong genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions + public long typesCount; + public ulong ptypes; + public long methodSpecsCount; + public ulong methodSpecs; - public int fieldOffsetsCount; - public uint pfieldOffsets; + public long fieldOffsetsCount; + public ulong pfieldOffsets; - public int typeDefinitionsSizesCount; - public uint typeDefinitionsSizes; - public uint metadataUsagesCount; - public uint metadataUsages; + public long typeDefinitionsSizesCount; + public ulong typeDefinitionsSizes; + public ulong metadataUsagesCount; + public ulong metadataUsages; } #pragma warning restore CS0649 @@ -163,44 +163,44 @@ namespace Il2CppInspector Il2CppGenericClass* generic_class; // for GENERICINST } */ - public uint datapoint; - public uint bits; // this should be private but we need it to be public for BinaryObjectReader to work + public ulong datapoint; + public ulong bits; // this should be private but we need it to be public for BinaryObjectReader to work - public uint attrs => bits & 0xffff; /* param attributes or field flags */ + public uint attrs => (uint) bits & 0xffff; /* param attributes or field flags */ public Il2CppTypeEnum type => (Il2CppTypeEnum)((bits >> 16) & 0xff); - public uint num_mods => (bits >> 24) & 0x3f; /* max 64 modifiers follow at the end */ + public uint num_mods => (uint) (bits >> 24) & 0x3f; /* max 64 modifiers follow at the end */ public bool byref => ((bits >> 30) & 1) == 1; public bool pinned => (bits >> 31) == 1; /* valid when included in a local var signature */ } public class Il2CppGenericClass { - public int typeDefinitionIndex; /* the generic type definition */ + public long typeDefinitionIndex; /* the generic type definition */ public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */ - public uint cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */ + public ulong cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */ } public class Il2CppGenericContext { /* The instantiation corresponding to the class generic parameters */ - public uint class_inst; + public ulong class_inst; /* The instantiation corresponding to the method generic parameters */ - public uint method_inst; + public ulong method_inst; } public class Il2CppGenericInst { - public uint type_argc; - public uint type_argv; + public ulong type_argc; + public ulong type_argv; } public class Il2CppArrayType { - public uint etype; + public ulong etype; public byte rank; public byte numsizes; public byte numlobounds; - public uint sizes; - public uint lobounds; + public ulong sizes; + public ulong lobounds; } } diff --git a/Il2CppInspector/Il2CppInspector.cs b/Il2CppInspector/Il2CppInspector.cs index 5f6fca7..c32fb70 100644 --- a/Il2CppInspector/Il2CppInspector.cs +++ b/Il2CppInspector/Il2CppInspector.cs @@ -32,10 +32,10 @@ namespace Il2CppInspector public Il2CppEventDefinition[] Events => Metadata.Events; public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices; public Dictionary FieldDefaultValue { get; } = new Dictionary(); - public List FieldOffsets { get; } + public List FieldOffsets { get; } public List TypeUsages => Binary.Types; public Dictionary Modules => Binary.Modules; - public uint[] GlobalMethodPointers => Binary.GlobalMethodPointers; // <=v24.1 only + public ulong[] GlobalMethodPointers => Binary.GlobalMethodPointers; // <=v24.1 only // TODO: Finish all file access in the constructor and eliminate the need for this public IFileFormatReader BinaryImage => Binary.Image; @@ -129,15 +129,15 @@ namespace Il2CppInspector } // Convert pointer list into fields else { - var offsets = new Dictionary(); + var offsets = new Dictionary(); for (var i = 0; i < TypeDefinitions.Length; i++) { var def = TypeDefinitions[i]; var pFieldOffsets = Binary.FieldOffsetData[i]; if (pFieldOffsets != 0) { - BinaryImage.Position = BinaryImage.MapVATR((uint) pFieldOffsets); + BinaryImage.Position = BinaryImage.MapVATR((ulong) pFieldOffsets); for (var f = 0; f < def.field_count; f++) - offsets.Add(def.fieldStart + f, BinaryImage.Stream.ReadInt32()); + offsets.Add(def.fieldStart + f, BinaryImage.Stream.ReadObject()); } } diff --git a/Il2CppInspector/Il2CppReflector.cs b/Il2CppInspector/Il2CppReflector.cs index 76718de..f005ef1 100644 --- a/Il2CppInspector/Il2CppReflector.cs +++ b/Il2CppInspector/Il2CppReflector.cs @@ -27,7 +27,7 @@ namespace Il2CppInspector.Reflection public Assembly GetAssembly(TypeInfo type) => Assemblies.FirstOrDefault(x => x.DefinedTypes.Contains(type)); // Get a type from its IL2CPP type index - public TypeInfo GetTypeFromIndex(int typeIndex) => Assemblies.SelectMany(x => x.DefinedTypes).FirstOrDefault(x => x.Index == typeIndex); + public TypeInfo GetTypeFromIndex(long typeIndex) => Assemblies.SelectMany(x => x.DefinedTypes).FirstOrDefault(x => x.Index == typeIndex); // Get or generate a type from its IL2CPP binary type usage reference // (field, return type, generic type parameter etc.) diff --git a/Il2CppInspector/Reflection/FieldInfo.cs b/Il2CppInspector/Reflection/FieldInfo.cs index 3598913..8106ae0 100644 --- a/Il2CppInspector/Reflection/FieldInfo.cs +++ b/Il2CppInspector/Reflection/FieldInfo.cs @@ -13,7 +13,7 @@ namespace Il2CppInspector.Reflection { // IL2CPP-specific data public Il2CppFieldDefinition Definition { get; } public int Index { get; } - public int Offset { get; } + public long Offset { get; } public bool HasDefaultValue { get; } public object DefaultValue { get; } diff --git a/Il2CppInspector/Reflection/MethodInfo.cs b/Il2CppInspector/Reflection/MethodInfo.cs index 5772ef6..25f6cdd 100644 --- a/Il2CppInspector/Reflection/MethodInfo.cs +++ b/Il2CppInspector/Reflection/MethodInfo.cs @@ -15,7 +15,7 @@ namespace Il2CppInspector.Reflection // IL2CPP-specific data public Il2CppMethodDefinition Definition { get; } public int Index { get; } - public uint VirtualAddress { get; } + public ulong VirtualAddress { get; } public bool HasBody { get; } public override MemberTypes MemberType => MemberTypes.Method;