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);
}
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<string, uint>();
var m = new Dictionary<string, ulong>();
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");
}

View File

@@ -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<Il2CppType> 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<Il2CppCodeRegistration>(codeRegistration);
MetadataRegistration = image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
// The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule
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
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<int>(MetadataRegistration.pfieldOffsets, MetadataRegistration.fieldOffsetsCount);
FieldOffsetData = image.ReadMappedArray<long>(MetadataRegistration.pfieldOffsets, (int) MetadataRegistration.fieldOffsetsCount);
// 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
[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;
}
}

View File

@@ -32,10 +32,10 @@ namespace Il2CppInspector
public Il2CppEventDefinition[] Events => Metadata.Events;
public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices;
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 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
public IFileFormatReader BinaryImage => Binary.Image;
@@ -129,15 +129,15 @@ namespace Il2CppInspector
}
// Convert pointer list into fields
else {
var offsets = new Dictionary<int, int>();
var offsets = new Dictionary<int, long>();
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<long>());
}
}

View File

@@ -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.)

View File

@@ -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; }

View File

@@ -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;