Correctly process 64-bit data structures in IL2CPP binaries

This commit is contained in:
Katy Coe
2019-10-23 03:37:01 +02:00
parent 79b62e2566
commit 7e3777dddd
7 changed files with 94 additions and 85 deletions

View File

@@ -19,6 +19,10 @@ namespace Il2CppInspector
model = new Il2CppReflector(proc); 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) { public void WriteFile(string outFile) {
using (var writer = new StreamWriter(new FileStream(outFile, FileMode.Create), Encoding.UTF8)) { using (var writer = new StreamWriter(new FileStream(outFile, FileMode.Create), Encoding.UTF8)) {
foreach (var asm in model.Assemblies) { foreach (var asm in model.Assemblies) {
@@ -63,7 +67,7 @@ namespace Il2CppInspector
writer.Write("out "); writer.Write("out ");
writer.Write($"{param.ParameterType.CSharpName} {param.Name}"); 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; continue;
} }
@@ -128,7 +132,7 @@ namespace Il2CppInspector
writer.Write($"{field.FieldType.CSharpName} {field.Name}"); writer.Write($"{field.FieldType.CSharpName} {field.Name}");
if (field.HasDefaultValue) if (field.HasDefaultValue)
writer.Write($" = {field.DefaultValueString}"); 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) if (type.DeclaredFields.Count > 0)
writer.Write("\n"); writer.Write("\n");
@@ -152,9 +156,8 @@ namespace Il2CppInspector
writer.Write((prop.GetMethod != null ? "get; " : "") + (prop.SetMethod != null ? "set; " : "") + "}"); 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)) if ((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0) || (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0))
writer.Write(" // "); writer.Write(" // ");
writer.Write((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0? "0x{0:X8} " : "") writer.Write((prop.GetMethod != null && prop.GetMethod.VirtualAddress != 0? formatAddress(prop.GetMethod.VirtualAddress) + " " : "")
+ (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0? "0x{1:X8}" : "") + "\n", + (prop.SetMethod != null && prop.SetMethod.VirtualAddress != 0? formatAddress(prop.SetMethod.VirtualAddress) : "") + "\n");
prop.GetMethod?.VirtualAddress, prop.SetMethod?.VirtualAddress);
usedMethods.Add(prop.GetMethod); usedMethods.Add(prop.GetMethod);
usedMethods.Add(prop.SetMethod); usedMethods.Add(prop.SetMethod);
} }
@@ -168,11 +171,11 @@ namespace Il2CppInspector
foreach (var evt in type.DeclaredEvents) { foreach (var evt in type.DeclaredEvents) {
string modifiers = evt.AddMethod?.GetModifierString(); string modifiers = evt.AddMethod?.GetModifierString();
writer.Write($"\t{modifiers}event {evt.EventHandlerType.CSharpName} {evt.Name} {{\n"); writer.Write($"\t{modifiers}event {evt.EventHandlerType.CSharpName} {evt.Name} {{\n");
var m = new Dictionary<string, uint>(); var m = new Dictionary<string, ulong>();
if (evt.AddMethod != null) m.Add("add", evt.AddMethod.VirtualAddress); if (evt.AddMethod != null) m.Add("add", evt.AddMethod.VirtualAddress);
if (evt.RemoveMethod != null) m.Add("remove", evt.RemoveMethod.VirtualAddress); if (evt.RemoveMethod != null) m.Add("remove", evt.RemoveMethod.VirtualAddress);
if (evt.RaiseMethod != null) m.Add("raise", evt.RaiseMethod.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.AddMethod);
usedMethods.Add(evt.RemoveMethod); usedMethods.Add(evt.RemoveMethod);
usedMethods.Add(evt.RaiseMethod); usedMethods.Add(evt.RaiseMethod);
@@ -199,7 +202,7 @@ namespace Il2CppInspector
writer.Write("out "); writer.Write("out ");
writer.Write($"{param.ParameterType.CSharpName} {param.Name}"); 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"); writer.Write("}\n");
} }

View File

