From 9a63bf733c545960b92fb9e0bb4dd3c65e6d78da Mon Sep 17 00:00:00 2001 From: Jeremy Pritts <49847914+ds5678@users.noreply.github.com> Date: Wed, 27 Dec 2023 23:18:13 -0500 Subject: [PATCH] Make VersionAwareSizeOf trimmable --- Cpp2IL.Core/Cpp2IL.Core.csproj | 1 + Cpp2IL.Core/Utils/MiscUtils.cs | 3 +- Cpp2IL/Cpp2IL.csproj | 9 ++- LibCpp2IL/BinarySearcher.cs | 6 +- LibCpp2IL/Elf/ElfFile.cs | 4 +- LibCpp2IL/LibCpp2IL.csproj | 3 +- LibCpp2IL/LibCpp2IlUtils.cs | 92 ++++++++++++++-------------- LibCpp2IL/Metadata/Il2CppMetadata.cs | 5 +- 8 files changed, 66 insertions(+), 57 deletions(-) diff --git a/Cpp2IL.Core/Cpp2IL.Core.csproj b/Cpp2IL.Core/Cpp2IL.Core.csproj index 8c67f80d..a4721ee2 100644 --- a/Cpp2IL.Core/Cpp2IL.Core.csproj +++ b/Cpp2IL.Core/Cpp2IL.Core.csproj @@ -22,6 +22,7 @@ true + true diff --git a/Cpp2IL.Core/Utils/MiscUtils.cs b/Cpp2IL.Core/Utils/MiscUtils.cs index e861ab31..b2beb0a4 100644 --- a/Cpp2IL.Core/Utils/MiscUtils.cs +++ b/Cpp2IL.Core/Utils/MiscUtils.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using Cpp2IL.Core.Extensions; @@ -153,7 +154,7 @@ public static int GetPointerSizeBytes() return LibCpp2IlMain.Binary!.is32Bit ? 4 : 8; } - public static IConvertible ReinterpretBytes(IConvertible original, Type desired) + public static IConvertible ReinterpretBytes(IConvertible original, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type desired) { if (desired is null) throw new ArgumentNullException(nameof(desired), "Destination type is null"); diff --git a/Cpp2IL/Cpp2IL.csproj b/Cpp2IL/Cpp2IL.csproj index 9bb21c9d..0dcb1864 100644 --- a/Cpp2IL/Cpp2IL.csproj +++ b/Cpp2IL/Cpp2IL.csproj @@ -9,14 +9,17 @@ 10 enable Exe - true - true net7.0;net472 - partial 2022.1.0 true + + partial + true + true + + bin\x64\Debug\ diff --git a/LibCpp2IL/BinarySearcher.cs b/LibCpp2IL/BinarySearcher.cs index 27614cb3..7241f3b3 100644 --- a/LibCpp2IL/BinarySearcher.cs +++ b/LibCpp2IL/BinarySearcher.cs @@ -213,7 +213,7 @@ internal ulong FindCodeRegistrationPost2019() //We have pCodegenModules which *should* be x-reffed in the last pointer of Il2CppCodeRegistration. //So, subtract the size of one pointer from that... - var bytesToGoBack = (ulong) LibCpp2ILUtils.VersionAwareSizeOf(typeof(Il2CppCodeRegistration)) - ptrSize; + var bytesToGoBack = (ulong) LibCpp2ILUtils.VersionAwareSizeOf() - ptrSize; LibLogger.VerboseNewline($"\t\t\tpCodegenModules is the second-to-last field of the codereg struct. Therefore on this version and architecture, we need to subtract {bytesToGoBack} bytes from its address to get pCodeReg"); @@ -285,7 +285,7 @@ public static bool ValidateCodeRegistration(Il2CppCodeRegistration codeReg, Dict public ulong FindMetadataRegistrationPre24_5() { //We're looking for TypeDefinitionsSizesCount, which is the 4th-to-last field - var sizeOfMr = (ulong) LibCpp2ILUtils.VersionAwareSizeOf(typeof(Il2CppMetadataRegistration)); + var sizeOfMr = (ulong) LibCpp2ILUtils.VersionAwareSizeOf(); var ptrSize = _binary.is32Bit ? 4ul : 8ul; var bytesToSubtract = sizeOfMr - ptrSize * 4; @@ -315,7 +315,7 @@ public ulong FindMetadataRegistrationPre24_5() public ulong FindMetadataRegistrationPost24_5() { var ptrSize = _binary.is32Bit ? 4ul : 8ul; - var sizeOfMr = (uint) LibCpp2ILUtils.VersionAwareSizeOf(typeof(Il2CppMetadataRegistration)); + var sizeOfMr = (uint) LibCpp2ILUtils.VersionAwareSizeOf(); LibLogger.VerboseNewline($"\t\t\tLooking for the number of type definitions, 0x{_typeDefinitionsCount:X}"); var ptrsToNumberOfTypes = FindAllMappedWords((ulong) _typeDefinitionsCount).ToList(); diff --git a/LibCpp2IL/Elf/ElfFile.cs b/LibCpp2IL/Elf/ElfFile.cs index 905d0001..228303ee 100644 --- a/LibCpp2IL/Elf/ElfFile.cs +++ b/LibCpp2IL/Elf/ElfFile.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -269,7 +269,7 @@ private void ProcessRelocations() } } - var sizeOfRelocationStruct = (ulong) (is32Bit ? LibCpp2ILUtils.VersionAwareSizeOf(typeof(ElfDynamicSymbol32), true, false) : LibCpp2ILUtils.VersionAwareSizeOf(typeof(ElfDynamicSymbol64), true, false)); + var sizeOfRelocationStruct = (ulong) (is32Bit ? LibCpp2ILUtils.VersionAwareSizeOf(true, false) : LibCpp2ILUtils.VersionAwareSizeOf(true, false)); LibLogger.Verbose($"\t-Now Processing {rels.Count} relocations..."); diff --git a/LibCpp2IL/LibCpp2IL.csproj b/LibCpp2IL/LibCpp2IL.csproj index e442da34..b65a3571 100644 --- a/LibCpp2IL/LibCpp2IL.csproj +++ b/LibCpp2IL/LibCpp2IL.csproj @@ -19,16 +19,17 @@ Debug;Release net7.0;net6.0;netstandard2.0 true + true + - diff --git a/LibCpp2IL/LibCpp2IlUtils.cs b/LibCpp2IL/LibCpp2IlUtils.cs index b86ef56f..178d41b9 100644 --- a/LibCpp2IL/LibCpp2IlUtils.cs +++ b/LibCpp2IL/LibCpp2IlUtils.cs @@ -35,22 +35,22 @@ public static class LibCpp2ILUtils {28, "object"} }; - private static readonly Dictionary PrimitiveSizes = new() + private static readonly Dictionary PrimitiveSizes = new() { - {"Byte", 1}, - {"SByte", 1}, - {"Boolean", 1}, - {"Int16", 2}, - {"UInt16", 2}, - {"Char", 2}, - {"Int32", 4}, - {"UInt32", 4}, - {"Single", 4}, - {"Int64", 8}, - {"UInt64", 8}, - {"Double", 8}, - {"IntPtr", 8}, - {"UIntPtr", 8}, + {typeof(byte), 1}, + {typeof(sbyte), 1}, + {typeof(bool), 1}, + {typeof(short), 2}, + {typeof(ushort), 2}, + {typeof(char), 2}, + {typeof(int), 4}, + {typeof(uint), 4}, + {typeof(float), 4}, + {typeof(long), 8}, + {typeof(ulong), 8}, + {typeof(double), 8}, + {typeof(IntPtr), 8}, + {typeof(UIntPtr), 8}, }; private static Dictionary _cachedVersionAttributes = new(); @@ -393,18 +393,24 @@ public static Il2CppTypeReflectionData GetTypeReflectionData(Il2CppType forWhat) throw new ArgumentException($"Unknown type {forWhat.Type}"); } -#pragma warning disable IL2070 //'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicFields' + public static int VersionAwareSizeOf<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>( + bool dontCheckVersionAttributes = false, + bool downsize = true) + { + return VersionAwareSizeOf(typeof(T), dontCheckVersionAttributes, downsize); + } + public static int VersionAwareSizeOf( - Type type, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type, bool dontCheckVersionAttributes = false, bool downsize = true ) { if (type.IsEnum) - type = type.GetEnumUnderlyingType(); + return PrimitiveSizes[type.GetEnumUnderlyingType()]; if (type.IsPrimitive) - return (int) PrimitiveSizes[type.Name]; + return PrimitiveSizes[type]; var shouldDownsize = downsize && LibCpp2IlMain.Binary!.is32Bit; @@ -418,36 +424,32 @@ public static int VersionAwareSizeOf( continue; } - switch (field.FieldType.Name) - { - case "Int64": - case "UInt64": - size += shouldDownsize ? 4 : 8; - break; - case "Int32": - case "UInt32": - size += 4; - break; - case "Int16": - case "UInt16": - size += 2; - break; - case "Byte": - case "SByte": - size += 1; - break; - default: - if (field.FieldType == type) - throw new Exception($"Infinite recursion is not allowed. Field {field} of type {type} has the same type as its parent."); - - size += VersionAwareSizeOf(field.FieldType, dontCheckVersionAttributes, downsize); - break; - } + if (field.FieldType == typeof(long) || field.FieldType == typeof(ulong)) + size += shouldDownsize ? 4 : 8; + else if (field.FieldType == typeof(int) || field.FieldType == typeof(uint)) + size += 4; + else if (field.FieldType == typeof(short) || field.FieldType == typeof(ushort)) + size += 2; + else if (field.FieldType == typeof(byte) || field.FieldType == typeof(sbyte)) + size += 1; + else if (field.FieldType.IsEnum) + size += PrimitiveSizes[field.FieldType.GetEnumUnderlyingType()]; + else if (field.FieldType.IsPrimitive) + size += PrimitiveSizes[field.FieldType]; + else if (field.FieldType == type) + throw new Exception($"Infinite recursion is not allowed. Field {field} of type {type} has the same type as its parent."); + else if (field.FieldType == typeof(Il2CppGenericContext)) + size += VersionAwareSizeOf(typeof(Il2CppGenericContext), dontCheckVersionAttributes, downsize); + else if (field.FieldType == typeof(Il2CppGenericMethodIndices)) + size += VersionAwareSizeOf(typeof(Il2CppGenericMethodIndices), dontCheckVersionAttributes, downsize); + else if (field.FieldType == typeof(Il2CppAssemblyNameDefinition)) + size += VersionAwareSizeOf(typeof(Il2CppAssemblyNameDefinition), dontCheckVersionAttributes, downsize); + else + throw new Exception($"Custom field type '{field.FieldType}' has no special case."); } return size; } -#pragma warning restore IL2070 internal static IEnumerable Range(int start, int count) { diff --git a/LibCpp2IL/Metadata/Il2CppMetadata.cs b/LibCpp2IL/Metadata/Il2CppMetadata.cs index 0cbda72f..592bd4ce 100644 --- a/LibCpp2IL/Metadata/Il2CppMetadata.cs +++ b/LibCpp2IL/Metadata/Il2CppMetadata.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -286,9 +287,9 @@ private Il2CppMetadata(MemoryStream stream) : base(stream) } #pragma warning restore 8618 - private T[] ReadMetadataClassArray(int offset, int length) where T : ReadableClass, new() + private T[] ReadMetadataClassArray<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(int offset, int length) where T : ReadableClass, new() { - return ReadReadableArrayAtRawAddr(offset, length / LibCpp2ILUtils.VersionAwareSizeOf(typeof(T), downsize: false)); + return ReadReadableArrayAtRawAddr(offset, length / LibCpp2ILUtils.VersionAwareSizeOf(downsize: false)); } private void DecipherMetadataUsage()