Add FieldRva MetadataUsage type and fix current heuristic
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Utils;
|
||||||
using NoisyCowStudios.Bin2Object;
|
using NoisyCowStudios.Bin2Object;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -184,70 +185,30 @@ namespace Il2CppInspector
|
|||||||
var encodedToken = (uint)metadataValue;
|
var encodedToken = (uint)metadataValue;
|
||||||
var usage = MetadataUsage.FromEncodedIndex(this, encodedToken);
|
var usage = MetadataUsage.FromEncodedIndex(this, encodedToken);
|
||||||
|
|
||||||
if (usage.Type > 0
|
if (CheckMetadataUsageSanity(usage)
|
||||||
&& usage.Type <= MetadataUsageType.MethodRef
|
|
||||||
&& metadataValue == (((uint)usage.Type << 29) | ((uint)usage.SourceIndex << 1)) + 1
|
|
||||||
&& BinaryImage.TryMapFileOffsetToVA(i * ((uint)BinaryImage.Bits / 8), out var va))
|
&& BinaryImage.TryMapFileOffsetToVA(i * ((uint)BinaryImage.Bits / 8), out var va))
|
||||||
{
|
{
|
||||||
usages.Add(MetadataUsage.FromEncodedIndex(this, encodedToken, va));
|
usage.SetAddress(va);
|
||||||
|
usages.Add(usage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return usages;
|
return usages;
|
||||||
|
|
||||||
/*BinaryImage.Position = 0;
|
bool CheckMetadataUsageSanity(MetadataUsage usage)
|
||||||
var sequenceLength = 0;
|
{
|
||||||
var threshold = 6000; // current versions of mscorlib generate about 6000-7000 metadata usages
|
return usage.Type switch
|
||||||
var usagesCount = 0;
|
{
|
||||||
|
MetadataUsageType.TypeInfo or MetadataUsageType.Type => TypeReferences.Count > usage.SourceIndex,
|
||||||
var words = BinaryImage.ReadArray<ulong>(0, (int) BinaryImage.Length / (BinaryImage.Bits / 8));
|
MetadataUsageType.MethodDef => Methods.Length > usage.SourceIndex,
|
||||||
|
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => FieldRefs.Length > usage.SourceIndex,
|
||||||
// Scan the image looking for a sequential block of at least 'threshold' valid metadata tokens
|
MetadataUsageType.StringLiteral => StringLiterals.Length > usage.SourceIndex,
|
||||||
int pos;
|
MetadataUsageType.MethodRef => MethodSpecs.Length > usage.SourceIndex,
|
||||||
for (pos = 0; pos < words.Length && (usagesCount == 0 || sequenceLength > 0); pos++) {
|
_ => false,
|
||||||
var word = words[pos];
|
};
|
||||||
|
|
||||||
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) (pos * wordSize - (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;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// Thumb instruction pointers have the bottom bit set to signify a switch from ARM to Thumb when jumping
|
// Thumb instruction pointers have the bottom bit set to signify a switch from ARM to Thumb when jumping
|
||||||
private ulong getDecodedAddress(ulong addr) {
|
private ulong getDecodedAddress(ulong addr) {
|
||||||
|
|||||||
@@ -1,56 +1,57 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2019-2020 Carter Bush - https://github.com/carterbush
|
Copyright (c) 2019-2020 Carter Bush - https://github.com/carterbush
|
||||||
Copyright (c) 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
Copyright (c) 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||||
Copyright 2020 Robert Xiao - https://robertxiao.ca
|
Copyright 2020 Robert Xiao - https://robertxiao.ca
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
public enum MetadataUsageType
|
public enum MetadataUsageType
|
||||||
{
|
{
|
||||||
TypeInfo = 1,
|
TypeInfo = 1,
|
||||||
Type = 2,
|
Type = 2,
|
||||||
MethodDef = 3,
|
MethodDef = 3,
|
||||||
FieldInfo = 4,
|
FieldInfo = 4,
|
||||||
StringLiteral = 5,
|
StringLiteral = 5,
|
||||||
MethodRef = 6,
|
MethodRef = 6,
|
||||||
}
|
FieldRva = 7
|
||||||
|
}
|
||||||
public class MetadataUsage
|
|
||||||
{
|
public class MetadataUsage
|
||||||
public MetadataUsageType Type { get; }
|
{
|
||||||
public int SourceIndex { get; }
|
public MetadataUsageType Type { get; }
|
||||||
public ulong VirtualAddress { get; private set; }
|
public int SourceIndex { get; }
|
||||||
|
public ulong VirtualAddress { get; private set; }
|
||||||
public MetadataUsage(MetadataUsageType type, int sourceIndex, ulong virtualAddress = 0) {
|
|
||||||
Type = type;
|
public MetadataUsage(MetadataUsageType type, int sourceIndex, ulong virtualAddress = 0) {
|
||||||
SourceIndex = sourceIndex;
|
Type = type;
|
||||||
VirtualAddress = virtualAddress;
|
SourceIndex = sourceIndex;
|
||||||
}
|
VirtualAddress = virtualAddress;
|
||||||
|
}
|
||||||
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) {
|
|
||||||
uint index;
|
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) {
|
||||||
MetadataUsageType usageType;
|
uint index;
|
||||||
if (package.Version < 19) {
|
MetadataUsageType usageType;
|
||||||
/* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */
|
if (package.Version < 19) {
|
||||||
var isGeneric = encodedIndex & 0x80000000;
|
/* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */
|
||||||
index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF];
|
var isGeneric = encodedIndex & 0x80000000;
|
||||||
usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef;
|
index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF];
|
||||||
} else {
|
usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef;
|
||||||
/* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */
|
} else {
|
||||||
var encodedType = encodedIndex & 0xE0000000;
|
/* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */
|
||||||
usageType = (MetadataUsageType)(encodedType >> 29);
|
var encodedType = encodedIndex & 0xE0000000;
|
||||||
index = encodedIndex & 0x1FFFFFFF;
|
usageType = (MetadataUsageType)(encodedType >> 29);
|
||||||
|
index = encodedIndex & 0x1FFFFFFF;
|
||||||
// From v27 the bottom bit is set to indicate the usage token hasn't been replaced with a pointer at runtime yet
|
|
||||||
if (package.Version >= 27)
|
// From v27 the bottom bit is set to indicate the usage token hasn't been replaced with a pointer at runtime yet
|
||||||
index >>= 1;
|
if (package.Version >= 27)
|
||||||
}
|
index >>= 1;
|
||||||
return new MetadataUsage(usageType, (int)index, virtualAddress);
|
}
|
||||||
}
|
return new MetadataUsage(usageType, (int)index, virtualAddress);
|
||||||
|
}
|
||||||
public void SetAddress(ulong virtualAddress) => VirtualAddress = virtualAddress;
|
|
||||||
}
|
public void SetAddress(ulong virtualAddress) => VirtualAddress = virtualAddress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -210,38 +210,28 @@ namespace Il2CppInspector.Model
|
|||||||
|
|
||||||
switch (usage.Type) {
|
switch (usage.Type) {
|
||||||
case MetadataUsageType.StringLiteral:
|
case MetadataUsageType.StringLiteral:
|
||||||
//if (usage.SourceIndex >= TypeModel.Package.Metadata.StringLiterals.Length)
|
|
||||||
// break;
|
|
||||||
|
|
||||||
var str = TypeModel.GetMetadataUsageName(usage);
|
var str = TypeModel.GetMetadataUsageName(usage);
|
||||||
Strings.Add(address, str);
|
Strings.Add(address, str);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MetadataUsageType.Type:
|
case MetadataUsageType.Type or MetadataUsageType.TypeInfo:
|
||||||
case MetadataUsageType.TypeInfo:
|
|
||||||
//if (usage.SourceIndex >= TypeModel.TypesByReferenceIndex.Length)
|
|
||||||
// break;
|
|
||||||
|
|
||||||
var type = TypeModel.GetMetadataUsageType(usage);
|
var type = TypeModel.GetMetadataUsageType(usage);
|
||||||
declarationGenerator.IncludeType(type);
|
declarationGenerator.IncludeType(type);
|
||||||
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
|
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
|
||||||
|
|
||||||
|
if (!Types.ContainsKey(type))
|
||||||
|
// Generic type definition has no associated C++ type, therefore no dictionary sub-key
|
||||||
|
Types.Add(type, new AppType(type, null) { Group = Group });
|
||||||
|
|
||||||
if (usage.Type == MetadataUsageType.TypeInfo)
|
if (usage.Type == MetadataUsageType.TypeInfo)
|
||||||
// Regular type definition
|
// Regular type definition
|
||||||
Types[type].TypeClassAddress = address;
|
Types[type].TypeClassAddress = address;
|
||||||
|
|
||||||
else if (!Types.ContainsKey(type))
|
|
||||||
// Generic type definition has no associated C++ type, therefore no dictionary sub-key
|
|
||||||
Types.Add(type, new AppType(type, null, cppTypeRefPtr: address) { Group = Group });
|
|
||||||
else
|
else
|
||||||
// Regular type reference
|
// Regular type reference
|
||||||
Types[type].TypeRefPtrAddress = address;
|
Types[type].TypeRefPtrAddress = address;
|
||||||
break;
|
|
||||||
case MetadataUsageType.MethodDef:
|
|
||||||
case MetadataUsageType.MethodRef:
|
|
||||||
//if (usage.SourceIndex > TypeModel.Package.Metadata.Methods.Length)
|
|
||||||
// break;
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef:
|
||||||
var method = TypeModel.GetMetadataUsageMethod(usage);
|
var method = TypeModel.GetMetadataUsageMethod(usage);
|
||||||
declarationGenerator.IncludeMethod(method);
|
declarationGenerator.IncludeMethod(method);
|
||||||
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
|
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
|
||||||
@@ -256,14 +246,18 @@ namespace Il2CppInspector.Model
|
|||||||
Methods[method].MethodInfoPtrAddress = address;
|
Methods[method].MethodInfoPtrAddress = address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MetadataUsageType.FieldInfo:
|
case MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva:
|
||||||
if (usage.SourceIndex > TypeModel.Package.Metadata.FieldRefs.Length)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var fieldRef = TypeModel.Package.FieldRefs[usage.SourceIndex];
|
var fieldRef = TypeModel.Package.FieldRefs[usage.SourceIndex];
|
||||||
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
||||||
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
||||||
Fields.Add(usage.VirtualAddress, $"{fieldType.Name}.{field.Name}".ToCIdentifier());
|
|
||||||
|
if (usage.Type == MetadataUsageType.FieldInfo)
|
||||||
|
Fields.Add(usage.VirtualAddress, $"{fieldType.Name}.{field.Name}".ToCIdentifier());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var defaultValue = Package.FieldDefaultValue[field.Index];
|
||||||
|
// TODO: Unsure what it could be used for here. Maybe PID array initializers?
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -344,18 +344,21 @@ namespace Il2CppInspector.Reflection
|
|||||||
type = GetMetadataUsageType(usage);
|
type = GetMetadataUsageType(usage);
|
||||||
method = GetMetadataUsageMethod(usage);
|
method = GetMetadataUsageMethod(usage);
|
||||||
return $"{type.Name}.{method.Name}";
|
return $"{type.Name}.{method.Name}";
|
||||||
|
|
||||||
|
case MetadataUsageType.FieldRva:
|
||||||
|
fieldRef = Package.FieldRefs[usage.SourceIndex];
|
||||||
|
type = GetMetadataUsageType(usage);
|
||||||
|
field = type.DeclaredFields.First(f => f.Index == type.Definition.fieldStart + fieldRef.fieldIndex);
|
||||||
|
return $"{type.Name}.{field.Name}_Default"; // TODO: Find out if this is really needed for anything
|
||||||
}
|
}
|
||||||
throw new NotImplementedException("Unknown metadata usage type: " + usage.Type);
|
throw new NotImplementedException("Unknown metadata usage type: " + usage.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the type used in a metadata usage
|
// Get the type used in a metadata usage
|
||||||
public TypeInfo GetMetadataUsageType(MetadataUsage usage) => usage.Type switch {
|
public TypeInfo GetMetadataUsageType(MetadataUsage usage) => usage.Type switch {
|
||||||
MetadataUsageType.Type => TypesByReferenceIndex[usage.SourceIndex],
|
MetadataUsageType.Type or MetadataUsageType.TypeInfo => TypesByReferenceIndex[usage.SourceIndex],
|
||||||
MetadataUsageType.TypeInfo => TypesByReferenceIndex[usage.SourceIndex],
|
MetadataUsageType.MethodDef or MetadataUsageType.MethodRef => GetMetadataUsageMethod(usage).DeclaringType,
|
||||||
MetadataUsageType.MethodDef => GetMetadataUsageMethod(usage).DeclaringType,
|
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => TypesByReferenceIndex[Package.FieldRefs[usage.SourceIndex].typeIndex],
|
||||||
MetadataUsageType.FieldInfo => TypesByReferenceIndex[Package.FieldRefs[usage.SourceIndex].typeIndex],
|
|
||||||
MetadataUsageType.MethodRef => GetMetadataUsageMethod(usage).DeclaringType,
|
|
||||||
|
|
||||||
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
|
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user