@@ -21,13 +21,13 @@ namespace Il2CppInspector
public Il2CppMetadataRegistration MetadataRegistration { get; protected set; } public Il2CppMetadataRegistration MetadataRegistration { get; protected set; }
// Only for <=v24.1 // 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: // NOTE: In versions <21 and earlier releases of v21, this array has the format:
// global field index => field offset // global field index => field offset
// In versions >=22 and later releases of v21, this array has the format: // 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) // 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 // Every defined type
public List<Il2CppType> Types { get; private set; } public List<Il2CppType> Types { get; private set; }
@@ -117,13 +117,19 @@ namespace Il2CppInspector
} }
private void Configure(IFileFormatReader image, ulong codeRegistration, ulong metadataRegistration) { 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 // Root structures from which we find everything else
CodeRegistration = image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration); CodeRegistration = image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
MetadataRegistration = image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration); MetadataRegistration = image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
// The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule // The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule
if (Image.Stream.Version <= 24.1) if (Image.Stream.Version <= 24.1)
GlobalMethodPointers = image.ReadMappedArray<uint>(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount); GlobalMethodPointers = image.ReadMappedArray<ulong>(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount);
// After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules // After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules
if (Image.Stream.Version >= 24.2) { 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 // Field offset data. Metadata <=21.x uses a value-type array; >=21.x uses a pointer array
FieldOffsetData = image.ReadMappedArray<int>(MetadataRegistration.pfieldOffsets, MetadataRegistration.fieldOffsetsCount); FieldOffsetData = image.ReadMappedArray<long>(MetadataRegistration.pfieldOffsets, (int) MetadataRegistration.fieldOffsetsCount);
// Type definitions (pointer array) // Type definitions (pointer array)
Types = image.ReadMappedObjectPointerArray<Il2CppType>(MetadataRegistration.ptypes, MetadataRegistration.typesCount); Types = image.ReadMappedObjectPointerArray<Il2CppType>(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount);
} }
} }
} }

View File

