From d426dad820d05aac726814a32466b326d7eaa44f Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Tue, 7 Apr 2020 05:05:21 -0700 Subject: [PATCH] Add support for parsing and interpreting VTables This prepares for a future PR where we add types to the IDA script output. --- Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs | 7 +++++++ .../IL2CPP/Il2CppInspector.cs | 21 +++++++++++++++++++ Il2CppInspector.Common/Reflection/TypeInfo.cs | 12 +++++++++++ 3 files changed, 40 insertions(+) diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs index cee808a..b4a1662 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs @@ -53,6 +53,9 @@ namespace Il2CppInspector // One invoker specifies a return type and argument list. Multiple methods with the same signature can be invoked with the same invoker public ulong[] MethodInvokePointers { get; private set; } + // Version 16 and below: method references for vtable + public uint[] VTableMethodReferences { get; private set; } + // Generic method specs for vtables public Il2CppMethodSpec[] MethodSpecs { get; private set; } @@ -245,6 +248,10 @@ namespace Il2CppInspector // >=22: unresolvedVirtualCallPointers // >=23: interopData + if (Image.Version < 19) { + VTableMethodReferences = image.ReadMappedArray(MetadataRegistration.methodReferences, (int)MetadataRegistration.methodReferencesCount); + } + // Generic type and method specs (open and closed constructed types) MethodSpecs = image.ReadMappedArray(MetadataRegistration.methodSpecs, (int) MetadataRegistration.methodSpecsCount); diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs index 46f23cc..a86b71a 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs @@ -294,6 +294,27 @@ namespace Il2CppInspector return Binary.MethodInvokerIndices[module][methodInModule - 1]; } + public MetadataUsage[] GetVTable(Il2CppTypeDefinition definition) { + MetadataUsage[] res = new MetadataUsage[definition.vtable_count]; + for (int i = 0; i < definition.vtable_count; i++) { + var encodedIndex = VTableMethodIndices[definition.vtableStart + i]; + uint index; + MetadataUsageType usageType; + if (Version < 19) { + var flag = encodedIndex & 0x80000000; + index = Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF]; + usageType = (flag != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef; + } else { + var encodedType = encodedIndex & 0xE0000000; + usageType = (MetadataUsageType)(encodedType >> 29); + index = encodedIndex & 0x1FFFFFFF; + } + if (index != 0) + res[i] = new MetadataUsage(usageType, (int)index, i); + } + return res; + } + public static List LoadFromFile(string codeFile, string metadataFile) { // Load the metadata file Metadata metadata; diff --git a/Il2CppInspector.Common/Reflection/TypeInfo.cs b/Il2CppInspector.Common/Reflection/TypeInfo.cs index dfa5186..79a7628 100644 --- a/Il2CppInspector.Common/Reflection/TypeInfo.cs +++ b/Il2CppInspector.Common/Reflection/TypeInfo.cs @@ -133,6 +133,18 @@ namespace Il2CppInspector.Reflection { // Get a property by its name public PropertyInfo GetProperty(string name) => DeclaredProperties.FirstOrDefault(p => p.Name == name); + public MethodBase[] GetVTable() { + var definition = Definition; + + MetadataUsage[] vt = Assembly.Model.Package.GetVTable(definition); + MethodBase[] res = new MethodBase[vt.Length]; + for (int i = 0; i < vt.Length; i++) { + if (vt[i] != null) + res[i] = Assembly.Model.GetMetadataUsageMethod(vt[i]); + } + return res; + } + // Method that the type is declared in if this is a type parameter of a generic method // TODO: Make a unit test from this: https://docs.microsoft.com/en-us/dotnet/api/system.type.declaringmethod?view=netframework-4.8 public MethodBase DeclaringMethod;