Skip to content

Commit

Permalink
Finish fully implementing v29 restoration
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Byass committed Oct 27, 2021
1 parent c37aea7 commit 6d7c048
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 34 deletions.
1 change: 1 addition & 0 deletions Cpp2IL.Core/AssemblyPopulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ private static void ProcessPropertiesInType(Il2CppTypeDefinition cppTypeDefiniti
ilTypeDefinition.Properties.Add(propertyDefinition);

SharedState.UnmanagedToManagedProperties[propertyDef] = propertyDefinition;
SharedState.ManagedToUnmanagedProperties[propertyDefinition] = propertyDef;
}
}

Expand Down
128 changes: 114 additions & 14 deletions Cpp2IL.Core/AttributeRestorerPost29.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,47 @@ private static void RestoreAttributesInType(Il2CppImageDefinition imageDef, Type
var typeDef = SharedState.ManagedToUnmanagedTypes[typeDefinition];

//Apply custom attributes to type itself
GetCustomAttributesByAttributeIndex(imageDef, typeDefinition.Module, typeDef.customAttributeIndex, typeDef.token, typeDef.FullName!)
GetCustomAttributesByAttributeIndex(imageDef, typeDefinition.Module, typeDef.token)
.ForEach(attribute => typeDefinition.CustomAttributes.Add(attribute));

//Apply custom attributes to fields
foreach (var fieldDef in typeDef.Fields!)
{
var fieldDefinition = SharedState.UnmanagedToManagedFields[fieldDef];

GetCustomAttributesByAttributeIndex(imageDef, typeDefinition.Module, fieldDef.token)
.ForEach(attribute => fieldDefinition.CustomAttributes.Add(attribute));
}

//Apply custom attributes to methods
foreach (var methodDef in typeDef.Methods!)
{
var methodDefinition = methodDef.AsManaged();

GetCustomAttributesByAttributeIndex(imageDef, typeDefinition.Module, methodDef.token)
.ForEach(attribute => methodDefinition.CustomAttributes.Add(attribute));
}

//Apply custom attributes to properties
foreach (var propertyDef in typeDef.Properties!)
{
var propertyDefinition = SharedState.UnmanagedToManagedProperties[propertyDef];

GetCustomAttributesByAttributeIndex(imageDef, typeDefinition.Module, propertyDef.token)
.ForEach(attribute => propertyDefinition.CustomAttributes.Add(attribute));
}

//Nested Types
foreach (var nestedType in typeDefinition.NestedTypes)
{
RestoreAttributesInType(imageDef, nestedType);
}
}