@@ -14,96 +14,96 @@ namespace Il2CppInspector
{ {
// Moved to Il2CppCodeGenModule in v24.2 // Moved to Il2CppCodeGenModule in v24.2
[Version(Max = 24.1)] [Version(Max = 24.1)]
public uint methodPointersCount; public ulong methodPointersCount;
[Version(Max = 24.1)] [Version(Max = 24.1)]
public uint pmethodPointers; public ulong pmethodPointers;
public uint reversePInvokeWrapperCount; // (was renamed from delegateWrappersFromNativeToManagedCount in v22) public ulong reversePInvokeWrapperCount; // (was renamed from delegateWrappersFromNativeToManagedCount in v22)
public uint reversePInvokeWrappers; // (was renamed from delegateWrappersFromNativeToManaged in v22) public ulong reversePInvokeWrappers; // (was renamed from delegateWrappersFromNativeToManaged in v22)
// Removed in metadata v23 // Removed in metadata v23
[Version(Max = 22)] [Version(Max = 22)]
public uint delegateWrappersFromManagedToNativeCount; public ulong delegateWrappersFromManagedToNativeCount;
[Version(Max = 22)] [Version(Max = 22)]
public uint delegateWrappersFromManagedToNative; public ulong delegateWrappersFromManagedToNative;
[Version(Max = 22)] [Version(Max = 22)]
public uint marshalingFunctionsCount; public ulong marshalingFunctionsCount;
[Version(Max = 22)] [Version(Max = 22)]
public uint marshalingFunctions; public ulong marshalingFunctions;
[Version(Max = 22)] [Version(Max = 22)]
public uint ccwMarshalingFunctionsCount; public ulong ccwMarshalingFunctionsCount;
[Version(Max = 22)] [Version(Max = 22)]
public uint ccwMarshalingFunctions; public ulong ccwMarshalingFunctions;
public uint genericMethodPointersCount; public ulong genericMethodPointersCount;
public uint genericMethodPointers; public ulong genericMethodPointers;
public uint invokerPointersCount; public ulong invokerPointersCount;
public uint invokerPointers; public ulong invokerPointers;
public int customAttributeCount; public long customAttributeCount;
public uint customAttributeGenerators; public ulong customAttributeGenerators;
// Removed in metadata v23 // Removed in metadata v23
[Version(Max = 22)] [Version(Max = 22)]
public int guidCount; public long guidCount;
[Version(Max = 22)] [Version(Max = 22)]
public uint guids; // Il2CppGuid public ulong guids; // Il2CppGuid
// Added in metadata v22 // Added in metadata v22
[Version(Min = 22)] [Version(Min = 22)]
public uint unresolvedVirtualCallCount; public ulong unresolvedVirtualCallCount;
[Version(Min = 22)] [Version(Min = 22)]
public uint unresolvedVirtualCallPointers; public ulong unresolvedVirtualCallPointers;
// Added in metadata v23 // Added in metadata v23
[Version(Min = 23)] [Version(Min = 23)]
public uint interopDataCount; public ulong interopDataCount;
[Version(Min = 23)] [Version(Min = 23)]
public uint interopData; public ulong interopData;
// Added in metadata v24.2 to replace methodPointers and methodPointersCount // Added in metadata v24.2 to replace methodPointers and methodPointersCount
[Version(Min = 24.2)] [Version(Min = 24.2)]
public uint codeGenModulesCount; public ulong codeGenModulesCount;
[Version(Min = 24.2)] [Version(Min = 24.2)]
public uint pcodeGenModules; public ulong pcodeGenModules;
} }
// Introduced in metadata v24.2 (replaces method pointers in Il2CppCodeRegistration) // Introduced in metadata v24.2 (replaces method pointers in Il2CppCodeRegistration)
public class Il2CppCodeGenModule public class Il2CppCodeGenModule
{ {
public uint moduleName; public ulong moduleName;
public uint methodPointerCount; public ulong methodPointerCount;
public uint methodPointers; public ulong methodPointers;
public uint invokerIndices; public ulong invokerIndices;
public uint reversePInvokeWrapperCount; public ulong reversePInvokeWrapperCount;
public uint reversePInvokeWrapperIndices; public ulong reversePInvokeWrapperIndices;
public uint rgctxRangesCount; public ulong rgctxRangesCount;
public uint rgctxRanges; public ulong rgctxRanges;
public uint rgctxsCount; public ulong rgctxsCount;
public uint rgctxs; public ulong rgctxs;
public uint debuggerMetadata; public ulong debuggerMetadata;
} }
#pragma warning disable CS0649 #pragma warning disable CS0649
public class Il2CppMetadataRegistration public class Il2CppMetadataRegistration
{ {
public int genericClassesCount; public long genericClassesCount;
public uint genericClasses; public ulong genericClasses;
public int genericInstsCount; public long genericInstsCount;
public uint genericInsts; public ulong genericInsts;
public int genericMethodTableCount; public long genericMethodTableCount;
public uint genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions public ulong genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions
public int typesCount; public long typesCount;
public uint ptypes; public ulong ptypes;
public int methodSpecsCount; public long methodSpecsCount;
public uint methodSpecs; public ulong methodSpecs;
public int fieldOffsetsCount; public long fieldOffsetsCount;
public uint pfieldOffsets; public ulong pfieldOffsets;
public int typeDefinitionsSizesCount; public long typeDefinitionsSizesCount;
public uint typeDefinitionsSizes; public ulong typeDefinitionsSizes;
public uint metadataUsagesCount; public ulong metadataUsagesCount;
public uint metadataUsages; public ulong metadataUsages;
} }
#pragma warning restore CS0649 #pragma warning restore CS0649
@@ -163,44 +163,44 @@ namespace Il2CppInspector
Il2CppGenericClass* generic_class; // for GENERICINST Il2CppGenericClass* generic_class; // for GENERICINST
} }
*/ */
public uint datapoint; public ulong datapoint;
public uint bits; // this should be private but we need it to be public for BinaryObjectReader to work 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 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 byref => ((bits >> 30) & 1) == 1;
public bool pinned => (bits >> 31) == 1; /* valid when included in a local var signature */ public bool pinned => (bits >> 31) == 1; /* valid when included in a local var signature */
} }
public class Il2CppGenericClass 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 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 public class Il2CppGenericContext
{ {
/* The instantiation corresponding to the class generic parameters */ /* The instantiation corresponding to the class generic parameters */
public uint class_inst; public ulong class_inst;
/* The instantiation corresponding to the method generic parameters */ /* The instantiation corresponding to the method generic parameters */
public uint method_inst; public ulong method_inst;
} }
public class Il2CppGenericInst public class Il2CppGenericInst
{ {
public uint type_argc; public ulong type_argc;
public uint type_argv; public ulong type_argv;
} }
public class Il2CppArrayType public class Il2CppArrayType
{ {
public uint etype; public ulong etype;
public byte rank; public byte rank;
public byte numsizes; public byte numsizes;
public byte numlobounds; public byte numlobounds;
public uint sizes; public ulong sizes;
public uint lobounds; public ulong lobounds;
} }
} }

