Add name mangling to Methods/MethodInfo/TypeInfo/TypeRef, remove Boxing from ValueTypes when used as the this parameter, fix crashes when a module has no attributes

This commit is contained in:
LukeFZ
2023-12-06 20:09:35 +01:00
parent e9434f4cad
commit 5b1d9c67d1
11 changed files with 335 additions and 119 deletions

View File

@@ -1,45 +1,50 @@
/*
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
All rights reserved.
*/
using Il2CppInspector.Cpp;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Model
{
// Class that represents a composite IL/C++ method
public class AppMethod
{
// The logical group this method is part of
// This is purely for querying methods in related groups and has no bearing on the code
public string Group { get; set; }
// The corresponding C++ function pointer type
public CppFnPtrType CppFnPtrType { get; internal set; }
// The corresponding .NET method
public MethodBase Method { get; internal set; }
// The VA of the MethodInfo* (VA of the pointer to the MethodInfo) object which defines this method
// Methods not referenced by the binary will be 0xffffffff_ffffffff
public ulong MethodInfoPtrAddress { get; internal set; }
// The VA of the method code itself
// Generic method definitions do not have a code address but may have a reference above
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff;
// Helpers
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff;
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0;
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) {
Method = method;
CppFnPtrType = cppMethod;
MethodInfoPtrAddress = methodInfoPtr;
}
public override string ToString() => CppFnPtrType.ToSignatureString();
}
}
/*
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
Copyright 2023 LukeFZ - https://github.com/LukeFZ
All rights reserved.
*/
using System.Diagnostics;
using Il2CppInspector.Cpp;
using Il2CppInspector.Reflection;
using System.Text;
namespace Il2CppInspector.Model
{
// Class that represents a composite IL/C++ method
public class AppMethod
{
// The logical group this method is part of
// This is purely for querying methods in related groups and has no bearing on the code
public string Group { get; set; }
// The corresponding C++ function pointer type
public CppFnPtrType CppFnPtrType { get; internal set; }
// The corresponding .NET method
public MethodBase Method { get; internal set; }
// The VA of the MethodInfo* (VA of the pointer to the MethodInfo) object which defines this method
// Methods not referenced by the binary will be 0xffffffff_ffffffff
public ulong MethodInfoPtrAddress { get; internal set; }
// The VA of the method code itself
// Generic method definitions do not have a code address but may have a reference above
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff;
// Helpers
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff;
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0;
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) {
Method = method;
CppFnPtrType = cppMethod;
MethodInfoPtrAddress = methodInfoPtr;
}
public override string ToString() => CppFnPtrType.ToSignatureString();
public string ToMangledString() => MangledNameBuilder.Method(Method);
public string ToMangledMethodInfoString() => MangledNameBuilder.MethodInfo(Method);
}
}

View File

@@ -51,8 +51,8 @@ namespace Il2CppInspector.Model
// For il2cpp < 19, the key is the string literal ordinal instead of the address
public Dictionary<ulong, string> Strings { get; } = [];
public Dictionary<ulong, (string Name, string Value)> Fields { get; } = [];
public Dictionary<ulong, (string Name, string Value)> FieldRvas { get; } = [];
public Dictionary<ulong, (FieldInfo Field, string Value)> Fields { get; } = [];
public Dictionary<ulong, (FieldInfo Field, string Value)> FieldRvas { get; } = [];
public bool StringIndexesAreOrdinals => Package.Version < 19;
@@ -254,10 +254,6 @@ namespace Il2CppInspector.Model
var fieldType = TypeModel.GetMetadataUsageType(usage);
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
var name = usage.Type == MetadataUsageType.FieldInfo
? $"{fieldType.Name}.{field.Name}".ToCIdentifier()
: $"{fieldType.Name}.{field.Name}_FieldRva".ToCIdentifier();
var value = field.HasFieldRVA
? Convert.ToHexString(Package.Metadata.ReadBytes(
(long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.nativeSize))
@@ -265,9 +261,9 @@ namespace Il2CppInspector.Model
if (usage.Type == MetadataUsageType.FieldInfo)
Fields[usage.VirtualAddress] = (name, value);
Fields[usage.VirtualAddress] = (field, value);
else
FieldRvas[usage.VirtualAddress] = (name, value);
FieldRvas[usage.VirtualAddress] = (field, value);
break;
}
@@ -345,11 +341,8 @@ namespace Il2CppInspector.Model
// Get the address map for the model
// This takes a while to construct so we only build it if requested
private AddressMap addressMap;
public AddressMap GetAddressMap() {
if (addressMap == null)
addressMap = new AddressMap(this);
return addressMap;
}
public AddressMap GetAddressMap()
=> addressMap ??= new AddressMap(this);
// Get the byte offset in Il2CppClass for this app's Unity version to the vtable
public int GetVTableOffset() => CppTypeCollection.GetComplexType("Il2CppClass")["vtable"].OffsetBytes;

