Correctly process 64-bit data structures in IL2CPP binaries
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user