View File

@@ -32,10 +32,10 @@ namespace Il2CppInspector
public Il2CppEventDefinition[] Events => Metadata.Events; public Il2CppEventDefinition[] Events => Metadata.Events;
public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices; public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices;
public Dictionary<int, object> FieldDefaultValue { get; } = new Dictionary<int, object>(); public Dictionary<int, object> FieldDefaultValue { get; } = new Dictionary<int, object>();
public List<int> FieldOffsets { get; } public List<long> FieldOffsets { get; }
public List<Il2CppType> TypeUsages => Binary.Types; public List<Il2CppType> TypeUsages => Binary.Types;
public Dictionary<string, Il2CppCodeGenModule> Modules => Binary.Modules; public Dictionary<string, Il2CppCodeGenModule> 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 // TODO: Finish all file access in the constructor and eliminate the need for this
public IFileFormatReader BinaryImage => Binary.Image; public IFileFormatReader BinaryImage => Binary.Image;
@@ -129,15 +129,15 @@ namespace Il2CppInspector
} }
// Convert pointer list into fields // Convert pointer list into fields
else { else {
var offsets = new Dictionary<int, int>(); var offsets = new Dictionary<int, long>();
for (var i = 0; i < TypeDefinitions.Length; i++) { for (var i = 0; i < TypeDefinitions.Length; i++) {
var def = TypeDefinitions[i]; var def = TypeDefinitions[i];
var pFieldOffsets = Binary.FieldOffsetData[i]; var pFieldOffsets = Binary.FieldOffsetData[i];
if (pFieldOffsets != 0) { if (pFieldOffsets != 0) {
BinaryImage.Position = BinaryImage.MapVATR((uint) pFieldOffsets); BinaryImage.Position = BinaryImage.MapVATR((ulong) pFieldOffsets);
for (var f = 0; f < def.field_count; f++) 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<long>());
} }
} }

View File

@@ -27,7 +27,7 @@ namespace Il2CppInspector.Reflection
public Assembly GetAssembly(TypeInfo type) => Assemblies.FirstOrDefault(x => x.DefinedTypes.Contains(type)); public Assembly GetAssembly(TypeInfo type) => Assemblies.FirstOrDefault(x => x.DefinedTypes.Contains(type));
// Get a type from its IL2CPP type index // 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 // Get or generate a type from its IL2CPP binary type usage reference
// (field, return type, generic type parameter etc.) // (field, return type, generic type parameter etc.)

View File

@@ -13,7 +13,7 @@ namespace Il2CppInspector.Reflection {
// IL2CPP-specific data // IL2CPP-specific data
public Il2CppFieldDefinition Definition { get; } public Il2CppFieldDefinition Definition { get; }
public int Index { get; } public int Index { get; }
public int Offset { get; } public long Offset { get; }
public bool HasDefaultValue { get; } public bool HasDefaultValue { get; }
public object DefaultValue { get; } public object DefaultValue { get; }

View File

@@ -15,7 +15,7 @@ namespace Il2CppInspector.Reflection
// IL2CPP-specific data // IL2CPP-specific data
public Il2CppMethodDefinition Definition { get; } public Il2CppMethodDefinition Definition { get; }
public int Index { get; } public int Index { get; }
public uint VirtualAddress { get; } public ulong VirtualAddress { get; }
public bool HasBody { get; } public bool HasBody { get; }
public override MemberTypes MemberType => MemberTypes.Method; public override MemberTypes MemberType => MemberTypes.Method;