Model: Ensure all TypeRefs are initialized with the model

Ensures that all types are output in the IDA Python script
Includes TypeRefs that aren't used in any type definition or member
This commit is contained in:
Katy Coe
2020-01-30 07:54:45 +01:00
parent a1e332620c
commit 37f1c49828
7 changed files with 96 additions and 92 deletions

View File

@@ -17,20 +17,20 @@ namespace Il2CppInspector.Reflection
public Il2CppInspector Package { get; }
public List<Assembly> Assemblies { get; } = new List<Assembly>();
// List of all types ordered by their TypeDefinitionIndex
// List of all types from TypeDefs ordered by their TypeDefinitionIndex
public TypeInfo[] TypesByDefinitionIndex { get; }
// List of all type definitions by fully qualified name
// List of all types from TypeRefs ordered by index
public TypeInfo[] TypesByReferenceIndex { get; }
// List of all type definitions by fully qualified name (TypeDefs only)
public Dictionary<string, TypeInfo> TypesByFullName { get; } = new Dictionary<string, TypeInfo>();
// List of all type references ordered by index
public TypeInfo[] TypeReferences { get; }
// List of type usages that are initialized via pointers in the image
// List of type references that are initialized via pointers in the image
public ConcurrentDictionary<ulong, TypeInfo> TypesByVirtualAddress { get; } = new ConcurrentDictionary<ulong, TypeInfo>();
// Every type
public IEnumerable<TypeInfo> Types => new IEnumerable<TypeInfo>[] {TypesByDefinitionIndex, TypeReferences, TypesByVirtualAddress.Values}.SelectMany(t => t);
public IEnumerable<TypeInfo> Types => new IEnumerable<TypeInfo>[] {TypesByDefinitionIndex, TypesByReferenceIndex, TypesByVirtualAddress.Values}.SelectMany(t => t);
// List of all methods ordered by their MethodDefinitionIndex
public MethodBase[] MethodsByDefinitionIndex { get; }
@@ -38,67 +38,66 @@ namespace Il2CppInspector.Reflection
// List of all generated CustomAttributeData objects by their index into AttributeTypeIndices
public ConcurrentDictionary<int, CustomAttributeData> AttributesByIndices { get; } = new ConcurrentDictionary<int, CustomAttributeData>();
public Il2CppModel(Il2CppInspector package) {
Package = package;
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
TypeReferences = new TypeInfo[package.TypeReferences.Count];
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
// Create Assembly objects from Il2Cpp package
for (var image = 0; image < package.Images.Length; image++)
Assemblies.Add(new Assembly(this, image));
}
// Get an assembly by its image name
public Assembly GetAssembly(string name) => Assemblies.FirstOrDefault(a => a.ShortName == name);
private TypeInfo getNewTypeUsage(Il2CppType usage, MemberTypes memberType) {
// Create type model
public Il2CppModel(Il2CppInspector package) {
Package = package;
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
// Recursively create hierarchy of assemblies and types from TypeDefs
// No code that executes here can access any type through a TypeRef (ie. via TypesByReferenceIndex)
for (var image = 0; image < package.Images.Length; image++)
Assemblies.Add(new Assembly(this, image));
// Create and reference types from TypeRefs
// Note that you can't resolve any TypeRefs until all the TypeDefs have been processed
for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) {
var typeRef = Package.TypeReferences[typeRefIndex];
var referencedType = resolveTypeReference(typeRef);
TypesByReferenceIndex[typeRefIndex] = referencedType;
}
}
private TypeInfo resolveTypeReference(Il2CppType typeRef) {
TypeInfo underlyingType;
switch (usage.type) {
switch (typeRef.type) {
// Classes defined in the metadata (reference to a TypeDef)
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
// Classes defined in the metadata
underlyingType = TypesByDefinitionIndex[usage.datapoint]; // klassIndex
underlyingType = TypesByDefinitionIndex[typeRef.datapoint]; // klassIndex
break;
// Constructed types
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
// Generic type and generic method parameters
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
// Everything that requires special handling
underlyingType = new TypeInfo(this, usage, memberType);
underlyingType = new TypeInfo(this, typeRef);
break;
// Primitive types
default:
// Primitive types
underlyingType = GetTypeFromTypeEnum(usage.type);
underlyingType = getTypeDefinitionFromTypeEnum(typeRef.type);
break;
}
// Create a reference type if necessary
return usage.byref ? underlyingType.MakeByRefType() : underlyingType;
return typeRef.byref ? underlyingType.MakeByRefType() : underlyingType;
}
// Get or generate a type from its IL2CPP binary type usage reference
// (field, return type, generic type parameter etc.)
public TypeInfo GetTypeFromUsage(int typeUsageIndex, MemberTypes memberType = MemberTypes.All) {
// Already generated type previously?
if (TypeReferences[typeUsageIndex] != null)
return TypeReferences[typeUsageIndex];
var usage = Package.TypeReferences[typeUsageIndex];
var newUsage = getNewTypeUsage(usage, memberType);
TypeReferences[typeUsageIndex] = newUsage;
return newUsage;
}
// Basic primitive types
public TypeInfo GetTypeFromTypeEnum(Il2CppTypeEnum t) {
// Basic primitive types are specified via a flag value
private TypeInfo getTypeDefinitionFromTypeEnum(Il2CppTypeEnum t) {
if ((int) t >= Il2CppConstants.FullNameTypeString.Count)
return null;
@@ -107,16 +106,17 @@ namespace Il2CppInspector.Reflection
}
// Type from a virtual address pointer
// These are always nested types frorm usages within another type
// These are always nested types from references within another TypeRef
// TODO: Eliminate GetTypeFromVirtualAddress() - use base and offset from MetadataRegistration.ptypes (Package.TypeReferences) instead
public TypeInfo GetTypeFromVirtualAddress(ulong ptr) {
if (TypesByVirtualAddress.ContainsKey(ptr))
return TypesByVirtualAddress[ptr];
var type = Package.BinaryImage.ReadMappedObject<Il2CppType>(ptr);
var newUsage = getNewTypeUsage(type, MemberTypes.NestedType);
var referencedType = resolveTypeReference(type);
TypesByVirtualAddress.TryAdd(ptr, newUsage);
return newUsage;
TypesByVirtualAddress.TryAdd(ptr, referencedType);
return referencedType;
}
// The attribute index is an index into AttributeTypeRanges, each of which is a start-end range index into AttributeTypeIndices, each of which is a TypeIndex
@@ -131,12 +131,12 @@ namespace Il2CppInspector.Reflection
return index;
}
// Get the name of a metadata usage
// Get the name of a metadata typeRef
public string GetMetadataUsageName(MetadataUsage usage) {
switch (usage.Type) {
case MetadataUsageType.TypeInfo:
case MetadataUsageType.Type:
var type = GetTypeFromUsage(usage.SourceIndex);
var type = TypesByReferenceIndex[usage.SourceIndex];
return type.Name;
case MetadataUsageType.MethodDef:
@@ -145,7 +145,7 @@ namespace Il2CppInspector.Reflection
case MetadataUsageType.FieldInfo:
var fieldRef = Package.FieldRefs[usage.SourceIndex];
type = GetTypeFromUsage(fieldRef.typeIndex);
type = TypesByReferenceIndex[fieldRef.typeIndex];
var field = type.DeclaredFields.First(f => f.Index == type.Definition.fieldStart + fieldRef.fieldIndex);
return $"{type.Name}.{field.Name}";