diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs index 36d4c6f..631c4e7 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs @@ -158,8 +158,59 @@ namespace Il2CppInspector return usages.Values.ToList(); } - public List buildLateBindingMetadataUsages() { - // TODO: Resolve late binding for metadata v27 + public List buildLateBindingMetadataUsages() + { + // plagiarism. noun - https://www.lexico.com/en/definition/plagiarism + // the practice of taking someone else's work or ideas and passing them off as one's own. + // Synonyms: copying, piracy, theft, strealing, infringement of copyright + + BinaryImage.Position = 0; + var sequenceLength = 0; + var threshold = 6000; // current versions of mscorlib generate about 6000-7000 metadata usages + var usagesCount = 0; + + // Scan the image looking for a sequential block of at least 'threshold' valid metadata tokens + while (BinaryImage.Position < BinaryImage.Length && (usagesCount == 0 || sequenceLength > 0)) { + var word = BinaryImage.ReadWord(); + + if (word % 2 != 1 || word >> 32 != 0) { + sequenceLength = 0; + continue; + } + + var potentialUsage = MetadataUsage.FromEncodedIndex(this, (uint) word); + switch (potentialUsage.Type) { + case MetadataUsageType.Type: + case MetadataUsageType.TypeInfo: + case MetadataUsageType.MethodDef: + case MetadataUsageType.MethodRef: + case MetadataUsageType.FieldInfo: + case MetadataUsageType.StringLiteral: + sequenceLength++; + + if (sequenceLength >= threshold) + usagesCount = sequenceLength; + break; + default: + sequenceLength = 0; + break; + } + } + + // If we found a block, read all the tokens and map them with their VAs to MetadataUsage objects + if (usagesCount > 0) { + var wordSize = BinaryImage.Bits / 8; + var pMetadataUsages = (uint) (BinaryImage.Position - (usagesCount + 1) * wordSize); + var pMetadataUsagesVA = BinaryImage.MapFileOffsetToVA(pMetadataUsages); + var usageTokens = BinaryImage.ReadWordArray(pMetadataUsages, usagesCount); + var usages = usageTokens.Zip(Enumerable.Range(0, usagesCount) + .Select(a => pMetadataUsagesVA + (ulong) (a * wordSize)), (t, a) => MetadataUsage.FromEncodedIndex(this, (uint) t, a)); + + Console.WriteLine("Late binding metadata usage block found successfully for metadata v27"); + return usages.ToList(); + } + + Console.WriteLine("Late binding metadata usage block could not be auto-detected - metadata usage references will not be available for this project"); return null; } diff --git a/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs b/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs index 7b1bb7f..bfca78a 100644 --- a/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs +++ b/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs @@ -24,12 +24,13 @@ namespace Il2CppInspector public int SourceIndex { get; } public ulong VirtualAddress { get; private set; } - public MetadataUsage(MetadataUsageType type, int sourceIndex) { + public MetadataUsage(MetadataUsageType type, int sourceIndex, ulong virtualAddress = 0) { Type = type; SourceIndex = sourceIndex; + VirtualAddress = virtualAddress; } - public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex) { + public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) { uint index; MetadataUsageType usageType; if (package.Version < 19) { @@ -47,7 +48,7 @@ namespace Il2CppInspector if (package.Version >= 27) index >>= 1; } - return new MetadataUsage(usageType, (int)index); + return new MetadataUsage(usageType, (int)index, virtualAddress); } public void SetAddress(ulong virtualAddress) => VirtualAddress = virtualAddress;