diff --git a/Il2CppDumper/Il2CppCSharpDumper.cs b/Il2CppDumper/Il2CppCSharpDumper.cs index cce3a83..bd646d1 100644 --- a/Il2CppDumper/Il2CppCSharpDumper.cs +++ b/Il2CppDumper/Il2CppCSharpDumper.cs @@ -195,7 +195,7 @@ namespace Il2CppInspector // Fixed buffers if (field.GetCustomAttributes(FBAttribute).Any()) { if (!SuppressMetadata) - sb.Append($"/* {((ulong) field.GetCustomAttributes(FBAttribute)[0].VirtualAddress).ToAddressString()} */ "); + sb.Append($"/* {field.GetCustomAttributes(FBAttribute)[0].VirtualAddress.ToAddressString()} */ "); sb.Append($"{field.FieldType.DeclaredFields[0].FieldType.CSharpName} {field.Name}[0]"); // FixedElementField } // Regular fields @@ -237,10 +237,10 @@ namespace Il2CppInspector + (prop.CanWrite? prop.SetMethod.CustomAttributes.Where(a => !SuppressGenerated || a.AttributeType.FullName != CGAttribute).ToString(inline: true, emitPointer: !SuppressMetadata) + (setAccess < getAccess? prop.SetMethod.GetAccessModifierString() : "") + "set; " : "") + "}"); if (!SuppressMetadata) { - if ((prop.CanRead && prop.GetMethod.VirtualAddress != 0) || (prop.CanWrite && prop.SetMethod.VirtualAddress != 0)) + if ((prop.CanRead && prop.GetMethod.VirtualAddress != null) || (prop.CanWrite && prop.SetMethod.VirtualAddress != null)) sb.Append(" // "); - sb.Append((prop.CanRead && prop.GetMethod.VirtualAddress != 0 ? prop.GetMethod.VirtualAddress.ToAddressString() + " " : "") - + (prop.CanWrite && prop.SetMethod.VirtualAddress != 0 ? prop.SetMethod.VirtualAddress.ToAddressString() : "")); + sb.Append((prop.CanRead && prop.GetMethod.VirtualAddress != null ? prop.GetMethod.VirtualAddress.ToAddressString() + " " : "") + + (prop.CanWrite && prop.SetMethod.VirtualAddress != null ? prop.SetMethod.VirtualAddress.ToAddressString() : "")); } sb.Append("\n"); @@ -257,7 +257,7 @@ namespace Il2CppInspector string modifiers = evt.AddMethod?.GetModifierString(); sb.Append($"{prefix}\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); @@ -279,7 +279,7 @@ namespace Il2CppInspector sb.Append($"{prefix}\t{method.GetModifierString()}{method.DeclaringType.UnmangledBaseName}{method.GetTypeParametersString()}("); sb.Append(method.GetParametersString(!SuppressMetadata) + ")" + (method.IsAbstract? ";" : @" {}")); - sb.Append((!SuppressMetadata && method.VirtualAddress != 0 ? $" // {method.VirtualAddress.ToAddressString()}" : "") + "\n"); + sb.Append((!SuppressMetadata && method.VirtualAddress != null ? $" // {method.VirtualAddress.ToAddressString()}" : "") + "\n"); } codeBlocks.Add("Constructors", sb.ToString()); @@ -384,7 +384,7 @@ namespace Il2CppInspector writer.Append($"\n{prefix}\t\t{constraint}"); } - writer.Append((method.IsAbstract? ";" : @" {}") + (!SuppressMetadata && method.VirtualAddress != 0 ? $" // {method.VirtualAddress.ToAddressString()}" : "") + "\n"); + writer.Append((method.IsAbstract? ";" : @" {}") + (!SuppressMetadata && method.VirtualAddress != null ? $" // {method.VirtualAddress.ToAddressString()}" : "") + "\n"); return writer.ToString(); } diff --git a/Il2CppInspector/Il2CppBinary.cs b/Il2CppInspector/Il2CppBinary.cs index c223d46..6489bdd 100644 --- a/Il2CppInspector/Il2CppBinary.cs +++ b/Il2CppInspector/Il2CppBinary.cs @@ -38,7 +38,7 @@ namespace Il2CppInspector public long[] FieldOffsetPointers { get; private set; } // Generated functions which call constructors on custom attributes - public long[] CustomAttributeGenerators { get; private set; } + public ulong[] CustomAttributeGenerators { get; private set; } // Every defined type public List Types { get; private set; } @@ -187,7 +187,7 @@ namespace Il2CppInspector Types = image.ReadMappedObjectPointerArray(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount); // Custom attribute constructors - CustomAttributeGenerators = Image.ReadMappedWordArray(CodeRegistration.customAttributeGenerators, (int) CodeRegistration.customAttributeCount); + CustomAttributeGenerators = Image.ReadMappedArray(CodeRegistration.customAttributeGenerators, (int) CodeRegistration.customAttributeCount); } } } diff --git a/Il2CppInspector/Il2CppInspector.cs b/Il2CppInspector/Il2CppInspector.cs index b56462e..8ff151f 100644 --- a/Il2CppInspector/Il2CppInspector.cs +++ b/Il2CppInspector/Il2CppInspector.cs @@ -19,6 +19,9 @@ namespace Il2CppInspector private Il2CppBinary Binary { get; } private Metadata Metadata { get; } + // All method pointers sorted in ascending order (for finding the end of a method) + private List sortedMethodPointers { get; set; } + // Shortcuts public double Version => Metadata.Version; @@ -43,7 +46,7 @@ namespace Il2CppInspector public List FieldOffsets { get; } public List TypeUsages => Binary.Types; public Dictionary Modules => Binary.Modules; - public long[] CustomAttributeGenerators => Binary.CustomAttributeGenerators; + public ulong[] CustomAttributeGenerators => Binary.CustomAttributeGenerators; // TODO: Finish all file access in the constructor and eliminate the need for this public IFileFormatReader BinaryImage => Binary.Image; @@ -149,33 +152,50 @@ namespace Il2CppInspector FieldOffsets = offsets.OrderBy(x => x.Key).Select(x => x.Value).ToList(); } + + // Get sorted list of method pointers + if (Version <= 24.1) + sortedMethodPointers = Binary.GlobalMethodPointers.OrderBy(m => m).ToList(); + if (Version >= 24.2) + sortedMethodPointers = Binary.ModuleMethodPointers.SelectMany(module => module.Value).OrderBy(m => m).ToList(); } - public ulong GetMethodPointer(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) { + public (ulong Start, ulong End)? GetMethodPointer(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) { // Find method pointer if (methodDef.methodIndex < 0) - return 0; + return null; + + ulong start = 0; // Global method pointer array if (Version <= 24.1) { - return Binary.GlobalMethodPointers[methodDef.methodIndex] & 0xffff_ffff_ffff_fffe; + start = Binary.GlobalMethodPointers[methodDef.methodIndex] & 0xffff_ffff_ffff_fffe; } // Per-module method pointer array uses the bottom 24 bits of the method's metadata token // Derived from il2cpp::vm::MetadataCache::GetMethodPointer - var method = (methodDef.token & 0xffffff); - if (method == 0) - return 0; + if (Version >= 24.2) { + var method = (methodDef.token & 0xffffff); + if (method == 0) + return null; - // In the event of an exception, the method pointer is not set in the file - // This probably means it has been optimized away by the compiler, or is an unused generic method - try { - // Remove ARM Thumb marker LSB if necessary - return Binary.ModuleMethodPointers[module][method - 1] & 0xffff_ffff_ffff_fffe; + // In the event of an exception, the method pointer is not set in the file + // This probably means it has been optimized away by the compiler, or is an unused generic method + try { + // Remove ARM Thumb marker LSB if necessary + start = Binary.ModuleMethodPointers[module][method - 1] & 0xffff_ffff_ffff_fffe; + } + catch (IndexOutOfRangeException) { + return null; + } } - catch (IndexOutOfRangeException) { } - return 0; + if (start == 0) + return null; + + // Consider the end of the method to be the start of the next method (or zero) + // The last method end will be wrong but there is no way to calculate it + return (start, sortedMethodPointers.FirstOrDefault(p => p > start)); } public static List LoadFromFile(string codeFile, string metadataFile) { diff --git a/Il2CppInspector/Reflection/CustomAttributeData.cs b/Il2CppInspector/Reflection/CustomAttributeData.cs index 39ecd48..9b70f19 100644 --- a/Il2CppInspector/Reflection/CustomAttributeData.cs +++ b/Il2CppInspector/Reflection/CustomAttributeData.cs @@ -21,7 +21,9 @@ namespace Il2CppInspector.Reflection // The type of the attribute public TypeInfo AttributeType { get; set; } - public long VirtualAddress => package.CustomAttributeGenerators[Index]; + public (ulong Start, ulong End)? VirtualAddress => + // The last one will be wrong but there is no way to calculate it + (package.CustomAttributeGenerators[Index], package.CustomAttributeGenerators[Math.Min(Index + 1, package.CustomAttributeGenerators.Length - 1)]); public override string ToString() => "[" + AttributeType.FullName + "]"; diff --git a/Il2CppInspector/Reflection/Extensions.cs b/Il2CppInspector/Reflection/Extensions.cs index 1139081..b32abf1 100644 --- a/Il2CppInspector/Reflection/Extensions.cs +++ b/Il2CppInspector/Reflection/Extensions.cs @@ -17,7 +17,7 @@ namespace Il2CppInspector.Reflection name = name[..suffix]; sb.Append($"{linePrefix}[{attributePrefix}{name}]"); if (emitPointer) - sb.Append($" {(inline? "/*" : "//")} {((ulong)cad.VirtualAddress).ToAddressString()}{(inline? " */" : "")}"); + sb.Append($" {(inline? "/*" : "//")} {cad.VirtualAddress.ToAddressString()}{(inline? " */" : "")}"); sb.Append(inline? " ":"\n"); } @@ -29,6 +29,8 @@ namespace Il2CppInspector.Reflection ? string.Format($"0x{(uint)address:X8}") : string.Format($"0x{address:X16}"); + public static string ToAddressString(this (ulong start, ulong end)? address) => ToAddressString(address?.start ?? 0) + "-" + ToAddressString(address?.end ?? 0); + // Output a value in C#-friendly syntax public static string ToCSharpValue(this object value) { if (value is bool) diff --git a/Il2CppInspector/Reflection/MethodBase.cs b/Il2CppInspector/Reflection/MethodBase.cs index ae574d0..316e7c6 100644 --- a/Il2CppInspector/Reflection/MethodBase.cs +++ b/Il2CppInspector/Reflection/MethodBase.cs @@ -17,7 +17,7 @@ namespace Il2CppInspector.Reflection // IL2CPP-specific data public Il2CppMethodDefinition Definition { get; } public int Index { get; } - public ulong VirtualAddress { get; } + public (ulong Start, ulong End)? VirtualAddress { get; } // Information/flags about the method public MethodAttributes Attributes { get; protected set; }