View File

@@ -1,52 +1,56 @@
/*
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
All rights reserved.
*/
using Il2CppInspector.Cpp;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Model
{
// Class that represents a composite IL/C++ type
public class AppType
{
// The logical group this type is part of
// This is purely for querying types in related groups and has no bearing on the code
public string Group { get; set; }
// The corresponding C++ type definition which represents an instance of the object
// This is derived from Il2CppObject
// If the underlying .NET type is a struct (value type), this will return the boxed version
public CppComplexType CppType { get; internal set; }
// For an underlying .NET type which is a struct (value type), the unboxed type, otherwise null
public CppComplexType CppValueType { get; internal set; }
// The type in the .NET type model this object maps to
public TypeInfo Type { get; internal set; }
// The VA of the Il2CppClass object which defines this type (ClassName__TypeInfo)
public ulong TypeClassAddress { get; internal set; }
// The VA of the Il2CppType* (VA of the pointer to the Il2CppType) object which references this type (ClassName__TypeRef)
public ulong TypeRefPtrAddress { get; internal set; }
public AppType(TypeInfo ilType, CppComplexType cppType, CppComplexType valueType = null,
ulong cppClassPtr = 0xffffffff_ffffffff, ulong cppTypeRefPtr = 0xffffffff_ffffffff) {
CppType = cppType;
Type = ilType;
CppValueType = valueType;
TypeClassAddress = cppClassPtr;
TypeRefPtrAddress = cppTypeRefPtr;
}
// The C++ name of the type
// TODO: Known issue here where we should be using CppDeclarationGenerator.TypeNamer to ensure uniqueness
// Prefer Foo over Foo__Boxed; if there is no C++ type defined, just convert the IL type to a C identifier
public string Name => CppValueType?.Name ?? CppType?.Name ?? Type.Name.ToCIdentifier();
public override string ToString() => Type.FullName + " -> " + CppType.Name;
}
/*
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
All rights reserved.
*/
using Il2CppInspector.Cpp;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Model
{
// Class that represents a composite IL/C++ type
public class AppType
{
// The logical group this type is part of
// This is purely for querying types in related groups and has no bearing on the code
public string Group { get; set; }
// The corresponding C++ type definition which represents an instance of the object
// This is derived from Il2CppObject
// If the underlying .NET type is a struct (value type), this will return the boxed version
public CppComplexType CppType { get; internal set; }
// For an underlying .NET type which is a struct (value type), the unboxed type, otherwise null
public CppComplexType CppValueType { get; internal set; }
// The type in the .NET type model this object maps to
public TypeInfo Type { get; internal set; }
// The VA of the Il2CppClass object which defines this type (ClassName__TypeInfo)
public ulong TypeClassAddress { get; internal set; }
// The VA of the Il2CppType* (VA of the pointer to the Il2CppType) object which references this type (ClassName__TypeRef)
public ulong TypeRefPtrAddress { get; internal set; }
public AppType(TypeInfo ilType, CppComplexType cppType, CppComplexType valueType = null,
ulong cppClassPtr = 0xffffffff_ffffffff, ulong cppTypeRefPtr = 0xffffffff_ffffffff) {
CppType = cppType;
Type = ilType;
CppValueType = valueType;
TypeClassAddress = cppClassPtr;
TypeRefPtrAddress = cppTypeRefPtr;
}
// The C++ name of the type
// TODO: Known issue here where we should be using CppDeclarationGenerator.TypeNamer to ensure uniqueness
// Prefer Foo over Foo__Boxed; if there is no C++ type defined, just convert the IL type to a C identifier
public string Name => CppValueType?.Name ?? CppType?.Name ?? Type.Name.ToCIdentifier();
public override string ToString() => Type.FullName + " -> " + CppType.Name;
public string ToMangledTypeInfoString() => MangledNameBuilder.TypeInfo(Type);
public string ToMangledTypeRefString() => MangledNameBuilder.TypeRef(Type);
}
}