public static List<CustomAttribute> GetCustomAttributesByAttributeIndex(Il2CppImageDefinition imageDef, ModuleDefinition moduleDefinition, int attributeIndex, uint token, string warningName)
public static List<CustomAttribute> GetCustomAttributesByAttributeIndex(Il2CppImageDefinition imageDef, ModuleDefinition moduleDefinition, uint token)
{
var ret = new List<CustomAttribute>();

//Search attribute data ranges for one with matching token
var target = new Il2CppCustomAttributeDataRange() { token = token };
var customAttributeIndex = LibCpp2IlMain.TheMetadata!.AttributeDataRanges.BinarySearch(imageDef.customAttributeStart, (int)imageDef.customAttributeCount, target, new TokenComparer());
Expand All @@ -47,7 +80,7 @@ public static List<CustomAttribute> GetCustomAttributesByAttributeIndex(Il2CppIm
var end = LibCpp2IlMain.TheMetadata.metadataHeader.attributeDataOffset + next.startOffset;

//Now we start actually reading. Start is a pointer to the address in the metadata file where the attribute data is.

//Read attribute count as compressed uint
var attributeCount = LibCpp2IlMain.TheMetadata.ReadUnityCompressedUIntAtRawAddr(start, out var countBytes);

Expand Down Expand Up @@ -104,10 +137,9 @@ private static CustomAttribute ReadAndCreateCustomAttribute(ModuleDefinition mod
bytesRead += ctorArgBytesRead;
pos += ctorArgBytesRead;

if (typeReference.IsArray)
if (typeReference.IsArray && val is Array arr)
{
Logger.WarnNewline($"Failed to parse custom attribute {constructor.DeclaringType!.FullName} due to an array type");
return MakeFallbackAttribute(module, constructor.AsManaged());
val = (from object? o in arr select new CustomAttributeArgument(Utils.TryLookupTypeDefKnownNotGeneric(o.GetType().FullName), o)).ToArray();
}

ret.ConstructorArguments.Add(new CustomAttributeArgument(typeReference, val));
Expand All @@ -119,6 +151,35 @@ private static CustomAttribute ReadAndCreateCustomAttribute(ModuleDefinition mod
var val = ReadBlob(pos, out var fieldBytesRead, out var typeReference);
bytesRead += fieldBytesRead;
pos += fieldBytesRead;

FieldDefinition field;

var fieldIndex = LibCpp2IlMain.TheMetadata.ReadUnityCompressedIntAtRawAddr(pos, out var fieldIdxBytesRead);
bytesRead += fieldIdxBytesRead;
pos += fieldIdxBytesRead;

if (fieldIndex < 0)
{
var typeIndex = LibCpp2IlMain.TheMetadata.ReadUnityCompressedUIntAtRawAddr(pos, out var typeIdxBytesRead);
bytesRead += typeIdxBytesRead;
pos += typeIdxBytesRead;

fieldIndex = -(fieldIndex + 1);

var declaringType = LibCpp2IlMain.TheMetadata.typeDefs[typeIndex];
field = declaringType!.Fields![fieldIndex].AsManaged();
}
else
{
field = constructor.DeclaringType!.Fields![fieldIndex].AsManaged();
}

if (typeReference.IsArray && val is Array arr)
{
val = (from object? o in arr select new CustomAttributeArgument(Utils.TryLookupTypeDefKnownNotGeneric(o.GetType().FullName), o)).ToArray();
}

ret.Fields.Add(new(field.Name, new(typeReference, val)));
}

//Read n props
Expand All @@ -127,6 +188,35 @@ private static CustomAttribute ReadAndCreateCustomAttribute(ModuleDefinition mod
var val = ReadBlob(pos, out var propBytesRead, out var typeReference);
bytesRead += propBytesRead;
pos += propBytesRead;

PropertyDefinition prop;

var propIndex = LibCpp2IlMain.TheMetadata.ReadUnityCompressedIntAtRawAddr(pos, out var propIdxBytesRead);
bytesRead += propIdxBytesRead;
pos += propIdxBytesRead;

if (propIndex < 0)
{
var typeIndex = LibCpp2IlMain.TheMetadata.ReadUnityCompressedUIntAtRawAddr(pos, out var typeIdxBytesRead);
bytesRead += typeIdxBytesRead;
pos += typeIdxBytesRead;

propIndex = -(propIndex + 1);

var declaringType = LibCpp2IlMain.TheMetadata.typeDefs[typeIndex];
prop = declaringType!.Properties![propIndex].AsManaged();
}
else
{
prop = constructor.DeclaringType!.Properties![propIndex].AsManaged();
}

if (typeReference.IsArray && val is Array arr)
{
val = (from object? o in arr select new CustomAttributeArgument(Utils.TryLookupTypeDefKnownNotGeneric(o.GetType().FullName), o)).ToArray();
}

ret.Properties.Add(new(prop.Name, new(typeReference, val)));
}

return ret;
Expand Down Expand Up @@ -161,7 +251,7 @@ private static CustomAttribute MakeFallbackAttribute(ModuleDefinition module, Me
private static object? ReadBlob(long pos, out int bytesRead, out TypeReference typeReference)
{
bytesRead = 0;

var type = ReadBlobType(pos, out var typeBytesRead, out typeReference);
bytesRead += typeBytesRead;
pos += typeBytesRead;
Expand Down Expand Up @@ -236,9 +326,17 @@ private static CustomAttribute MakeFallbackAttribute(ModuleDefinition module, Me
var strLength = md.ReadUnityCompressedIntAtRawAddr(pos, out var stringLenBytesRead);
bytesRead += stringLenBytesRead;
pos += stringLenBytesRead;

ret = Encoding.UTF8.GetString(md.ReadByteArrayAtRawAddress(pos, strLength));
bytesRead += strLength;

if (strLength > 0)
{
ret = Encoding.UTF8.GetString(md.ReadByteArrayAtRawAddress(pos, strLength));
bytesRead += strLength;
}
else
{
ret = null;
}

break;
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
var arrLength = md.ReadUnityCompressedIntAtRawAddr(pos, out var arrayLenBytesRead);
Expand Down Expand Up @@ -288,7 +386,7 @@ private static CustomAttribute MakeFallbackAttribute(ModuleDefinition module, Me
var arrElem = ReadBlobValue(pos, thisElementType, out var elemBytesRead, out _);
bytesRead += elemBytesRead;
pos += elemBytesRead;

//Set in the array
resultArray.SetValue(arrElem, i);
}
Expand Down Expand Up @@ -317,6 +415,7 @@ private static CustomAttribute MakeFallbackAttribute(ModuleDefinition module, Me
if (ret == null)
throw new($"Failed to resolve type reflection data for type index {typeIndex}");
}

break;
default:
throw new ArgumentOutOfRangeException();
Expand All @@ -331,7 +430,7 @@ private static Il2CppTypeEnum ReadBlobType(long pos, out int bytesRead, out Type
var ret = (Il2CppTypeEnum)LibCpp2IlMain.TheMetadata!.ReadClassAtRawAddr<byte>(pos);
pos += 1;
bytesRead += 1;

if (ret == Il2CppTypeEnum.IL2CPP_TYPE_ENUM)
{
var enumTypeIndex = LibCpp2IlMain.TheMetadata.ReadUnityCompressedIntAtRawAddr(pos, out var compressedBytesRead);
Expand All @@ -341,7 +440,8 @@ private static Il2CppTypeEnum ReadBlobType(long pos, out int bytesRead, out Type
var typeDef = LibCpp2IlReflection.GetTypeDefinitionByTypeIndex(enumTypeIndex)!;
type = typeDef.AsManaged(); //Get enum type
ret = LibCpp2IlMain.Binary!.GetType(typeDef.elementTypeIndex).type; //Get enum underlying type's type enum
} else if (ret == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
}
else if (ret == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
type = Utils.ArrayReference;
}
Expand Down
5 changes: 3 additions & 2 deletions Cpp2IL.Core/Cpp2IlApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,12 @@ public static void RunAttributeRestorationForAllAssemblies(BaseKeyFunctionAddres

enumerable.Select(def =>
{
if(!parallel)
if(!parallel && LibCpp2IlMain.MetadataVersion < 29)
Logger.Verbose($"Processing {def.Name.Name}...");
RunAttributeRestorationForAssembly(def, keyFunctionAddresses);

Logger.VerboseNewline($"Finished processing {def.Name.Name}");
if(LibCpp2IlMain.MetadataVersion < 29)
Logger.VerboseNewline($"Finished processing {def.Name.Name}");
return true;
}).ToList(); //Force full evaluation
}
Expand Down
18 changes: 18 additions & 0 deletions Cpp2IL.Core/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,24 @@ public static T[] SubArray<T>(this T[] source, Range range)

return SharedState.ManagedToUnmanagedTypes[managed];
}

[return: NotNullIfNotNull("unmanaged")]
public static PropertyDefinition? AsManaged(this Il2CppPropertyDefinition? unmanaged)
{
if (unmanaged == null)
return null;

return SharedState.UnmanagedToManagedProperties[unmanaged];
}

[return: NotNullIfNotNull("managed")]
public static Il2CppPropertyDefinition? AsUnmanaged(this PropertyDefinition? managed)
{
if (managed == null)
return null;

return SharedState.ManagedToUnmanagedProperties[managed];
}

[return: NotNullIfNotNull("unmanaged")]
public static TypeDefinition? AsManaged(this Il2CppTypeDefinition? unmanaged)
Expand Down
35 changes: 18 additions & 17 deletions Cpp2IL.Core/SharedState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,37 @@ namespace Cpp2IL.Core
public static class SharedState
{
//Virt methods
internal static readonly Dictionary<ushort, MethodDefinition> VirtualMethodsBySlot = new Dictionary<ushort, MethodDefinition>();
internal static readonly Dictionary<ushort, MethodDefinition> VirtualMethodsBySlot = new();

//Methods
internal static readonly ConcurrentDictionary<ulong, MethodDefinition> MethodsByAddress = new ConcurrentDictionary<ulong, MethodDefinition>();
internal static readonly ConcurrentDictionary<long, MethodDefinition> MethodsByIndex = new ConcurrentDictionary<long, MethodDefinition>();
internal static readonly ConcurrentDictionary<Il2CppMethodDefinition, MethodDefinition> UnmanagedToManagedMethods = new ConcurrentDictionary<Il2CppMethodDefinition, MethodDefinition>();
internal static readonly ConcurrentDictionary<MethodDefinition, Il2CppMethodDefinition> ManagedToUnmanagedMethods = new ConcurrentDictionary<MethodDefinition, Il2CppMethodDefinition>();
internal static readonly ConcurrentDictionary<ulong, MethodDefinition> MethodsByAddress = new();
internal static readonly ConcurrentDictionary<long, MethodDefinition> MethodsByIndex = new();
internal static readonly ConcurrentDictionary<Il2CppMethodDefinition, MethodDefinition> UnmanagedToManagedMethods = new();
internal static readonly ConcurrentDictionary<MethodDefinition, Il2CppMethodDefinition> ManagedToUnmanagedMethods = new();

//Generic params
internal static readonly Dictionary<long, GenericParameter> GenericParamsByIndex = new Dictionary<long, GenericParameter>();
internal static readonly Dictionary<long, GenericParameter> GenericParamsByIndex = new();

//Type defs
internal static readonly ConcurrentDictionary<long, TypeDefinition> TypeDefsByIndex = new ConcurrentDictionary<long, TypeDefinition>();
internal static readonly List<TypeDefinition> AllTypeDefinitions = new List<TypeDefinition>();
internal static readonly ConcurrentDictionary<TypeDefinition, Il2CppTypeDefinition> ManagedToUnmanagedTypes = new ConcurrentDictionary<TypeDefinition, Il2CppTypeDefinition>();
internal static readonly ConcurrentDictionary<Il2CppTypeDefinition, TypeDefinition> UnmanagedToManagedTypes = new ConcurrentDictionary<Il2CppTypeDefinition, TypeDefinition>();
internal static readonly ConcurrentDictionary<long, TypeDefinition> TypeDefsByIndex = new();
internal static readonly List<TypeDefinition> AllTypeDefinitions = new();
internal static readonly ConcurrentDictionary<TypeDefinition, Il2CppTypeDefinition> ManagedToUnmanagedTypes = new();
internal static readonly ConcurrentDictionary<Il2CppTypeDefinition, TypeDefinition> UnmanagedToManagedTypes = new();

internal static readonly Dictionary<Il2CppTypeDefinition, Il2CppTypeDefinition> ConcreteImplementations = new Dictionary<Il2CppTypeDefinition, Il2CppTypeDefinition>();
internal static readonly Dictionary<Il2CppTypeDefinition, Il2CppTypeDefinition> ConcreteImplementations = new();

//Fields
internal static readonly ConcurrentDictionary<Il2CppFieldDefinition, FieldDefinition> UnmanagedToManagedFields = new ConcurrentDictionary<Il2CppFieldDefinition, FieldDefinition>();
internal static readonly ConcurrentDictionary<FieldDefinition, Il2CppFieldDefinition> ManagedToUnmanagedFields = new ConcurrentDictionary<FieldDefinition, Il2CppFieldDefinition>();
internal static readonly ConcurrentDictionary<TypeDefinition, List<FieldInType>> FieldsByType = new ConcurrentDictionary<TypeDefinition, List<FieldInType>>();
internal static readonly ConcurrentDictionary<Il2CppFieldDefinition, FieldDefinition> UnmanagedToManagedFields = new();
internal static readonly ConcurrentDictionary<FieldDefinition, Il2CppFieldDefinition> ManagedToUnmanagedFields = new();
internal static readonly ConcurrentDictionary<TypeDefinition, List<FieldInType>> FieldsByType = new();

//Properties
internal static readonly ConcurrentDictionary<Il2CppPropertyDefinition, PropertyDefinition> UnmanagedToManagedProperties = new ConcurrentDictionary<Il2CppPropertyDefinition, PropertyDefinition>();
internal static readonly ConcurrentDictionary<Il2CppPropertyDefinition, PropertyDefinition> UnmanagedToManagedProperties = new();
internal static readonly ConcurrentDictionary<PropertyDefinition, Il2CppPropertyDefinition> ManagedToUnmanagedProperties = new();

//Assemblies
internal static readonly List<AssemblyDefinition> AssemblyList = new List<AssemblyDefinition>();
internal static readonly Dictionary<AssemblyDefinition, Il2CppImageDefinition> ManagedToUnmanagedAssemblies = new Dictionary<AssemblyDefinition, Il2CppImageDefinition>();
internal static readonly List<AssemblyDefinition> AssemblyList = new();
internal static readonly Dictionary<AssemblyDefinition, Il2CppImageDefinition> ManagedToUnmanagedAssemblies = new();

internal static HashSet<ulong> AttributeGeneratorStarts = new();

Expand Down
2 changes: 1 addition & 1 deletion Cpp2IL/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public static int MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs)
// if(LibCpp2IlMain.MetadataVersion >= 29)
// Logger.WarnNewline("Unable to run attribute restoration, because v29 is not fully supported yet.");
// else
Cpp2IlApi.RunAttributeRestorationForAllAssemblies(keyFunctionAddresses, parallel: LibCpp2IlMain.Binary!.InstructionSet is InstructionSet.X86_32 or InstructionSet.X86_64);
Cpp2IlApi.RunAttributeRestorationForAllAssemblies(keyFunctionAddresses, parallel: LibCpp2IlMain.MetadataVersion >= 29 || LibCpp2IlMain.Binary!.InstructionSet is InstructionSet.X86_32 or InstructionSet.X86_64);

Logger.InfoNewline($"Finished Applying Attributes in {(DateTime.Now - start).TotalMilliseconds:F0}ms");

Expand Down
2 changes: 2 additions & 0 deletions LibCpp2IL/Metadata/Il2CppPropertyDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class Il2CppPropertyDefinition
public uint token;

[NonSerialized] private Il2CppTypeDefinition? _type;

public int PropertyIndex => LibCpp2IlReflection.GetPropertyIndexFromProperty(this);

public Il2CppTypeDefinition? DeclaringType
{
Expand Down
Loading

0 comments on commit 6d7c048

Please sign in to comment.