├── .github └── workflows │ └── dotnet.yml ├── .gitignore ├── AssemblyUnhollower.sln ├── AssemblyUnhollower.sln.DotSettings ├── AssemblyUnhollower ├── AssemblyKnownImports.cs ├── AssemblyUnhollower.csproj ├── Contexts │ ├── AssemblyRewriteContext.cs │ ├── FieldRewriteContext.cs │ ├── MethodRewriteContext.cs │ ├── RewriteGlobalContext.cs │ └── TypeRewriteContext.cs ├── DeobfuscationMapGenerator.cs ├── Extensions │ ├── CollectionEx.cs │ ├── CustomAttributeEx.cs │ ├── EnumEx.cs │ ├── StringEx.cs │ ├── TypeReferenceEx.cs │ └── WriterEx.cs ├── FieldAccessorGenerator.cs ├── MetadataAccess │ ├── CecilMetadataAccess.cs │ ├── IIl2CppMetadataAccess.cs │ ├── IMetadataAccess.cs │ └── NullMetadataAccess.cs ├── Passes │ ├── Pass05CreateRenameGroups.cs │ ├── Pass10CreateTypedefs.cs │ ├── Pass11ComputeTypeSpecifics.cs │ ├── Pass12FillTypedefs.cs │ ├── Pass13FillGenericConstraints.cs │ ├── Pass15GenerateMemberContexts.cs │ ├── Pass16ScanMethodRefs.cs │ ├── Pass18FinalizeMethodContexts.cs │ ├── Pass19CopyMethodParameters.cs │ ├── Pass20GenerateStaticConstructors.cs │ ├── Pass21GenerateValueTypeFields.cs │ ├── Pass22GenerateEnums.cs │ ├── Pass23GeneratePointerConstructors.cs │ ├── Pass24GenerateTypeStaticGetters.cs │ ├── Pass25GenerateNonBlittableValueTypeDefaultCtors.cs │ ├── Pass30GenerateGenericMethodStoreConstructors.cs │ ├── Pass40GenerateFieldAccessors.cs │ ├── Pass50GenerateMethods.cs │ ├── Pass60AddImplicitConversions.cs │ ├── Pass70GenerateProperties.cs │ ├── Pass79UnstripTypes.cs │ ├── Pass80UnstripFields.cs │ ├── Pass80UnstripMethods.cs │ ├── Pass81FillUnstrippedMethodBodies.cs │ ├── Pass89GenerateForwarders.cs │ ├── Pass89GenerateMethodXrefCache.cs │ ├── Pass90WriteToDisk.cs │ └── Pass91GenerateMethodPointerMap.cs ├── Program.cs ├── TargetTypeSystemHandler.cs ├── TimingCookie.cs ├── UnhollowerOptions.cs ├── UtilGenerator.cs └── Utils │ ├── UniquificationContext.cs │ ├── UnstripGenerator.cs │ ├── UnstripTranslator.cs │ └── XrefScanMetadataGenerationUtil.cs ├── COPYING.LESSER ├── Documentation ├── Class-Injection.md ├── Command-Line-Usage.md ├── Common-Problems.md └── Injected-Components-In-Asset-Bundles.md ├── LICENSE ├── README.md ├── ReleaseChangelog.md ├── UnhollowerBaseLib ├── AssemblyInfo.cs ├── Attributes │ ├── AlsoInitializeAttribute.cs │ ├── CachedScanResultsAttribute.cs │ ├── CallerCountAttribute.cs │ ├── ClassInjectionAssemblyTargetAttribute.cs │ ├── HideFromIl2CppAttribute.cs │ └── ObfuscatedNameAttribute.cs ├── ClassInjector.cs ├── DelegateSupport.cs ├── GeneratedDatabasesUtil.cs ├── IL2CPP.cs ├── Il2CppArrayBase.cs ├── Il2CppClassPointerStore.cs ├── Il2CppException.cs ├── Il2CppObjectBase.cs ├── Il2CppReferenceArray.cs ├── Il2CppStringArray.cs ├── Il2CppStructArray.cs ├── Il2CppType.cs ├── Libs │ └── Il2Cppmscorlib.dll ├── LogSupport.cs ├── Maps │ ├── MethodAddressToTokenMap.cs │ ├── MethodAddressToTokenMapBase.cs │ └── MethodXrefScanCache.cs ├── MiniILParser.cs ├── ObjectCollectedException.cs ├── Runtime │ ├── ClassInjectorBase.cs │ ├── Il2CppApi.cs │ ├── Il2CppStructs.cs │ ├── NativeStructUtils.cs │ ├── StructHandlerInterfaces.cs │ ├── UnityVersionHandler.cs │ └── VersionSpecific │ │ ├── Assembly │ │ ├── Assembly_16_0.cs │ │ ├── Assembly_20_0.cs │ │ ├── Assembly_24_0_B.cs │ │ ├── Assembly_24_1.cs │ │ ├── Assembly_24_4.cs │ │ └── Interfaces.cs │ │ ├── Class │ │ ├── Class_16_0.cs │ │ ├── Class_19_0.cs │ │ ├── Class_20_0.cs │ │ ├── Class_21_0_B.cs │ │ ├── Class_21_0_C.cs │ │ ├── Class_22_0_A.cs │ │ ├── Class_22_0_B.cs │ │ ├── Class_23_0.cs │ │ ├── Class_24_0_B.cs │ │ ├── Class_24_0_C.cs │ │ ├── Class_24_1_A.cs │ │ ├── Class_24_1_B.cs │ │ ├── Class_24_2.cs │ │ ├── Class_27_0.cs │ │ ├── Class_27_2.cs │ │ ├── Class_27_3.cs │ │ └── Interfaces.cs │ │ ├── EventInfo │ │ ├── EventInfo_16_0.cs │ │ ├── EventInfo_19_0.cs │ │ ├── EventInfo_24_1.cs │ │ └── Interfaces.cs │ │ ├── Exception │ │ ├── Exception_16_0.cs │ │ ├── Exception_21_0.cs │ │ ├── Exception_22_0.cs │ │ ├── Exception_27_3.cs │ │ └── Interfaces.cs │ │ ├── FieldInfo │ │ ├── FieldInfo_16_0.cs │ │ ├── FieldInfo_19_0.cs │ │ ├── FieldInfo_24_1.cs │ │ └── Interfaces.cs │ │ ├── Image │ │ ├── Images_16_0.cs │ │ ├── Images_19_0.cs │ │ ├── Images_24_0_A.cs │ │ ├── Images_24_0_B.cs │ │ ├── Images_24_0_C.cs │ │ ├── Images_24_1.cs │ │ ├── Images_24_2.cs │ │ ├── Images_27_0.cs │ │ └── Interfaces.cs │ │ ├── MethodInfo │ │ ├── Interfaces.cs │ │ ├── MethodInfo_16_0.cs │ │ ├── MethodInfo_24_1.cs │ │ └── MethodInfo_27_3.cs │ │ ├── ParameterInfo │ │ ├── Interfaces.cs │ │ ├── ParameterInfo_16_0.cs │ │ ├── ParameterInfo_24_1.cs │ │ └── ParameterInfo_27_3.cs │ │ ├── PropertyInfo │ │ ├── Interfaces.cs │ │ ├── PropertyInfo_16_0.cs │ │ ├── PropertyInfo_19_0.cs │ │ └── PropertyInfo_24_1.cs │ │ └── Type │ │ ├── Interfaces.cs │ │ ├── Type_16_0.cs │ │ ├── Type_27_0.cs │ │ └── Type_27_2.cs ├── RuntimeReflectionHelper.cs ├── RuntimeSpecificsStore.cs ├── UnhollowerBaseLib.csproj ├── UnhollowerUtils.cs └── XrefScans │ ├── XrefInstance.cs │ ├── XrefScanMetadataRuntimeUtil.cs │ ├── XrefScanMethodDb.cs │ ├── XrefScanUtilFinder.cs │ ├── XrefScanner.cs │ ├── XrefScannerLowLevel.cs │ └── XrefType.cs ├── UnhollowerPdbGen ├── MethodAddressToTokenMapCecil.cs ├── MsPdbCore.cs ├── PdbGenMain.cs └── UnhollowerPdbGen.csproj └── UnhollowerRuntimeLib ├── Forwarders.cs └── UnhollowerRuntimeLib.csproj /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | create: 7 | tags: 8 | - '*' 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Setup .NET 19 | uses: actions/setup-dotnet@v1 20 | with: 21 | dotnet-version: 5.0.x 22 | 23 | - name: Restore dependencies 24 | run: dotnet restore 25 | 26 | - name: Build 27 | run: dotnet build --no-restore 28 | 29 | - name: Extract Release Version 30 | id: get_version 31 | shell: bash 32 | run: | 33 | if [ "${GITHUB_REF#refs/tags/v}" != "$GITHUB_REF" ]; then 34 | echo ::set-output name=version::${GITHUB_REF#refs/tags/v} 35 | else 36 | echo ::set-output name=version::${GITHUB_SHA} 37 | fi 38 | 39 | - name: Zip release files 40 | uses: thedoctor0/zip-release@master 41 | with: 42 | directory: AssemblyUnhollower/bin/Debug/net4.7.2/ 43 | filename: Il2CppAssemblyUnhollower.${{ steps.get_version.outputs.version }}.zip 44 | exclusions: '*.pdb' 45 | 46 | - name: Move release zip to root 47 | shell: bash 48 | run: mv AssemblyUnhollower/bin/Debug/net4.7.2/Il2CppAssemblyUnhollower.${{ steps.get_version.outputs.version }}.zip . 49 | 50 | - name: Upload artifact 51 | uses: actions/upload-artifact@v2 52 | with: 53 | path: Il2CppAssemblyUnhollower.${{ steps.get_version.outputs.version }}.zip 54 | 55 | - name: Publish a release 56 | uses: softprops/action-gh-release@v1 57 | if: startsWith(github.ref, 'refs/tags/') 58 | with: 59 | body_path: ReleaseChangelog.md 60 | files: | 61 | Il2CppAssemblyUnhollower.${{ steps.get_version.outputs.version }}.zip 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | -------------------------------------------------------------------------------- /AssemblyUnhollower.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | <Policy Inspect="True" Prefix="my" Suffix="" Style="AaBb" /> 3 | <Policy Inspect="True" Prefix="our" Suffix="" Style="AaBb" /> 4 | True 5 | True -------------------------------------------------------------------------------- /AssemblyUnhollower/AssemblyUnhollower.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net4.7.2;net5.0;netstandard2.1 6 | enable 7 | 0.4.18.0 8 | latest 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /AssemblyUnhollower/Contexts/FieldRewriteContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using AssemblyUnhollower.Extensions; 4 | using Mono.Cecil; 5 | 6 | namespace AssemblyUnhollower.Contexts 7 | { 8 | public class FieldRewriteContext 9 | { 10 | public readonly TypeRewriteContext DeclaringType; 11 | public readonly FieldDefinition OriginalField; 12 | public readonly string UnmangledName; 13 | 14 | public readonly FieldReference PointerField; 15 | 16 | public FieldRewriteContext(TypeRewriteContext declaringType, FieldDefinition originalField, Dictionary? renamedFieldCounts = null) 17 | { 18 | DeclaringType = declaringType; 19 | OriginalField = originalField; 20 | 21 | UnmangledName = UnmangleFieldName(originalField, declaringType.AssemblyContext.GlobalContext.Options, renamedFieldCounts); 22 | var pointerField = new FieldDefinition("NativeFieldInfoPtr_" + UnmangledName, FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly, declaringType.AssemblyContext.Imports.IntPtr); 23 | 24 | declaringType.NewType.Fields.Add(pointerField); 25 | 26 | PointerField = new FieldReference(pointerField.Name, pointerField.FieldType, DeclaringType.SelfSubstitutedRef); 27 | } 28 | 29 | private static readonly string[] MethodAccessTypeLabels = { "CompilerControlled", "Private", "FamAndAssem", "Internal", "Protected", "FamOrAssem", "Public"}; 30 | private string UnmangleFieldNameBase(FieldDefinition field, UnhollowerOptions options) 31 | { 32 | if (options.PassthroughNames) return field.Name; 33 | 34 | if (!field.Name.IsObfuscated(options)) 35 | { 36 | if(!field.Name.IsInvalidInSource()) 37 | return field.Name; 38 | return field.Name.FilterInvalidInSourceChars(); 39 | } 40 | 41 | var accessModString = MethodAccessTypeLabels[(int) (field.Attributes & FieldAttributes.FieldAccessMask)]; 42 | var staticString = field.IsStatic ? "_Static" : ""; 43 | return "field_" + accessModString + staticString + "_" + DeclaringType.AssemblyContext.RewriteTypeRef(field.FieldType).GetUnmangledName(); 44 | } 45 | 46 | private string UnmangleFieldName(FieldDefinition field, UnhollowerOptions options, Dictionary? renamedFieldCounts) 47 | { 48 | if (options.PassthroughNames) return field.Name; 49 | 50 | if (!field.Name.IsObfuscated(options)) 51 | { 52 | if(!field.Name.IsInvalidInSource()) 53 | return field.Name; 54 | return field.Name.FilterInvalidInSourceChars(); 55 | } 56 | 57 | if (renamedFieldCounts == null) throw new ArgumentNullException(nameof(renamedFieldCounts)); 58 | 59 | var unmangleFieldNameBase = UnmangleFieldNameBase(field, options); 60 | 61 | renamedFieldCounts.TryGetValue(unmangleFieldNameBase, out var count); 62 | renamedFieldCounts[unmangleFieldNameBase] = count + 1; 63 | 64 | unmangleFieldNameBase += "_" + count; 65 | 66 | if (DeclaringType.AssemblyContext.GlobalContext.Options.RenameMap.TryGetValue( 67 | DeclaringType.NewType.GetNamespacePrefix() + "." + DeclaringType.NewType.Name + "::" + unmangleFieldNameBase, out var newName)) 68 | unmangleFieldNameBase = newName; 69 | 70 | return unmangleFieldNameBase; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Extensions/CollectionEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace AssemblyUnhollower.Extensions 5 | { 6 | public static class CollectionEx 7 | { 8 | public static TV GetOrCreate(this IDictionary dict, TK key, Func valueFactory) where TK : notnull 9 | { 10 | if (!dict.TryGetValue(key, out var result)) 11 | { 12 | result = valueFactory(key); 13 | dict[key] = result; 14 | } 15 | 16 | return result; 17 | } 18 | 19 | public static void AddLocked(this List list, T value) 20 | { 21 | lock (list) 22 | list.Add(value); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Extensions/CustomAttributeEx.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Linq; 3 | using Mono.Cecil; 4 | 5 | namespace AssemblyUnhollower.Extensions 6 | { 7 | public static class CustomAttributeEx 8 | { 9 | public static long ExtractOffset(this ICustomAttributeProvider originalMethod) => Extract(originalMethod, "AddressAttribute", "Offset"); 10 | public static long ExtractRva(this ICustomAttributeProvider originalMethod) => Extract(originalMethod, "AddressAttribute", "RVA"); 11 | public static long ExtractToken(this ICustomAttributeProvider originalMethod) => Extract(originalMethod, "TokenAttribute", "Token"); 12 | 13 | private static long Extract(this ICustomAttributeProvider originalMethod, string attributeName, string parameterName) 14 | { 15 | var addressAttribute = originalMethod.CustomAttributes.SingleOrDefault(it => it.AttributeType.Name == attributeName); 16 | var rvaField = addressAttribute?.Fields.SingleOrDefault(it => it.Name == parameterName); 17 | 18 | if (rvaField?.Name == null) return 0; 19 | 20 | var addressString = (string) rvaField.Value.Argument.Value; 21 | long.TryParse(addressString.Substring(2), NumberStyles.HexNumber, null, out var address); 22 | return address; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Extensions/EnumEx.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | 3 | namespace AssemblyUnhollower.Extensions 4 | { 5 | public static class EnumEx 6 | { 7 | public static FieldAttributes ForcePublic(this FieldAttributes fieldAttributes) 8 | { 9 | return fieldAttributes & ~FieldAttributes.FieldAccessMask & ~FieldAttributes.HasFieldMarshal | FieldAttributes.Public; 10 | } 11 | 12 | public static GenericParameterAttributes StripValueTypeConstraint(this GenericParameterAttributes parameterAttributes) 13 | { 14 | return parameterAttributes & ~GenericParameterAttributes.NotNullableValueTypeConstraint; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Extensions/StringEx.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Mono.Cecil; 3 | 4 | namespace AssemblyUnhollower.Extensions 5 | { 6 | public static class StringEx 7 | { 8 | public static string UnSystemify(this string str, UnhollowerOptions options) 9 | { 10 | foreach (var prefix in options.NamespacesAndAssembliesToPrefix) 11 | if (str.StartsWith(prefix)) 12 | return "Il2Cpp" + str; 13 | 14 | return str; 15 | } 16 | 17 | public static string FilterInvalidInSourceChars(this string str) 18 | { 19 | var chars = str.ToCharArray(); 20 | for (var i = 0; i < chars.Length; i++) 21 | { 22 | var it = chars[i]; 23 | if (!char.IsDigit(it) && !(it >= 'a' && it <= 'z' || it >= 'A' && it <= 'Z') && it != '_' && 24 | it != '`') chars[i] = '_'; 25 | } 26 | 27 | return new string(chars); 28 | } 29 | 30 | public static bool IsInvalidInSource(this string str) 31 | { 32 | for (var i = 0; i < str.Length; i++) 33 | { 34 | var it = str[i]; 35 | if (!char.IsDigit(it) && !(it >= 'a' && it <= 'z' || it >= 'A' && it <= 'Z') && it != '_' && 36 | it != '`') return true; 37 | } 38 | 39 | return false; 40 | } 41 | 42 | public static bool IsObfuscated(this string str, UnhollowerOptions options) 43 | { 44 | if (options.ObfuscatedNamesRegex != null) 45 | return options.ObfuscatedNamesRegex.IsMatch(str); 46 | 47 | foreach (var it in str) 48 | { 49 | if (!char.IsDigit(it) && !(it >= 'a' && it <= 'z' || it >= 'A' && it <= 'Z') && it != '_' && it != '`' && it != '.' && it != '<' && it != '>') return true; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | public static ulong StableHash(this string str) 56 | { 57 | ulong hash = 0; 58 | for (var i = 0; i < str.Length; i++) 59 | hash = hash * 37 + str[i]; 60 | 61 | return hash; 62 | } 63 | 64 | public static string GetUnmangledName(this TypeReference typeRef) 65 | { 66 | StringBuilder builder = new StringBuilder(); 67 | if (typeRef is GenericInstanceType genericInstance) 68 | { 69 | builder.Append(genericInstance.ElementType.GetUnmangledName()); 70 | foreach (var genericArgument in genericInstance.GenericArguments) 71 | { 72 | builder.Append("_"); 73 | builder.Append(genericArgument.GetUnmangledName()); 74 | } 75 | } else if (typeRef is ByReferenceType byRef) 76 | { 77 | builder.Append("byref_"); 78 | builder.Append(byRef.ElementType.GetUnmangledName()); 79 | } else if (typeRef is PointerType pointer) 80 | { 81 | builder.Append("ptr_"); 82 | builder.Append(pointer.ElementType.GetUnmangledName()); 83 | } 84 | else 85 | { 86 | if (typeRef.Namespace == nameof(UnhollowerBaseLib) && typeRef.Name.StartsWith("Il2Cpp") && typeRef.Name.Contains("Array")) 87 | { 88 | builder.Append("ArrayOf"); 89 | } else 90 | builder.Append(typeRef.Name.Replace('`', '_')); 91 | } 92 | 93 | return builder.ToString(); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Extensions/TypeReferenceEx.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | 3 | namespace AssemblyUnhollower.Extensions 4 | { 5 | public static class TypeReferenceEx 6 | { 7 | public static bool UnmangledNamesMatch(this TypeReference typeRefA, TypeReference typeRefB) 8 | { 9 | var aIsDefOrRef = typeRefA.GetType() == typeof(TypeReference) || typeRefA.GetType() == typeof(TypeDefinition); 10 | var bIsDefOrRef = typeRefB.GetType() == typeof(TypeReference) || typeRefB.GetType() == typeof(TypeDefinition); 11 | if (!(aIsDefOrRef && bIsDefOrRef) && typeRefA.GetType() != typeRefB.GetType()) 12 | return false; 13 | 14 | switch (typeRefA) 15 | { 16 | case PointerType pointer: 17 | return pointer.ElementType.UnmangledNamesMatch(((PointerType) typeRefB).ElementType); 18 | case ByReferenceType byRef: 19 | return byRef.ElementType.UnmangledNamesMatch(((ByReferenceType) typeRefB).ElementType); 20 | case ArrayType array: 21 | return array.ElementType.UnmangledNamesMatch(((ArrayType) typeRefB).ElementType); 22 | case GenericInstanceType genericInstance: 23 | { 24 | var elementA = genericInstance.ElementType; 25 | var genericInstanceB = (GenericInstanceType) typeRefB; 26 | var elementB = genericInstanceB.ElementType; 27 | if (!elementA.UnmangledNamesMatch(elementB)) 28 | return false; 29 | if (genericInstance.GenericArguments.Count != genericInstanceB.GenericArguments.Count) 30 | return false; 31 | 32 | for (var i = 0; i < genericInstance.GenericArguments.Count; i++) 33 | { 34 | if (!genericInstance.GenericArguments[i].UnmangledNamesMatch(genericInstanceB.GenericArguments[i])) 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | default: 41 | return typeRefA.Name == typeRefB.Name; 42 | } 43 | } 44 | 45 | public static string GetNamespacePrefix(this TypeReference type) 46 | { 47 | if (type.IsNested) 48 | return GetNamespacePrefix(type.DeclaringType) + "." + type.DeclaringType.Name; 49 | 50 | return type.Namespace; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Extensions/WriterEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace AssemblyUnhollower.Extensions 6 | { 7 | public static class WriterEx 8 | { 9 | [ThreadStatic] 10 | private static byte[]? ourBuffer; 11 | 12 | public static unsafe void Write(this BinaryWriter writer, T value) where T : unmanaged 13 | { 14 | var structSize = Marshal.SizeOf(); 15 | 16 | if (ourBuffer == null || ourBuffer.Length < structSize) 17 | ourBuffer = new byte[structSize]; 18 | 19 | fixed (byte* bytes = ourBuffer) 20 | *(T*) bytes = value; 21 | 22 | writer.Write(ourBuffer, 0, structSize); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/MetadataAccess/CecilMetadataAccess.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Mono.Cecil; 3 | 4 | namespace AssemblyUnhollower.MetadataAccess 5 | { 6 | public class CecilMetadataAccess : IIl2CppMetadataAccess 7 | { 8 | private readonly Resolver myAssemblyResolver = new(); 9 | private readonly List myAssemblies = new(); 10 | private readonly Dictionary myAssembliesByName = new(); 11 | private readonly Dictionary<(string AssemblyName, string TypeName), TypeDefinition> myTypesByName = new(); 12 | 13 | public CecilMetadataAccess(IEnumerable assemblyPaths) 14 | { 15 | var metadataResolver = new MetadataResolver(myAssemblyResolver); 16 | 17 | foreach (var sourceAssemblyPath in assemblyPaths) 18 | { 19 | var sourceAssembly = AssemblyDefinition.ReadAssembly(sourceAssemblyPath, new ReaderParameters(ReadingMode.Deferred) {MetadataResolver = metadataResolver}); 20 | myAssemblyResolver.Register(sourceAssembly); 21 | myAssemblies.Add(sourceAssembly); 22 | myAssembliesByName[sourceAssembly.Name.Name] = sourceAssembly; 23 | } 24 | 25 | foreach (var sourceAssembly in myAssemblies) 26 | { 27 | var sourceAssemblyName = sourceAssembly.Name.Name; 28 | foreach (var type in sourceAssembly.MainModule.Types) 29 | { 30 | // todo: nested types? 31 | myTypesByName[(sourceAssemblyName, type.FullName)] = type; 32 | } 33 | } 34 | } 35 | 36 | public void Dispose() 37 | { 38 | foreach (var assemblyDefinition in myAssemblies) 39 | assemblyDefinition.Dispose(); 40 | 41 | myAssemblies.Clear(); 42 | myAssembliesByName.Clear(); 43 | myAssemblyResolver.Dispose(); 44 | } 45 | 46 | public AssemblyDefinition? GetAssemblyBySimpleName(string name) => myAssembliesByName.TryGetValue(name, out var result) ? result : null; 47 | 48 | public TypeDefinition? GetTypeByName(string assemblyName, string typeName) => myTypesByName.TryGetValue((assemblyName, typeName), out var result) ? result : null; 49 | 50 | public IList Assemblies => myAssemblies; 51 | 52 | public IList? GetKnownInstantiationsFor(TypeDefinition genericDeclaration) => null; 53 | public string? GetStringStoredAtAddress(long offsetInMemory) => null; 54 | public MethodReference? GetMethodRefStoredAt(long offsetInMemory) => null; 55 | 56 | private class Resolver : DefaultAssemblyResolver 57 | { 58 | public void Register(AssemblyDefinition ass) => RegisterAssembly(ass); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/MetadataAccess/IIl2CppMetadataAccess.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Mono.Cecil; 3 | 4 | namespace AssemblyUnhollower.MetadataAccess 5 | { 6 | public interface IIl2CppMetadataAccess : IMetadataAccess 7 | { 8 | IList? GetKnownInstantiationsFor(TypeDefinition genericDeclaration); 9 | string? GetStringStoredAtAddress(long offsetInMemory); 10 | MethodReference? GetMethodRefStoredAt(long offsetInMemory); 11 | } 12 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/MetadataAccess/IMetadataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Mono.Cecil; 4 | 5 | namespace AssemblyUnhollower.MetadataAccess 6 | { 7 | public interface IMetadataAccess : IDisposable 8 | { 9 | IList Assemblies { get; } 10 | 11 | AssemblyDefinition? GetAssemblyBySimpleName(string name); 12 | TypeDefinition? GetTypeByName(string assemblyName, string typeName); 13 | } 14 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/MetadataAccess/NullMetadataAccess.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Mono.Cecil; 3 | using Mono.Collections.Generic; 4 | 5 | namespace AssemblyUnhollower.MetadataAccess 6 | { 7 | public class NullMetadataAccess : IMetadataAccess 8 | { 9 | public static readonly NullMetadataAccess Instance = new(); 10 | 11 | public void Dispose() 12 | { 13 | } 14 | 15 | public IList Assemblies => ReadOnlyCollection.Empty; 16 | public AssemblyDefinition? GetAssemblyBySimpleName(string name) => null; 17 | public TypeDefinition? GetTypeByName(string assemblyName, string typeName) => null; 18 | public IList? GetKnownInstantiationsFor(TypeReference genericDeclaration) => null; 19 | public string? GetStringStoredAtAddress(long offsetInMemory) => null; 20 | public MethodReference? GetMethodRefStoredAt(long offsetInMemory) => null; 21 | } 22 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass11ComputeTypeSpecifics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AssemblyUnhollower.Contexts; 3 | 4 | namespace AssemblyUnhollower.Passes 5 | { 6 | public static class Pass11ComputeTypeSpecifics 7 | { 8 | public static void DoPass(RewriteGlobalContext context) 9 | { 10 | foreach (var assemblyContext in context.Assemblies) 11 | foreach (var typeContext in assemblyContext.Types) 12 | { 13 | ComputeSpecifics(typeContext); 14 | } 15 | } 16 | 17 | private static void ComputeSpecifics(TypeRewriteContext typeContext) 18 | { 19 | if (typeContext.ComputedTypeSpecifics != TypeRewriteContext.TypeSpecifics.NotComputed) return; 20 | typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.Computing; 21 | 22 | foreach (var originalField in typeContext.OriginalType.Fields) 23 | { 24 | if(originalField.IsStatic) continue; 25 | 26 | var fieldType = originalField.FieldType; 27 | if (fieldType.IsPrimitive || fieldType.IsPointer) continue; 28 | if (fieldType.FullName == "System.String" || fieldType.FullName == "System.Object" || fieldType.IsArray || fieldType.IsByReference || fieldType.IsGenericParameter || fieldType.IsGenericInstance) 29 | { 30 | typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.NonBlittableStruct; 31 | return; 32 | } 33 | 34 | var fieldTypeContext = typeContext.AssemblyContext.GlobalContext.GetNewTypeForOriginal(fieldType.Resolve()); 35 | ComputeSpecifics(fieldTypeContext); 36 | if (fieldTypeContext.ComputedTypeSpecifics != TypeRewriteContext.TypeSpecifics.BlittableStruct) 37 | { 38 | typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.NonBlittableStruct; 39 | return; 40 | } 41 | } 42 | 43 | typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.BlittableStruct; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass12FillTypedefs.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using AssemblyUnhollower.Extensions; 3 | using Mono.Cecil; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass12FillTypedefs 8 | { 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | foreach (var assemblyContext in context.Assemblies) 12 | { 13 | foreach (var typeContext in assemblyContext.Types) 14 | { 15 | foreach (var originalParameter in typeContext.OriginalType.GenericParameters) 16 | { 17 | var newParameter = new GenericParameter(originalParameter.Name, typeContext.NewType); 18 | typeContext.NewType.GenericParameters.Add(newParameter); 19 | newParameter.Attributes = originalParameter.Attributes.StripValueTypeConstraint(); 20 | } 21 | 22 | if (typeContext.OriginalType.IsEnum) 23 | { 24 | typeContext.NewType.BaseType = assemblyContext.Imports.Enum; 25 | } else if (typeContext.ComputedTypeSpecifics == TypeRewriteContext.TypeSpecifics.BlittableStruct) { 26 | typeContext.NewType.BaseType = assemblyContext.Imports.ValueType; 27 | } 28 | } 29 | } 30 | 31 | // Second pass is explicitly done after first to account for rewriting of generic base types - value-typeness is important there 32 | foreach (var assemblyContext in context.Assemblies) 33 | foreach (var typeContext in assemblyContext.Types) 34 | if (!typeContext.OriginalType.IsEnum && typeContext.ComputedTypeSpecifics != 35 | TypeRewriteContext.TypeSpecifics.BlittableStruct) 36 | typeContext.NewType.BaseType = assemblyContext.RewriteTypeRef(typeContext.OriginalType.BaseType); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass13FillGenericConstraints.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | 4 | namespace AssemblyUnhollower.Passes 5 | { 6 | public static class Pass13FillGenericConstraints 7 | { 8 | public static void DoPass(RewriteGlobalContext context) 9 | { 10 | foreach (var assemblyContext in context.Assemblies) 11 | { 12 | foreach (var typeContext in assemblyContext.Types) 13 | { 14 | for (var i = 0; i < typeContext.OriginalType.GenericParameters.Count; i++) 15 | { 16 | var originalParameter = typeContext.OriginalType.GenericParameters[i]; 17 | var newParameter = typeContext.NewType.GenericParameters[i]; 18 | foreach (var originalConstraint in originalParameter.Constraints) 19 | { 20 | if (originalConstraint.ConstraintType.FullName == "System.ValueType" || originalConstraint.ConstraintType.Resolve()?.IsInterface == true) continue; 21 | 22 | newParameter.Constraints.Add( 23 | new GenericParameterConstraint( 24 | assemblyContext.RewriteTypeRef(originalConstraint.ConstraintType))); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass15GenerateMemberContexts.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | 3 | namespace AssemblyUnhollower.Passes 4 | { 5 | public static class Pass15GenerateMemberContexts 6 | { 7 | public static bool HasObfuscatedMethods; 8 | 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | foreach (var assemblyContext in context.Assemblies) 12 | foreach (var typeContext in assemblyContext.Types) 13 | typeContext.AddMembers(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass18FinalizeMethodContexts.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | using UnhollowerBaseLib; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass18FinalizeMethodContexts 8 | { 9 | public static int TotalPotentiallyDeadMethods; 10 | 11 | public static void DoPass(RewriteGlobalContext context) 12 | { 13 | var pdmNested0Caller = 0; 14 | var pdmNestedNZCaller = 0; 15 | var pdmTop0Caller = 0; 16 | var pdmTopNZCaller = 0; 17 | 18 | foreach (var assemblyContext in context.Assemblies) 19 | foreach (var typeContext in assemblyContext.Types) 20 | foreach (var methodContext in typeContext.Methods) 21 | { 22 | methodContext.CtorPhase2(); 23 | 24 | int callerCount = 0; 25 | if (Pass16ScanMethodRefs.MapOfCallers.TryGetValue(methodContext.Rva, out var callers)) 26 | callerCount = callers.Count; 27 | 28 | methodContext.NewMethod.CustomAttributes.Add( 29 | new CustomAttribute(assemblyContext.Imports.CallerCountAttributeCtor) 30 | { 31 | ConstructorArguments = 32 | {new CustomAttributeArgument(assemblyContext.Imports.Int, callerCount)} 33 | }); 34 | 35 | if (!Pass15GenerateMemberContexts.HasObfuscatedMethods) continue; 36 | if (!methodContext.UnmangledName.Contains("_PDM_")) continue; 37 | TotalPotentiallyDeadMethods++; 38 | 39 | var hasZeroCallers = callerCount == 0; 40 | if (methodContext.DeclaringType.OriginalType.IsNested) 41 | { 42 | if (hasZeroCallers) 43 | pdmNested0Caller++; 44 | else 45 | pdmNestedNZCaller++; 46 | } 47 | else 48 | { 49 | if (hasZeroCallers) 50 | pdmTop0Caller++; 51 | else 52 | pdmTopNZCaller++; 53 | } 54 | } 55 | 56 | LogSupport.Trace(""); 57 | LogSupport.Trace($"Dead method statistics: 0t={pdmTop0Caller} mt={pdmTopNZCaller} 0n={pdmNested0Caller} mn={pdmNestedNZCaller}"); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass19CopyMethodParameters.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using AssemblyUnhollower.Extensions; 3 | using Mono.Cecil; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass19CopyMethodParameters 8 | { 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | foreach (var assemblyContext in context.Assemblies) 12 | { 13 | foreach (var typeContext in assemblyContext.Types) 14 | { 15 | foreach (var methodRewriteContext in typeContext.Methods) 16 | { 17 | var originalMethod = methodRewriteContext.OriginalMethod; 18 | var newMethod = methodRewriteContext.NewMethod; 19 | 20 | foreach (var originalMethodParameter in originalMethod.Parameters) 21 | { 22 | var newName = originalMethodParameter.Name.IsObfuscated(context.Options) 23 | ? $"param_{originalMethodParameter.Sequence}" 24 | : originalMethodParameter.Name; 25 | 26 | var newParameter = new ParameterDefinition(newName, 27 | originalMethodParameter.Attributes & ~ParameterAttributes.HasFieldMarshal, 28 | assemblyContext.RewriteTypeRef(originalMethodParameter.ParameterType)); 29 | 30 | if (originalMethodParameter.HasConstant && (originalMethodParameter.Constant == null || 31 | originalMethodParameter.Constant is string || 32 | originalMethodParameter.Constant is bool)) 33 | newParameter.Constant = originalMethodParameter.Constant; 34 | else 35 | newParameter.Attributes &= ~ParameterAttributes.HasDefault; 36 | 37 | newMethod.Parameters.Add(newParameter); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass21GenerateValueTypeFields.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using AssemblyUnhollower.Contexts; 4 | using AssemblyUnhollower.Extensions; 5 | using Mono.Cecil; 6 | 7 | namespace AssemblyUnhollower.Passes 8 | { 9 | public static class Pass21GenerateValueTypeFields 10 | { 11 | public static void DoPass(RewriteGlobalContext context) 12 | { 13 | foreach (var assemblyContext in context.Assemblies) 14 | { 15 | var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.Object"); 16 | var il2CppSystemTypeRef = assemblyContext.NewAssembly.MainModule.ImportReference(il2CppTypeTypeRewriteContext.NewType); 17 | 18 | foreach (var typeContext in assemblyContext.Types) 19 | { 20 | if (typeContext.ComputedTypeSpecifics != TypeRewriteContext.TypeSpecifics.BlittableStruct || typeContext.OriginalType.IsEnum) continue; 21 | 22 | var newType = typeContext.NewType; 23 | newType.Attributes = newType.Attributes & ~(TypeAttributes.LayoutMask) | 24 | TypeAttributes.ExplicitLayout; 25 | 26 | UtilGenerator.GenerateBoxMethod(newType, typeContext.ClassPointerFieldRef, il2CppSystemTypeRef); 27 | 28 | foreach (var fieldContext in typeContext.Fields) 29 | { 30 | var field = fieldContext.OriginalField; 31 | if(field.IsStatic) continue; 32 | 33 | var newField = new FieldDefinition(fieldContext.UnmangledName, field.Attributes.ForcePublic(), 34 | !field.FieldType.IsValueType 35 | ? assemblyContext.Imports.IntPtr 36 | : assemblyContext.RewriteTypeRef(field.FieldType)); 37 | 38 | newField.Offset = Convert.ToInt32( 39 | (string) field.CustomAttributes 40 | .Single(it => it.AttributeType.Name == "FieldOffsetAttribute") 41 | .Fields.Single().Argument.Value, 16); 42 | 43 | newType.Fields.Add(newField); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass22GenerateEnums.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using AssemblyUnhollower.Contexts; 3 | using AssemblyUnhollower.Extensions; 4 | using Mono.Cecil; 5 | 6 | namespace AssemblyUnhollower.Passes 7 | { 8 | public static class Pass22GenerateEnums 9 | { 10 | public static void DoPass(RewriteGlobalContext context) 11 | { 12 | foreach (var assemblyContext in context.Assemblies) 13 | { 14 | foreach (var typeContext in assemblyContext.Types) 15 | { 16 | if (!typeContext.OriginalType.IsEnum) continue; 17 | 18 | var type = typeContext.OriginalType; 19 | var newType = typeContext.NewType; 20 | 21 | if (type.CustomAttributes.Any(it => it.AttributeType.FullName == "System.FlagsAttribute")) 22 | newType.CustomAttributes.Add(new CustomAttribute(assemblyContext.Imports.FlagsAttributeCtor)); 23 | 24 | foreach (var fieldDefinition in type.Fields) 25 | { 26 | var fieldName = fieldDefinition.Name; 27 | if (!context.Options.PassthroughNames && fieldName.IsObfuscated(context.Options)) 28 | fieldName = GetUnmangledName(fieldDefinition); 29 | 30 | if (context.Options.RenameMap.TryGetValue(typeContext.NewType.GetNamespacePrefix() + "." + typeContext.NewType.Name + "::" + fieldName, out var newName)) 31 | fieldName = newName; 32 | 33 | var newDef = new FieldDefinition(fieldName, fieldDefinition.Attributes | FieldAttributes.HasDefault, assemblyContext.RewriteTypeRef(fieldDefinition.FieldType)); 34 | newType.Fields.Add(newDef); 35 | 36 | newDef.Constant = fieldDefinition.Constant; 37 | } 38 | } 39 | } 40 | } 41 | 42 | public static string GetUnmangledName(FieldDefinition field) 43 | { 44 | return "EnumValue" + field.Constant; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass23GeneratePointerConstructors.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | using Mono.Cecil.Cil; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass23GeneratePointerConstructors 8 | { 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | foreach (var assemblyContext in context.Assemblies) 12 | { 13 | foreach (var typeContext in assemblyContext.Types) 14 | { 15 | if (typeContext.ComputedTypeSpecifics == TypeRewriteContext.TypeSpecifics.BlittableStruct || typeContext.OriginalType.IsEnum) continue; 16 | 17 | var newType = typeContext.NewType; 18 | var nativeCtor = new MethodDefinition(".ctor", 19 | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | 20 | MethodAttributes.HideBySig, assemblyContext.Imports.Void); 21 | 22 | nativeCtor.Parameters.Add(new ParameterDefinition(assemblyContext.Imports.IntPtr)); 23 | 24 | var ctorBody = nativeCtor.Body.GetILProcessor(); 25 | newType.Methods.Add(nativeCtor); 26 | 27 | ctorBody.Emit(OpCodes.Ldarg_0); 28 | ctorBody.Emit(OpCodes.Ldarg_1); 29 | ctorBody.Emit(OpCodes.Call, 30 | new MethodReference(".ctor", assemblyContext.Imports.Void, newType.BaseType) 31 | {Parameters = {new ParameterDefinition(assemblyContext.Imports.IntPtr)}, HasThis = true}); 32 | ctorBody.Emit(OpCodes.Ret); 33 | } 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass24GenerateTypeStaticGetters.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | using Mono.Cecil.Cil; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass24GenerateTypeStaticGetters 8 | { 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | foreach (var assemblyContext in context.Assemblies) 12 | { 13 | var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext 14 | .GetAssemblyByName("mscorlib").GetTypeByName("System.Type"); 15 | var il2CppSystemTypeRef = 16 | assemblyContext.NewAssembly.MainModule.ImportReference(il2CppTypeTypeRewriteContext.NewType); 17 | 18 | foreach (var typeContext in assemblyContext.Types) 19 | { 20 | var typeGetMethod = new MethodDefinition("get_Il2CppType", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, il2CppSystemTypeRef); 21 | typeContext.NewType.Methods.Add(typeGetMethod); 22 | var typeProperty = new PropertyDefinition("Il2CppType", PropertyAttributes.None, il2CppSystemTypeRef); 23 | typeProperty.GetMethod = typeGetMethod; 24 | typeContext.NewType.Properties.Add(typeProperty); 25 | 26 | typeProperty.CustomAttributes.Add(new CustomAttribute(assemblyContext.Imports.ObsoleteAttributeCtor) 27 | { 28 | ConstructorArguments = 29 | { 30 | new CustomAttributeArgument(assemblyContext.Imports.String, 31 | "Use Il2CppType.Of() instead. This will be removed in a future version of unhollower.") 32 | } 33 | }); 34 | 35 | var bodyBuilder = typeGetMethod.Body.GetILProcessor(); 36 | 37 | bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef); 38 | bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass); 39 | 40 | bodyBuilder.Emit(OpCodes.Call, 41 | new MethodReference("internal_from_handle", il2CppSystemTypeRef, 42 | il2CppSystemTypeRef) 43 | {Parameters = {new ParameterDefinition(assemblyContext.Imports.IntPtr)}}); 44 | 45 | bodyBuilder.Emit(OpCodes.Ret); 46 | } 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass25GenerateNonBlittableValueTypeDefaultCtors.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | using Mono.Cecil.Cil; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass25GenerateNonBlittableValueTypeDefaultCtors 8 | { 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | foreach (var assemblyContext in context.Assemblies) 12 | { 13 | foreach (var typeContext in assemblyContext.Types) 14 | { 15 | if (typeContext.ComputedTypeSpecifics != 16 | TypeRewriteContext.TypeSpecifics.NonBlittableStruct) continue; 17 | 18 | var emptyCtor = new MethodDefinition(".ctor", 19 | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | 20 | MethodAttributes.HideBySig, assemblyContext.Imports.Void); 21 | 22 | typeContext.NewType.Methods.Add(emptyCtor); 23 | 24 | var local0 = new VariableDefinition(assemblyContext.Imports.IntPtr); 25 | emptyCtor.Body.Variables.Add(local0); 26 | 27 | var bodyBuilder = emptyCtor.Body.GetILProcessor(); 28 | bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef); 29 | bodyBuilder.Emit(OpCodes.Ldc_I4_0); 30 | bodyBuilder.Emit(OpCodes.Conv_U); 31 | bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.ValueSizeGet); 32 | bodyBuilder.Emit(OpCodes.Conv_U); 33 | bodyBuilder.Emit(OpCodes.Localloc); 34 | bodyBuilder.Emit(OpCodes.Stloc_0); 35 | bodyBuilder.Emit(OpCodes.Ldarg_0); 36 | bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef); 37 | bodyBuilder.Emit(OpCodes.Ldloc_0); 38 | bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.ObjectBox); 39 | bodyBuilder.Emit(OpCodes.Call, new MethodReference(".ctor", assemblyContext.Imports.Void, typeContext.NewType.BaseType) { HasThis = true, Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }}); 40 | bodyBuilder.Emit(OpCodes.Ret); 41 | } 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass40GenerateFieldAccessors.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | 4 | namespace AssemblyUnhollower.Passes 5 | { 6 | public static class Pass40GenerateFieldAccessors 7 | { 8 | public static void DoPass(RewriteGlobalContext context) 9 | { 10 | foreach (var assemblyContext in context.Assemblies) 11 | { 12 | foreach (var typeContext in assemblyContext.Types) 13 | { 14 | foreach (var fieldContext in typeContext.Fields) 15 | { 16 | if (typeContext.ComputedTypeSpecifics == TypeRewriteContext.TypeSpecifics.BlittableStruct && !fieldContext.OriginalField.IsStatic) continue; 17 | 18 | var field = fieldContext.OriginalField; 19 | var unmangleFieldName = fieldContext.UnmangledName; 20 | 21 | var property = new PropertyDefinition(unmangleFieldName, PropertyAttributes.None, 22 | assemblyContext.RewriteTypeRef(fieldContext.OriginalField.FieldType)); 23 | typeContext.NewType.Properties.Add(property); 24 | 25 | FieldAccessorGenerator.MakeGetter(field, fieldContext, property, assemblyContext.Imports); 26 | FieldAccessorGenerator.MakeSetter(field, fieldContext, property, assemblyContext.Imports); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass80UnstripFields.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using AssemblyUnhollower.Contexts; 4 | using AssemblyUnhollower.Utils; 5 | using Mono.Cecil; 6 | using UnhollowerBaseLib; 7 | 8 | namespace AssemblyUnhollower.Passes 9 | { 10 | public static class Pass80UnstripFields 11 | { 12 | public static void DoPass(RewriteGlobalContext context) 13 | { 14 | int fieldsUnstripped = 0; 15 | int fieldsIgnored = 0; 16 | 17 | foreach (var unityAssembly in context.UnityAssemblies.Assemblies) 18 | { 19 | var processedAssembly = context.TryGetAssemblyByName(unityAssembly.Name.Name); 20 | if (processedAssembly == null) continue; 21 | var imports = processedAssembly.Imports; 22 | 23 | foreach (var unityType in unityAssembly.MainModule.Types) 24 | { 25 | var processedType = processedAssembly.TryGetTypeByName(unityType.FullName); 26 | if (processedType == null) continue; 27 | 28 | if (!unityType.IsValueType || unityType.IsEnum || processedType.NewType.IsExplicitLayout) 29 | continue; 30 | 31 | foreach (var unityField in unityType.Fields) 32 | { 33 | if(unityField.IsStatic) continue; 34 | 35 | var processedField = processedType.TryGetFieldByUnityAssemblyField(unityField); 36 | if (processedField != null) continue; 37 | 38 | var fieldType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(context, unityField.FieldType, imports); 39 | if (fieldType == null) 40 | { 41 | LogSupport.Trace($"Field {unityField} on type {unityType.FullName} has unsupported type {unityField.FieldType}, the type will be unusable"); 42 | fieldsIgnored++; 43 | continue; 44 | } 45 | 46 | var newMethod = new FieldDefinition(unityField.Name, unityField.Attributes & ~FieldAttributes.FieldAccessMask | FieldAttributes.Public, fieldType); 47 | 48 | processedType.NewType.Fields.Add(newMethod); 49 | 50 | fieldsUnstripped++; 51 | } 52 | } 53 | } 54 | 55 | LogSupport.Info(""); // finish the progress line 56 | LogSupport.Info($"{fieldsUnstripped} fields restored"); 57 | LogSupport.Info($"{fieldsIgnored} fields failed to restore"); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass81FillUnstrippedMethodBodies.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using AssemblyUnhollower.Contexts; 3 | using AssemblyUnhollower.Utils; 4 | using Mono.Cecil; 5 | using UnhollowerBaseLib; 6 | 7 | namespace AssemblyUnhollower.Passes 8 | { 9 | public static class Pass81FillUnstrippedMethodBodies 10 | { 11 | private static readonly 12 | List<(MethodDefinition unityMethod, MethodDefinition newMethod, TypeRewriteContext processedType, AssemblyKnownImports imports)> StuffToProcess = 13 | new List<(MethodDefinition unityMethod, MethodDefinition newMethod, TypeRewriteContext processedType, AssemblyKnownImports imports)>(); 14 | 15 | public static void DoPass(RewriteGlobalContext context) 16 | { 17 | int methodsSucceeded = 0; 18 | int methodsFailed = 0; 19 | 20 | foreach (var (unityMethod, newMethod, processedType, imports) in StuffToProcess) 21 | { 22 | var success = UnstripTranslator.TranslateMethod(unityMethod, newMethod, processedType, imports); 23 | if (success == false) 24 | { 25 | methodsFailed++; 26 | UnstripTranslator.ReplaceBodyWithException(newMethod, imports); 27 | } 28 | else 29 | methodsSucceeded++; 30 | } 31 | 32 | LogSupport.Info(""); // finish progress line 33 | LogSupport.Info($"IL unstrip statistics: {methodsSucceeded} successful, {methodsFailed} failed"); 34 | } 35 | 36 | public static void PushMethod(MethodDefinition unityMethod, MethodDefinition newMethod, TypeRewriteContext processedType, AssemblyKnownImports imports) 37 | { 38 | StuffToProcess.Add((unityMethod, newMethod, processedType, imports)); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass89GenerateForwarders.cs: -------------------------------------------------------------------------------- 1 | using AssemblyUnhollower.Contexts; 2 | using Mono.Cecil; 3 | using UnhollowerBaseLib; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass89GenerateForwarders 8 | { 9 | public static void DoPass(RewriteGlobalContext context) 10 | { 11 | var targetAssembly = context.TryGetAssemblyByName("UnityEngine"); 12 | if (targetAssembly == null) 13 | { 14 | LogSupport.Info("No UnityEngine.dll, will not generate forwarders"); 15 | return; 16 | } 17 | 18 | var targetModule = targetAssembly.NewAssembly.MainModule; 19 | 20 | foreach (var assemblyRewriteContext in context.Assemblies) 21 | { 22 | if (!assemblyRewriteContext.NewAssembly.Name.Name.StartsWith("UnityEngine.")) continue; 23 | foreach (var mainModuleType in assemblyRewriteContext.NewAssembly.MainModule.Types) 24 | { 25 | var importedType = targetModule.ImportReference(mainModuleType); 26 | var exportedType = new ExportedType(mainModuleType.Namespace, mainModuleType.Name, importedType.Module, importedType.Scope) { Attributes = TypeAttributes.Forwarder }; 27 | targetModule.ExportedTypes.Add(exportedType); 28 | 29 | AddNestedTypes(mainModuleType, exportedType, targetModule); 30 | } 31 | } 32 | } 33 | 34 | private static void AddNestedTypes(TypeDefinition mainModuleType, ExportedType importedType, ModuleDefinition targetModule) 35 | { 36 | foreach (var nested in mainModuleType.NestedTypes) 37 | { 38 | if((nested.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.NestedPublic) continue; 39 | 40 | var nestedImport = targetModule.ImportReference(nested); 41 | var nestedExport = new ExportedType(nestedImport.Namespace, nestedImport.Name, nestedImport.Module, nestedImport.Scope) { Attributes = TypeAttributes.Forwarder }; 42 | nestedExport.DeclaringType = importedType; 43 | targetModule.ExportedTypes.Add(nestedExport); 44 | 45 | AddNestedTypes(nested, nestedExport, targetModule); 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass90WriteToDisk.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using AssemblyUnhollower.Contexts; 4 | 5 | namespace AssemblyUnhollower.Passes 6 | { 7 | public static class Pass90WriteToDisk 8 | { 9 | public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options) 10 | { 11 | var tasks = context.Assemblies.Where(it => !options.AdditionalAssembliesBlacklist.Contains(it.NewAssembly.Name.Name)).Select(assemblyContext => Task.Run(() => { 12 | assemblyContext.NewAssembly.Write(options.OutputDir + "/" + assemblyContext.NewAssembly.Name.Name + ".dll"); 13 | })).ToArray(); 14 | 15 | Task.WaitAll(tasks); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Passes/Pass91GenerateMethodPointerMap.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Text; 4 | using AssemblyUnhollower.Contexts; 5 | using AssemblyUnhollower.Extensions; 6 | using UnhollowerBaseLib.Maps; 7 | 8 | namespace AssemblyUnhollower.Passes 9 | { 10 | public static class Pass91GenerateMethodPointerMap 11 | { 12 | public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options) 13 | { 14 | var data = new List<(long, int, int)>(); 15 | var assemblyList = new List(); 16 | 17 | foreach (var assemblyRewriteContext in context.Assemblies) 18 | { 19 | if (options.AdditionalAssembliesBlacklist.Contains(assemblyRewriteContext.NewAssembly.Name.Name)) 20 | continue; 21 | 22 | assemblyList.Add(assemblyRewriteContext.NewAssembly.FullName); 23 | 24 | foreach (var typeRewriteContext in assemblyRewriteContext.Types) 25 | { 26 | foreach (var methodRewriteContext in typeRewriteContext.Methods) 27 | { 28 | var address = methodRewriteContext.Rva; 29 | 30 | if (address != 0) 31 | data.Add((address, methodRewriteContext.NewMethod.MetadataToken.ToInt32(), assemblyList.Count - 1)); 32 | } 33 | } 34 | } 35 | 36 | data.Sort((a, b) => a.Item1.CompareTo(b.Item1)); 37 | 38 | var header = new MethodAddressToTokenMapFileHeader 39 | { 40 | Magic = MethodAddressToTokenMap.Magic, 41 | Version = MethodAddressToTokenMap.Version, 42 | NumMethods = data.Count, 43 | NumAssemblies = assemblyList.Count 44 | }; 45 | 46 | using var writer = new BinaryWriter(new FileStream(Path.Combine(options.OutputDir, MethodAddressToTokenMap.FileName), FileMode.Create, FileAccess.Write), Encoding.UTF8, false); 47 | writer.Write(header); 48 | 49 | foreach (var s in assemblyList) 50 | writer.Write(s); 51 | 52 | header.DataOffset = (int) writer.BaseStream.Position; 53 | 54 | foreach (var valueTuple in data) 55 | writer.Write(valueTuple.Item1); 56 | 57 | foreach (var valueTuple in data) 58 | { 59 | writer.Write(valueTuple.Item2); 60 | writer.Write(valueTuple.Item3); 61 | } 62 | 63 | writer.BaseStream.Position = 0; 64 | writer.Write(header); 65 | 66 | if (options.Verbose) 67 | { 68 | using var plainTextWriter = new StreamWriter(Path.Combine(options.OutputDir, MethodAddressToTokenMap.FileName + ".txt")); 69 | for (var i = 0; i < data.Count; i++) 70 | { 71 | plainTextWriter.WriteLine($"{i}\t{data[i].Item1}\t{data[i].Item2}\t{data[i].Item3}"); 72 | } 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/TargetTypeSystemHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AssemblyUnhollower.MetadataAccess; 3 | using Mono.Cecil; 4 | 5 | namespace AssemblyUnhollower 6 | { 7 | public static class TargetTypeSystemHandler 8 | { 9 | public static TypeReference Void { get; private set; } 10 | public static TypeReference IntPtr { get; private set; } 11 | public static TypeDefinition String { get; private set; } 12 | public static TypeDefinition Int { get; private set; } 13 | public static TypeDefinition Long { get; private set; } 14 | public static TypeDefinition Type { get; private set; } 15 | public static TypeReference Object { get; private set; } 16 | public static TypeReference Enum { get; private set; } 17 | public static TypeReference ValueType { get; private set; } 18 | public static TypeReference Delegate { get; private set; } 19 | public static TypeReference MulticastDelegate { get; private set; } 20 | public static TypeReference DefaultMemberAttribute { get; private set; } 21 | public static TypeReference NotSupportedException { get; private set; } 22 | public static TypeReference FlagsAttribute { get; private set; } 23 | public static TypeReference ObsoleteAttribute { get; private set; } 24 | 25 | public static void Init(IMetadataAccess systemLibraries) 26 | { 27 | var mscorlib = systemLibraries.GetAssemblyBySimpleName("mscorlib") ?? 28 | systemLibraries.GetAssemblyBySimpleName("netstandard") ?? throw new ArgumentException("System libraries metadata access doesn't contain mscorlib or netstandard"); 29 | 30 | Void = mscorlib.MainModule.TypeSystem.Void; 31 | IntPtr = mscorlib.MainModule.TypeSystem.IntPtr; 32 | String = mscorlib.MainModule.GetType("System.String"); 33 | Int = mscorlib.MainModule.GetType("System.Int32"); 34 | Long = mscorlib.MainModule.GetType("System.Int64"); 35 | Type = mscorlib.MainModule.GetType("System.Type"); 36 | Object = mscorlib.MainModule.TypeSystem.Object; 37 | Enum = mscorlib.MainModule.GetType("System.Enum"); 38 | ValueType = mscorlib.MainModule.GetType("System.ValueType"); 39 | Delegate = mscorlib.MainModule.GetType("System.Delegate"); 40 | MulticastDelegate = mscorlib.MainModule.GetType("System.MulticastDelegate"); 41 | DefaultMemberAttribute = mscorlib.MainModule.GetType("System.Reflection.DefaultMemberAttribute"); 42 | NotSupportedException = mscorlib.MainModule.GetType("System.NotSupportedException"); 43 | FlagsAttribute = mscorlib.MainModule.GetType("System.FlagsAttribute"); 44 | ObsoleteAttribute = mscorlib.MainModule.GetType("System.ObsoleteAttribute"); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/TimingCookie.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using UnhollowerBaseLib; 4 | 5 | namespace AssemblyUnhollower 6 | { 7 | internal readonly struct TimingCookie : IDisposable 8 | { 9 | private readonly Stopwatch myStopwatch; 10 | public TimingCookie(string message) 11 | { 12 | LogSupport.Info(message + "... "); 13 | myStopwatch = Stopwatch.StartNew(); 14 | } 15 | 16 | public void Dispose() 17 | { 18 | LogSupport.Info($"Done in {myStopwatch.Elapsed}"); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/UnhollowerOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace AssemblyUnhollower 5 | { 6 | public class UnhollowerOptions 7 | { 8 | public string SourceDir { get; set; } 9 | public string OutputDir { get; set; } 10 | public string MscorlibPath { get; set; } 11 | public string SystemLibrariesPath { get; set; } 12 | 13 | public string? UnityBaseLibsDir { get; set; } 14 | public List AdditionalAssembliesBlacklist { get; } = new List(); 15 | public int TypeDeobfuscationCharsPerUniquifier { get; set; } = 2; 16 | public int TypeDeobfuscationMaxUniquifiers { get; set; } = 10; 17 | public string GameAssemblyPath { get; set; } 18 | public bool Verbose { get; set; } 19 | public bool NoXrefCache { get; set; } 20 | public bool NoCopyUnhollowerLibs { get; set; } 21 | public Regex? ObfuscatedNamesRegex { get; set; } 22 | public Dictionary RenameMap { get; } = new Dictionary(); 23 | public bool PassthroughNames { get; set; } 24 | public HashSet NamespacesAndAssembliesToPrefix { get; } = new() {"System", "mscorlib", "Microsoft", "Mono", "I18N"}; 25 | 26 | public List DeobfuscationGenerationAssemblies { get; } = new List(); 27 | public string DeobfuscationNewAssembliesPath { get; set; } 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Utils/UniquificationContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AssemblyUnhollower.Extensions; 5 | 6 | namespace AssemblyUnhollower.Utils 7 | { 8 | public class UniquificationContext 9 | { 10 | private readonly UnhollowerOptions myUnhollowerOptions; 11 | private readonly Dictionary myUniquifiersCount = new Dictionary(); 12 | private readonly SortedSet<(string, float)> myPrefixes = new SortedSet<(string, float)>(new Item2Comparer()); 13 | 14 | public UniquificationContext(UnhollowerOptions unhollowerOptions) 15 | { 16 | myUnhollowerOptions = unhollowerOptions; 17 | } 18 | 19 | public bool CheckFull() 20 | { 21 | return myUniquifiersCount.Count >= myUnhollowerOptions.TypeDeobfuscationMaxUniquifiers; 22 | } 23 | 24 | public void Push(string str, bool noSubstring = false) 25 | { 26 | if (str.IsInvalidInSource()) return; 27 | 28 | var stringPrefix = noSubstring ? str : SubstringBounded(str, 0, myUnhollowerOptions.TypeDeobfuscationCharsPerUniquifier); 29 | var currentCount = myUniquifiersCount[stringPrefix] = myUniquifiersCount.GetOrCreate(stringPrefix, _ => 0) + 1; 30 | myPrefixes.Add((stringPrefix, myUniquifiersCount.Count + currentCount * 2 + myPrefixes.Count / 100f)); 31 | } 32 | 33 | public void Push(List strings, bool noSubstring = false) 34 | { 35 | foreach (var str in strings) 36 | Push(str, noSubstring); 37 | } 38 | 39 | public string GetTop() 40 | { 41 | return string.Join("", myPrefixes.Take(myUnhollowerOptions.TypeDeobfuscationMaxUniquifiers).Select(it => it.Item1)); 42 | } 43 | 44 | private class Item2Comparer : IComparer<(string, float)> 45 | { 46 | public int Compare((string, float) x, (string, float) y) => x.Item2.CompareTo(y.Item2); 47 | } 48 | 49 | private static string SubstringBounded(string str, int startIndex, int length) 50 | { 51 | length = Math.Min(length, str.Length); 52 | return str.Substring(startIndex, length); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /AssemblyUnhollower/Utils/XrefScanMetadataGenerationUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using AssemblyUnhollower.Contexts; 4 | using AssemblyUnhollower.Extensions; 5 | 6 | namespace UnhollowerRuntimeLib.XrefScans 7 | { 8 | internal static class XrefScanMetadataGenerationUtil 9 | { 10 | internal static long MetadataInitForMethodRva; 11 | internal static IntPtr MetadataInitForMethodFileOffset; 12 | 13 | private static readonly (string Assembly, string Type, string Method)[] MetadataInitCandidates = { 14 | ("UnityEngine.CoreModule", "UnityEngine.Object", ".cctor"), 15 | ("mscorlib", "System.Exception", "get_Message"), 16 | ("mscorlib", "System.IntPtr", "Equals") 17 | }; 18 | 19 | private static void FindMetadataInitForMethod(RewriteGlobalContext context, long gameAssemblyBase) 20 | { 21 | foreach (var metadataInitCandidate in MetadataInitCandidates) 22 | { 23 | var assembly = context.Assemblies.FirstOrDefault(it => it.OriginalAssembly.Name.Name == metadataInitCandidate.Assembly); 24 | var unityObjectCctor = assembly?.TryGetTypeByName(metadataInitCandidate.Type)?.OriginalType.Methods.FirstOrDefault(it => it.Name == metadataInitCandidate.Method); 25 | 26 | if(unityObjectCctor == null) continue; 27 | 28 | MetadataInitForMethodFileOffset = 29 | (IntPtr) ((long) XrefScannerLowLevel.JumpTargets((IntPtr) (gameAssemblyBase + unityObjectCctor.ExtractOffset())).First()); 30 | MetadataInitForMethodRva = (long) MetadataInitForMethodFileOffset - gameAssemblyBase - unityObjectCctor.ExtractOffset() + unityObjectCctor.ExtractRva(); 31 | 32 | return; 33 | } 34 | 35 | throw new ApplicationException("Unable to find a method with metadata init reference"); 36 | } 37 | 38 | internal static (long FlagRva, long TokenRva) FindMetadataInitForMethod(MethodRewriteContext method, long gameAssemblyBase) 39 | { 40 | if (MetadataInitForMethodRva == 0) 41 | FindMetadataInitForMethod(method.DeclaringType.AssemblyContext.GlobalContext, gameAssemblyBase); 42 | 43 | var codeStart = (IntPtr) (gameAssemblyBase + method.FileOffset); 44 | var firstCall = XrefScannerLowLevel.JumpTargets(codeStart).FirstOrDefault(); 45 | if (firstCall != MetadataInitForMethodFileOffset || firstCall == IntPtr.Zero) return (0, 0); 46 | 47 | var tokenPointer = XrefScanUtilFinder.FindLastRcxReadAddressBeforeCallTo(codeStart, MetadataInitForMethodFileOffset); 48 | var initFlagPointer = XrefScanUtilFinder.FindByteWriteTargetRightAfterCallTo(codeStart, MetadataInitForMethodFileOffset); 49 | 50 | if (tokenPointer == IntPtr.Zero || initFlagPointer == IntPtr.Zero) return (0, 0); 51 | 52 | return ((long) initFlagPointer - gameAssemblyBase - method.FileOffset + method.Rva, (long) tokenPointer - gameAssemblyBase - method.FileOffset + method.Rva); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Documentation/Class-Injection.md: -------------------------------------------------------------------------------- 1 | # Class injection 2 | Starting with version `0.4.0.0`, managed classes can be injected into IL2CPP domain. Currently this is fairly limited, but functional enough for GC integration and implementing custom MonoBehaviors. 3 | 4 | ## How-to 5 | * Your class must inherit from a non-abstract IL2CPP class. 6 | * You must include a constructor that takes IntPtr and passes it to base class constructor. It will be called when objects of your class are created from IL2CPP side. 7 | * To create your object from managed side, call base class IntPtr constructor with result of `ClassInjector.DerivedConstructorPointer()`, where T is your class type, and call `ClassInjector.DerivedConstructorBody(this)` in constructor body. 8 | * An example of injected class is `Il2CppToMonoDelegateReference` in [DelegateSupport.cs](UnhollowerRuntimeLib/DelegateSupport.cs) 9 | * Call `ClassInjector.RegisterTypeInIl2Cpp()` before first use of class to be injected 10 | * The injected class can be used normally afterwards, for example a custom MonoBehavior implementation would work with `AddComponent` 11 | 12 | ## Fine-tuning 13 | * `[HideFromIl2Cpp]` can be used to prevent a method from being exposed to il2cpp 14 | 15 | ## Caveats 16 | * Injected class instances are handled by IL2CPP garbage collection. This means that an object may be collected even if it's referenced from managed domain. Attempting to use that object afterwards will result in `ObjectCollectedException`. Conversely, managed representation of injected object will not be garbage collected as long as it's referenced from IL2CPP domain. 17 | * It might be possible to create a cross-domain reference loop that will prevent objects from being garbage collected. Avoid doing anything that will result in injected class instances (indirectly) storing references to itself. The simplest example of how to leak memory is this: 18 | ```c# 19 | class Injected: Il2CppSystem.Object { 20 | Il2CppSystem.Collections.Generic.List list = new ...; 21 | public Injected() { 22 | list.Add(this); // reference to itself through an IL2CPP list. This will prevent both this and list from being garbage collected, ever. 23 | } 24 | } 25 | ``` 26 | 27 | ## Limitations 28 | * Interfaces can't be implemented 29 | * Virtual methods can't be overridden 30 | * Only instance methods are exposed to IL2CPP side - no fields, properties, events or static methods will be visible to IL2CPP reflection 31 | * Only a limited set of types is supported for method signatures 32 | -------------------------------------------------------------------------------- /Documentation/Common-Problems.md: -------------------------------------------------------------------------------- 1 | # Common Problems 2 | 3 | ## Wrong mscorlib 4 | 5 | You may be getting this error when running assembly generation: 6 | 7 | ``` 8 | Unhandled Exception: System.ArgumentNullException: Value cannot be null. 9 | Parameter name: type 10 | at Mono.Cecil.Mixin.CheckType(Object type) 11 | at Mono.Cecil.ModuleDefinition.ImportReference(TypeReference type, IGenericParameterProvider context) 12 | at AssemblyUnhollower.Passes.Pass60AddImplicitConversions.AddDelegateConversions(RewriteGlobalContext context) 13 | at AssemblyUnhollower.Passes.Pass60AddImplicitConversions.DoPass(RewriteGlobalContext context) 14 | at AssemblyUnhollower.Program.Main(UnhollowerOptions options) 15 | at AssemblyUnhollower.Program.Main(String[] args) 16 | ``` 17 | 18 | This is because `--mscorlib` should point at the mod loader's mscorlib (or at the very least GAC mscorlib). It should not point to the dummy dll mscorlib. -------------------------------------------------------------------------------- /Documentation/Injected-Components-In-Asset-Bundles.md: -------------------------------------------------------------------------------- 1 | # Injected Components in Asset Bundles 2 | 3 | Starting with version `0.4.15.0`, injected components can be used in asset bundles. 4 | 5 | ## How-to 6 | * Your class must meet the critereon mentioned in Class Injection. 7 | * Add a dummy script for your component into Unity. Remove any methods, constructors, and properties. Fields can optionally be left in for future deserialization support. 8 | * Apply the component to your intended objects in Unity and build the asset bundle. 9 | * At runtime, register your component with `RegisterTypeInIl2Cpp` before loading any objects from the asset bundle. 10 | 11 | ## Limitations 12 | * Currently, deserialization for component fields is not supported. Any fields on the component will initially have their default value as defined in the mono assembly. -------------------------------------------------------------------------------- /ReleaseChangelog.md: -------------------------------------------------------------------------------- 1 | This is a small bugfix update. Generated assemblies should be fully compatible with those generated by 0.4.17.x. 2 | 3 | New features: 4 | * Fixed compatibility with Unity versions 2021.2.0 and above 5 | * Fixed setters of non-blittable-value-type non-generic fields having invalid IL 6 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.Runtime.CompilerServices; 3 | 4 | [assembly:InternalsVisibleTo("AssemblyUnhollower")] -------------------------------------------------------------------------------- /UnhollowerBaseLib/Attributes/AlsoInitializeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] 6 | public class AlsoInitializeAttribute : Attribute 7 | { 8 | public readonly Type LinkedType; 9 | 10 | public AlsoInitializeAttribute(Type linkedType) 11 | { 12 | LinkedType = linkedType; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Attributes/CachedScanResultsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method, Inherited = false)] 6 | public class CachedScanResultsAttribute : Attribute 7 | { 8 | // Items that this method calls/uses 9 | public int XrefRangeStart; 10 | public int XrefRangeEnd; 11 | 12 | // Methods that call this method 13 | public int RefRangeStart; 14 | public int RefRangeEnd; 15 | 16 | // Data for metadata init call 17 | public long MetadataInitFlagRva; 18 | public long MetadataInitTokenRva; 19 | } 20 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Attributes/CallerCountAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method, Inherited = false)] 6 | public class CallerCountAttribute : Attribute 7 | { 8 | public readonly int Count; 9 | 10 | public CallerCountAttribute(int count) 11 | { 12 | Count = count; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Attributes/ClassInjectionAssemblyTargetAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace UnhollowerRuntimeLib 5 | { 6 | [Obsolete("UnhollowerRuntimeLib.ClassInjectionAssemblyTargetAttribute is obsolete. Use UnhollowerBaseLib.Attributes.ClassInjectionAssemblyTargetAttribute instead.")] 7 | [AttributeUsage(AttributeTargets.Class)] 8 | public class ClassInjectionAssemblyTargetAttribute : UnhollowerBaseLib.Attributes.ClassInjectionAssemblyTargetAttribute 9 | { 10 | public ClassInjectionAssemblyTargetAttribute(string assembly) : base(assembly) { } 11 | public ClassInjectionAssemblyTargetAttribute(string[] assemblies) : base(assemblies) { } 12 | } 13 | } 14 | 15 | namespace UnhollowerBaseLib.Attributes 16 | { 17 | [AttributeUsage(AttributeTargets.Class)] 18 | public class ClassInjectionAssemblyTargetAttribute : Attribute 19 | { 20 | string[] assemblies; 21 | 22 | public ClassInjectionAssemblyTargetAttribute(string assembly) 23 | { 24 | if (string.IsNullOrWhiteSpace(assembly)) assemblies = new string[0]; 25 | else assemblies = new string[] { assembly }; 26 | } 27 | public ClassInjectionAssemblyTargetAttribute(string[] assemblies) 28 | { 29 | if (assemblies is null) this.assemblies = new string[0]; 30 | else this.assemblies = assemblies; 31 | } 32 | internal IntPtr[] GetImagePointers() 33 | { 34 | List result = new List(); 35 | foreach (string assembly in assemblies) 36 | { 37 | IntPtr intPtr = IL2CPP.GetIl2CppImage(assembly); 38 | if (intPtr != IntPtr.Zero) result.Add(intPtr); 39 | } 40 | return result.ToArray(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Attributes/HideFromIl2CppAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Attributes 4 | { 5 | /// 6 | /// This attribute indicates that the target should not be exposed to IL2CPP in injected classes 7 | /// 8 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] 9 | public class HideFromIl2CppAttribute : Attribute 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Attributes/ObfuscatedNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.All, Inherited = false)] 6 | public class ObfuscatedNameAttribute : Attribute 7 | { 8 | public readonly string ObfuscatedName; 9 | 10 | public ObfuscatedNameAttribute(string obfuscatedName) 11 | { 12 | ObfuscatedName = obfuscatedName; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/GeneratedDatabasesUtil.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | 4 | namespace UnhollowerBaseLib 5 | { 6 | public static class GeneratedDatabasesUtil 7 | { 8 | public static string DatabasesLocationOverride { get; set; } = null; 9 | 10 | public static string GetDatabasePath(string databaseName) => Path.Combine( 11 | (DatabasesLocationOverride ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))!, 12 | databaseName); 13 | } 14 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Il2CppClassPointerStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Runtime.CompilerServices; 4 | using UnhollowerBaseLib.Attributes; 5 | 6 | namespace UnhollowerBaseLib 7 | { 8 | public static class Il2CppClassPointerStore 9 | { 10 | public static IntPtr NativeClassPtr; 11 | public static Type CreatedTypeRedirect; 12 | 13 | static Il2CppClassPointerStore() 14 | { 15 | var targetType = typeof(T); 16 | RuntimeHelpers.RunClassConstructor(targetType.TypeHandle); 17 | if (targetType.IsPrimitive || targetType == typeof(string)) 18 | { 19 | RuntimeHelpers.RunClassConstructor(AppDomain.CurrentDomain.GetAssemblies() 20 | .Single(it => it.GetName().Name == "Il2Cppmscorlib").GetType("Il2Cpp" + targetType.FullName) 21 | .TypeHandle); 22 | } 23 | 24 | foreach (var customAttribute in targetType.CustomAttributes) 25 | { 26 | if (customAttribute.AttributeType != typeof(AlsoInitializeAttribute)) continue; 27 | 28 | var linkedType = (Type) customAttribute.ConstructorArguments[0].Value; 29 | RuntimeHelpers.RunClassConstructor(linkedType.TypeHandle); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Il2CppException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace UnhollowerBaseLib 5 | { 6 | public class Il2CppException : Exception 7 | { 8 | [ThreadStatic] private static byte[] ourMessageBytes; 9 | 10 | public static Func ParseMessageHook; 11 | 12 | public Il2CppException(IntPtr exception) : base(BuildMessage(exception)) 13 | { 14 | } 15 | 16 | private static unsafe string BuildMessage(IntPtr exception) 17 | { 18 | if (ParseMessageHook != null) return ParseMessageHook(exception); 19 | ourMessageBytes ??= new byte[65536]; 20 | fixed (byte* message = ourMessageBytes) 21 | IL2CPP.il2cpp_format_exception(exception, message, ourMessageBytes.Length); 22 | string builtMessage = Encoding.UTF8.GetString(ourMessageBytes, 0, Array.IndexOf(ourMessageBytes, (byte) 0)); 23 | fixed (byte* message = ourMessageBytes) 24 | IL2CPP.il2cpp_format_stack_trace(exception, message, ourMessageBytes.Length); 25 | builtMessage += 26 | "\n" + Encoding.UTF8.GetString(ourMessageBytes, 0, Array.IndexOf(ourMessageBytes, (byte) 0)); 27 | return builtMessage; 28 | } 29 | 30 | public static void RaiseExceptionIfNecessary(IntPtr returnedException) 31 | { 32 | if (returnedException == IntPtr.Zero) return; 33 | throw new Il2CppException(returnedException); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Il2CppObjectBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using UnhollowerBaseLib.Runtime; 4 | 5 | namespace UnhollowerBaseLib 6 | { 7 | public class Il2CppObjectBase 8 | { 9 | public IntPtr Pointer 10 | { 11 | get 12 | { 13 | var handleTarget = IL2CPP.il2cpp_gchandle_get_target(myGcHandle); 14 | if (handleTarget == IntPtr.Zero) throw new ObjectCollectedException("Object was garbage collected in IL2CPP domain"); 15 | return handleTarget; 16 | } 17 | } 18 | 19 | public bool WasCollected 20 | { 21 | get 22 | { 23 | var handleTarget = IL2CPP.il2cpp_gchandle_get_target(myGcHandle); 24 | if (handleTarget == IntPtr.Zero) return true; 25 | return false; 26 | } 27 | } 28 | 29 | private readonly uint myGcHandle; 30 | 31 | public Il2CppObjectBase(IntPtr pointer) 32 | { 33 | if (pointer == IntPtr.Zero) 34 | throw new NullReferenceException(); 35 | 36 | myGcHandle = RuntimeSpecificsStore.ShouldUseWeakRefs(IL2CPP.il2cpp_object_get_class(pointer)) 37 | ? IL2CPP.il2cpp_gchandle_new_weakref(pointer, false) 38 | : IL2CPP.il2cpp_gchandle_new(pointer, false); 39 | } 40 | 41 | public T Cast() where T: Il2CppObjectBase 42 | { 43 | return TryCast() ?? throw new InvalidCastException($"Can't cast object of type {Marshal.PtrToStringAnsi(IL2CPP.il2cpp_class_get_name(IL2CPP.il2cpp_object_get_class(Pointer)))} to type {typeof(T)}"); 44 | } 45 | 46 | public T Unbox() where T : unmanaged 47 | { 48 | var nestedTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; 49 | if (nestedTypeClassPointer == IntPtr.Zero) 50 | throw new ArgumentException($"{typeof(T)} is not an Il2Cpp reference type"); 51 | 52 | var ownClass = IL2CPP.il2cpp_object_get_class(Pointer); 53 | if (!IL2CPP.il2cpp_class_is_assignable_from(nestedTypeClassPointer, ownClass)) 54 | throw new InvalidCastException($"Can't cast object of type {Marshal.PtrToStringAnsi(IL2CPP.il2cpp_class_get_name(IL2CPP.il2cpp_object_get_class(Pointer)))} to type {typeof(T)}"); 55 | 56 | return Marshal.PtrToStructure(IL2CPP.il2cpp_object_unbox(Pointer)); 57 | } 58 | 59 | public T TryCast() where T: Il2CppObjectBase 60 | { 61 | var nestedTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; 62 | if (nestedTypeClassPointer == IntPtr.Zero) 63 | throw new ArgumentException($"{typeof(T)} is not an Il2Cpp reference type"); 64 | 65 | var ownClass = IL2CPP.il2cpp_object_get_class(Pointer); 66 | if (!IL2CPP.il2cpp_class_is_assignable_from(nestedTypeClassPointer, ownClass)) 67 | return null; 68 | 69 | if (RuntimeSpecificsStore.IsInjected(ownClass)) 70 | return ClassInjectorBase.GetMonoObjectFromIl2CppPointer(Pointer) as T; 71 | 72 | return (T) Activator.CreateInstance(Il2CppClassPointerStore.CreatedTypeRedirect ?? typeof(T), Pointer); 73 | } 74 | 75 | ~Il2CppObjectBase() 76 | { 77 | IL2CPP.il2cpp_gchandle_free(myGcHandle); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Il2CppStringArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib 4 | { 5 | public class Il2CppStringArray : Il2CppArrayBase 6 | { 7 | public Il2CppStringArray(IntPtr pointer) : base(pointer) 8 | { 9 | } 10 | 11 | public Il2CppStringArray(long size) : base(AllocateArray(size)) 12 | { 13 | } 14 | 15 | public Il2CppStringArray(string[] arr) : base(AllocateArray(arr.Length)) 16 | { 17 | for (var i = 0; i < arr.Length; i++) 18 | this[i] = arr[i]; 19 | } 20 | 21 | static Il2CppStringArray() 22 | { 23 | StaticCtorBody(typeof(Il2CppStringArray)); 24 | } 25 | 26 | public static implicit operator Il2CppStringArray(string[] arr) 27 | { 28 | if (arr == null) return null; 29 | 30 | return new Il2CppStringArray(arr); 31 | } 32 | 33 | private static IntPtr AllocateArray(long size) 34 | { 35 | if(size < 0) 36 | throw new ArgumentOutOfRangeException(nameof(size), "Array size must not be negative"); 37 | 38 | var elementTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; 39 | if (elementTypeClassPointer == IntPtr.Zero) 40 | throw new ArgumentException("String class pointer is missing, something is very wrong"); 41 | return IL2CPP.il2cpp_array_new(elementTypeClassPointer, (ulong) size); 42 | } 43 | 44 | public override unsafe string this[int index] 45 | { 46 | get 47 | { 48 | if(index < 0 || index >= Length) 49 | throw new ArgumentOutOfRangeException(nameof(index), "Array index may not be negative or above length of the array"); 50 | var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size); 51 | var elementPointer = IntPtr.Add(arrayStartPointer, index * IntPtr.Size); 52 | return IL2CPP.Il2CppStringToManaged(*(IntPtr*) elementPointer); 53 | } 54 | set 55 | { 56 | if(index < 0 || index >= Length) 57 | throw new ArgumentOutOfRangeException(nameof(index), "Array index may not be negative or above length of the array"); 58 | var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size); 59 | var elementPointer = IntPtr.Add(arrayStartPointer, index * IntPtr.Size); 60 | *(IntPtr*)elementPointer = IL2CPP.ManagedStringToIl2Cpp(value); 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Il2CppStructArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib 4 | { 5 | public class Il2CppStructArray : Il2CppArrayBase where T: unmanaged 6 | { 7 | public Il2CppStructArray(IntPtr nativeObject) : base(nativeObject) 8 | { 9 | } 10 | 11 | public Il2CppStructArray(long size) : base(AllocateArray(size)) 12 | { 13 | } 14 | 15 | static Il2CppStructArray() 16 | { 17 | StaticCtorBody(typeof(Il2CppStructArray)); 18 | } 19 | 20 | public static implicit operator Il2CppStructArray(T[] arr) 21 | { 22 | if (arr == null) return null; 23 | 24 | var il2CppArray = new Il2CppStructArray(arr.Length); 25 | for (var i = 0; i < arr.Length; i++) il2CppArray[i] = arr[i]; 26 | 27 | return il2CppArray; 28 | } 29 | 30 | public override unsafe T this[int index] 31 | { 32 | get 33 | { 34 | if(index < 0 || index >= Length) 35 | throw new ArgumentOutOfRangeException(nameof(index), "Array index may not be negative or above length of the array"); 36 | var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size); 37 | return ((T*) arrayStartPointer.ToPointer())[index]; 38 | } 39 | set 40 | { 41 | if(index < 0 || index >= Length) 42 | throw new ArgumentOutOfRangeException(nameof(index), "Array index may not be negative or above length of the array"); 43 | var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size); 44 | ((T*) arrayStartPointer.ToPointer())[index] = value; 45 | } 46 | } 47 | 48 | private static IntPtr AllocateArray(long size) 49 | { 50 | if(size < 0) 51 | throw new ArgumentOutOfRangeException(nameof(size), "Array size must not be negative"); 52 | 53 | var elementTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; 54 | if(elementTypeClassPointer == IntPtr.Zero) 55 | throw new ArgumentException($"{nameof(Il2CppStructArray)} requires an Il2Cpp reference type, which {typeof(T)} isn't"); 56 | return IL2CPP.il2cpp_array_new(elementTypeClassPointer, (ulong) size); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Il2CppType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnhollowerBaseLib; 3 | 4 | namespace UnhollowerRuntimeLib 5 | { 6 | public static class Il2CppType 7 | { 8 | public static Il2CppSystem.Type TypeFromPointer(IntPtr classPointer, string typeName = "") => TypeFromPointerInternal(classPointer, typeName, true); 9 | 10 | private static Il2CppSystem.Type TypeFromPointerInternal(IntPtr classPointer, string typeName, bool throwOnFailure) 11 | { 12 | if (classPointer == IntPtr.Zero) 13 | { 14 | if (throwOnFailure) throw new ArgumentException($"{typeName} does not have a corresponding IL2CPP class pointer"); 15 | else return null; 16 | } 17 | var il2CppType = IL2CPP.il2cpp_class_get_type(classPointer); 18 | if (il2CppType == IntPtr.Zero) 19 | { 20 | if (throwOnFailure) throw new ArgumentException($"{typeName} does not have a corresponding IL2CPP type pointer"); 21 | else return null; 22 | } 23 | return Il2CppSystem.Type.internal_from_handle(il2CppType); 24 | } 25 | 26 | public static Il2CppSystem.Type From(Type type) => From(type, true); 27 | 28 | public static Il2CppSystem.Type From(Type type, bool throwOnFailure) 29 | { 30 | var pointer = ClassInjector.ReadClassPointerForType(type); 31 | return TypeFromPointerInternal(pointer, type.Name, throwOnFailure); 32 | } 33 | 34 | public static Il2CppSystem.Type Of() => Of(true); 35 | 36 | public static Il2CppSystem.Type Of(bool throwOnFailure) 37 | { 38 | var classPointer = Il2CppClassPointerStore.NativeClassPtr; 39 | return TypeFromPointerInternal(classPointer, typeof(T).Name, throwOnFailure); 40 | } 41 | } 42 | 43 | [Obsolete("Use Il2CppType.Of()", false)] 44 | public static class Il2CppTypeOf 45 | { 46 | [Obsolete("Use Il2CppType.Of()", true)] 47 | public static Il2CppSystem.Type Type => Il2CppType.Of(); 48 | } 49 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Libs/Il2Cppmscorlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knah/Il2CppAssemblyUnhollower/ea4ff499b2bd902de8ef2de3d132278cbb86ae4f/UnhollowerBaseLib/Libs/Il2Cppmscorlib.dll -------------------------------------------------------------------------------- /UnhollowerBaseLib/LogSupport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib 5 | { 6 | public static class LogSupport 7 | { 8 | public static event Action ErrorHandler; 9 | public static event Action WarningHandler; 10 | public static event Action InfoHandler; 11 | public static event Action TraceHandler; 12 | 13 | public static void InstallConsoleHandlers() 14 | { 15 | ErrorHandler += Console.WriteLine; 16 | WarningHandler += Console.WriteLine; 17 | InfoHandler += Console.WriteLine; 18 | } 19 | 20 | public static void RemoveAllHandlers() 21 | { 22 | ErrorHandler = null; 23 | WarningHandler = null; 24 | InfoHandler = null; 25 | TraceHandler = null; 26 | } 27 | 28 | public static void Error(string message) => ErrorHandler?.Invoke(message); 29 | public static void Warning(string message) => WarningHandler?.Invoke(message); 30 | public static void Info(string message) => InfoHandler?.Invoke(message); 31 | public static void Trace(string message) => TraceHandler?.Invoke(message); 32 | } 33 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Maps/MethodAddressToTokenMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | #nullable enable 5 | 6 | namespace UnhollowerBaseLib.Maps 7 | { 8 | public class MethodAddressToTokenMap : MethodAddressToTokenMapBase 9 | { 10 | [Obsolete("Use the constant in MethodAddressToTokenMapBase")] 11 | public new const int Magic = MethodAddressToTokenMapBase.Magic; 12 | [Obsolete("Use the constant in MethodAddressToTokenMapBase")] 13 | public new const int Version = MethodAddressToTokenMapBase.Version; 14 | [Obsolete("Use the constant in MethodAddressToTokenMapBase")] 15 | public new const string FileName = MethodAddressToTokenMapBase.FileName; 16 | 17 | public MethodAddressToTokenMap(string filePath) : base(filePath) 18 | { 19 | } 20 | 21 | protected override Assembly LoadAssembly(string assemblyName) => Assembly.Load(assemblyName); 22 | 23 | protected override MethodBase? ResolveMethod(Assembly? assembly, int token) => assembly?.ManifestModule.ResolveMethod(token); 24 | } 25 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/ObjectCollectedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib 4 | { 5 | public class ObjectCollectedException : Exception 6 | { 7 | public ObjectCollectedException(string message) : base(message) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/ClassInjectorBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime 5 | { 6 | public static class ClassInjectorBase 7 | { 8 | public static object GetMonoObjectFromIl2CppPointer(IntPtr pointer) 9 | { 10 | var gcHandle = GetGcHandlePtrFromIl2CppObject(pointer); 11 | return GCHandle.FromIntPtr(gcHandle).Target; 12 | } 13 | 14 | public static unsafe IntPtr GetGcHandlePtrFromIl2CppObject(IntPtr pointer) 15 | { 16 | if (pointer == IntPtr.Zero) throw new NullReferenceException(); 17 | var objectKlass = (Il2CppClass*) IL2CPP.il2cpp_object_get_class(pointer); 18 | var targetGcHandlePointer = IntPtr.Add(pointer, (int) UnityVersionHandler.Wrap(objectKlass).InstanceSize - IntPtr.Size); 19 | var gcHandle = *(IntPtr*) targetGcHandlePointer; 20 | return gcHandle; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/NativeStructUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime 5 | { 6 | public static class NativeStructUtils 7 | { 8 | public static IntPtr GetMethodInfoForMissingMethod(string methodName) 9 | { 10 | var methodInfo = UnityVersionHandler.NewMethod(); 11 | methodInfo.Name = Marshal.StringToHGlobalAnsi(methodName); 12 | methodInfo.Slot = ushort.MaxValue; 13 | return methodInfo.Pointer; 14 | } 15 | 16 | public static unsafe bool CheckBit(this INativeStruct self, int startOffset, int bit) 17 | { 18 | var byteOffset = bit / 8; 19 | var bitOffset = bit % 8; 20 | var p = self.Pointer + startOffset + byteOffset; 21 | 22 | var mask = 1 << bitOffset; 23 | var val = *(byte*) p.ToPointer(); 24 | var masked = val & mask; 25 | return masked == mask; 26 | } 27 | 28 | public static unsafe void SetBit(this INativeStruct self, int startOffset, int bit, bool value) 29 | { 30 | var byteOffset = bit / 8; 31 | var bitOffset = bit % 8; 32 | var p = self.Pointer + startOffset + byteOffset; 33 | 34 | var mask = ~(1 << bitOffset); 35 | var ptr = (byte*) p.ToPointer(); 36 | var val = *ptr; 37 | var newVal = (byte)(val & mask | ((value ? 1 : 0) << bitOffset)); 38 | *ptr = newVal; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/StructHandlerInterfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime 4 | { 5 | public interface INativeStructHandler {} 6 | 7 | public interface INativeStruct 8 | { 9 | IntPtr Pointer { get; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Assembly 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativeAssemblyStructHandler_16_0 : INativeAssemblyStructHandler 8 | { 9 | public INativeAssemblyStruct CreateNewAssemblyStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppAssembly_16_0*)pointer = default; 14 | 15 | return new NativeAssemblyStruct(pointer); 16 | } 17 | 18 | public INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) 19 | { 20 | if ((IntPtr)assemblyPointer == IntPtr.Zero) return null; 21 | else return new NativeAssemblyStruct((IntPtr)assemblyPointer); 22 | } 23 | 24 | public IntPtr il2cpp_assembly_get_name(IntPtr assembly) => ((Il2CppAssembly_16_0*)assembly)->aname.name; 25 | 26 | #if DEBUG 27 | public string GetName() => "NativeAssemblyStructHandler_16_0"; 28 | #endif 29 | 30 | [StructLayout(LayoutKind.Sequential)] 31 | internal struct Il2CppAssembly_16_0 32 | { 33 | public int imageIndex; 34 | public int customAttributeIndex; 35 | public Il2CppAssemblyName_16_0 aname; 36 | } 37 | 38 | [StructLayout(LayoutKind.Sequential)] 39 | internal struct Il2CppAssemblyName_16_0 40 | { 41 | public IntPtr name; // const char* 42 | public IntPtr culture; // const char* 43 | public IntPtr hash_value; // const char* 44 | public IntPtr public_key; // const char* 45 | public uint hash_alg; 46 | public int hash_len; 47 | public uint flags; 48 | public int major; 49 | public int minor; 50 | public int build; 51 | public int revision; 52 | public long public_key_token; // PUBLIC_KEY_BYTE_LENGTH 53 | } 54 | 55 | internal class NativeAssemblyStruct : INativeAssemblyStruct 56 | { 57 | public NativeAssemblyStruct(IntPtr pointer) 58 | { 59 | Pointer = pointer; 60 | } 61 | 62 | public IntPtr Pointer { get; } 63 | 64 | public Il2CppAssembly* AssemblyPointer => (Il2CppAssembly*)Pointer; 65 | 66 | private Il2CppAssembly_16_0* NativeAssembly => (Il2CppAssembly_16_0*)Pointer; 67 | 68 | private Il2CppImage* dummyImagePointer; 69 | 70 | public ref Il2CppImage* Image => ref dummyImagePointer; 71 | 72 | public ref IntPtr Name => ref NativeAssembly->aname.name; 73 | 74 | public ref int Major => ref NativeAssembly->aname.major; 75 | 76 | public ref int Minor => ref NativeAssembly->aname.minor; 77 | 78 | public ref int Build => ref NativeAssembly->aname.build; 79 | 80 | public ref int Revision => ref NativeAssembly->aname.revision; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Assembly 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.3")] 7 | public unsafe class NativeAssemblyStructHandler_20_0 : INativeAssemblyStructHandler 8 | { 9 | public INativeAssemblyStruct CreateNewAssemblyStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppAssembly_20_0*)pointer = default; 14 | 15 | return new NativeAssemblyStruct(pointer); 16 | } 17 | 18 | public INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) 19 | { 20 | if ((IntPtr)assemblyPointer == IntPtr.Zero) return null; 21 | else return new NativeAssemblyStruct((IntPtr)assemblyPointer); 22 | } 23 | 24 | public IntPtr il2cpp_assembly_get_name(IntPtr assembly) => ((Il2CppAssembly_20_0*)assembly)->aname.name; 25 | 26 | #if DEBUG 27 | public string GetName() => "NativeAssemblyStructHandler_20_0"; 28 | #endif 29 | 30 | [StructLayout(LayoutKind.Sequential)] 31 | internal struct Il2CppAssembly_20_0 32 | { 33 | public int imageIndex; 34 | public int customAttributeIndex; 35 | public int referencedAssemblyStart; 36 | public int referencedAssemblyCount; 37 | public Il2CppAssemblyName_20_0 aname; 38 | } 39 | 40 | [StructLayout(LayoutKind.Sequential)] 41 | internal struct Il2CppAssemblyName_20_0 42 | { 43 | public IntPtr name; // const char* 44 | public IntPtr culture; // const char* 45 | public IntPtr hash_value; // const char* 46 | public IntPtr public_key; // const char* 47 | public uint hash_alg; 48 | public int hash_len; 49 | public uint flags; 50 | public int major; 51 | public int minor; 52 | public int build; 53 | public int revision; 54 | public long public_key_token; // PUBLIC_KEY_BYTE_LENGTH 55 | } 56 | 57 | internal class NativeAssemblyStruct : INativeAssemblyStruct 58 | { 59 | public NativeAssemblyStruct(IntPtr pointer) 60 | { 61 | Pointer = pointer; 62 | } 63 | 64 | public IntPtr Pointer { get; } 65 | 66 | public Il2CppAssembly* AssemblyPointer => (Il2CppAssembly*)Pointer; 67 | 68 | private Il2CppAssembly_20_0* NativeAssembly => (Il2CppAssembly_20_0*)Pointer; 69 | 70 | private Il2CppImage* dummyImagePointer; 71 | 72 | public ref Il2CppImage* Image => ref dummyImagePointer; 73 | 74 | public ref IntPtr Name => ref NativeAssembly->aname.name; 75 | 76 | public ref int Major => ref NativeAssembly->aname.major; 77 | 78 | public ref int Minor => ref NativeAssembly->aname.minor; 79 | 80 | public ref int Build => ref NativeAssembly->aname.build; 81 | 82 | public ref int Revision => ref NativeAssembly->aname.revision; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Assembly/Assembly_24_0_B.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Assembly 5 | { 6 | [ApplicableToUnityVersionsSince("2018.1.0")] 7 | public unsafe class NativeAssemblyStructHandler_24_0_B : INativeAssemblyStructHandler 8 | { 9 | public INativeAssemblyStruct CreateNewAssemblyStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppAssembly_24_0_B*)pointer = default; 14 | 15 | return new NativeAssemblyStruct(pointer); 16 | } 17 | 18 | public INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) 19 | { 20 | if ((IntPtr)assemblyPointer == IntPtr.Zero) return null; 21 | else return new NativeAssemblyStruct((IntPtr)assemblyPointer); 22 | } 23 | 24 | public IntPtr il2cpp_assembly_get_name(IntPtr assembly) => ((Il2CppAssembly_24_0_B*)assembly)->aname.name; 25 | 26 | #if DEBUG 27 | public string GetName() => "NativeAssemblyStructHandler_24_0_B"; 28 | #endif 29 | 30 | [StructLayout(LayoutKind.Sequential)] 31 | internal struct Il2CppAssembly_24_0_B 32 | { 33 | public Il2CppImage* image; 34 | public int customAttributeIndex; 35 | public int referencedAssemblyStart; 36 | public int referencedAssemblyCount; 37 | public Il2CppAssemblyName_24_0_B aname; 38 | } 39 | 40 | [StructLayout(LayoutKind.Sequential)] 41 | internal struct Il2CppAssemblyName_24_0_B 42 | { 43 | public IntPtr name; // const char* 44 | public IntPtr culture; // const char* 45 | public IntPtr hash_value; // const char* 46 | public IntPtr public_key; // const char* 47 | public uint hash_alg; 48 | public int hash_len; 49 | public uint flags; 50 | public int major; 51 | public int minor; 52 | public int build; 53 | public int revision; 54 | public long public_key_token; // PUBLIC_KEY_BYTE_LENGTH 55 | } 56 | 57 | internal class NativeAssemblyStruct : INativeAssemblyStruct 58 | { 59 | public NativeAssemblyStruct(IntPtr pointer) 60 | { 61 | Pointer = pointer; 62 | } 63 | 64 | public IntPtr Pointer { get; } 65 | 66 | public Il2CppAssembly* AssemblyPointer => (Il2CppAssembly*)Pointer; 67 | 68 | private Il2CppAssembly_24_0_B* NativeAssembly => (Il2CppAssembly_24_0_B*)Pointer; 69 | 70 | public ref Il2CppImage* Image => ref NativeAssembly->image; 71 | 72 | public ref IntPtr Name => ref NativeAssembly->aname.name; 73 | 74 | public ref int Major => ref NativeAssembly->aname.major; 75 | 76 | public ref int Minor => ref NativeAssembly->aname.minor; 77 | 78 | public ref int Build => ref NativeAssembly->aname.build; 79 | 80 | public ref int Revision => ref NativeAssembly->aname.revision; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Assembly 5 | { 6 | [ApplicableToUnityVersionsSince("2018.3.0")] 7 | [ApplicableToUnityVersionsSince("2020.1.0")] 8 | public unsafe class NativeAssemblyStructHandler_24_1 : INativeAssemblyStructHandler 9 | { 10 | public INativeAssemblyStruct CreateNewAssemblyStruct() 11 | { 12 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 13 | 14 | *(Il2CppAssembly_24_1*)pointer = default; 15 | 16 | return new NativeAssemblyStruct(pointer); 17 | } 18 | 19 | public INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) 20 | { 21 | if ((IntPtr)assemblyPointer == IntPtr.Zero) return null; 22 | else return new NativeAssemblyStruct((IntPtr)assemblyPointer); 23 | } 24 | 25 | public IntPtr il2cpp_assembly_get_name(IntPtr assembly) => ((Il2CppAssembly_24_1*)assembly)->aname.name; 26 | 27 | #if DEBUG 28 | public string GetName() => "NativeAssemblyStructHandler_24_1"; 29 | #endif 30 | 31 | [StructLayout(LayoutKind.Sequential)] 32 | internal struct Il2CppAssembly_24_1 33 | { 34 | public Il2CppImage* image; 35 | public uint token; 36 | public int referencedAssemblyStart; 37 | public int referencedAssemblyCount; 38 | public Il2CppAssemblyName_24_1 aname; 39 | } 40 | 41 | [StructLayout(LayoutKind.Sequential)] 42 | internal struct Il2CppAssemblyName_24_1 43 | { 44 | public IntPtr name; // const char* 45 | public IntPtr culture; // const char* 46 | public IntPtr hash_value; // const char* 47 | public IntPtr public_key; // const char* 48 | public uint hash_alg; 49 | public int hash_len; 50 | public uint flags; 51 | public int major; 52 | public int minor; 53 | public int build; 54 | public int revision; 55 | public long public_key_token; // PUBLIC_KEY_BYTE_LENGTH 56 | } 57 | 58 | internal class NativeAssemblyStruct : INativeAssemblyStruct 59 | { 60 | public NativeAssemblyStruct(IntPtr pointer) 61 | { 62 | Pointer = pointer; 63 | } 64 | 65 | public IntPtr Pointer { get; } 66 | 67 | public Il2CppAssembly* AssemblyPointer => (Il2CppAssembly*)Pointer; 68 | 69 | private Il2CppAssembly_24_1* NativeAssembly => (Il2CppAssembly_24_1*)Pointer; 70 | 71 | public ref Il2CppImage* Image => ref NativeAssembly->image; 72 | 73 | public ref IntPtr Name => ref NativeAssembly->aname.name; 74 | 75 | public ref int Major => ref NativeAssembly->aname.major; 76 | 77 | public ref int Minor => ref NativeAssembly->aname.minor; 78 | 79 | public ref int Build => ref NativeAssembly->aname.build; 80 | 81 | public ref int Revision => ref NativeAssembly->aname.revision; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Assembly/Assembly_24_4.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Assembly 5 | { 6 | [ApplicableToUnityVersionsSince("2018.4.34")] 7 | [ApplicableToUnityVersionsSince("2019.4.15")] 8 | [ApplicableToUnityVersionsSince("2020.1.11")] 9 | public unsafe class NativeAssemblyStructHandler_24_4 : INativeAssemblyStructHandler 10 | { 11 | public INativeAssemblyStruct CreateNewAssemblyStruct() 12 | { 13 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 14 | 15 | *(Il2CppAssembly_24_4*)pointer = default; 16 | 17 | return new NativeAssemblyStruct(pointer); 18 | } 19 | 20 | public INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) 21 | { 22 | if ((IntPtr)assemblyPointer == IntPtr.Zero) return null; 23 | else return new NativeAssemblyStruct((IntPtr)assemblyPointer); 24 | } 25 | 26 | public IntPtr il2cpp_assembly_get_name(IntPtr assembly) => ((Il2CppAssembly_24_4*)assembly)->aname.name; 27 | 28 | #if DEBUG 29 | public string GetName() => "NativeAssemblyStructHandler_24_4"; 30 | #endif 31 | 32 | [StructLayout(LayoutKind.Sequential)] 33 | internal struct Il2CppAssembly_24_4 34 | { 35 | public Il2CppImage* image; 36 | public uint token; 37 | public int referencedAssemblyStart; 38 | public int referencedAssemblyCount; 39 | public Il2CppAssemblyName_24_4 aname; 40 | } 41 | 42 | [StructLayout(LayoutKind.Sequential)] 43 | internal struct Il2CppAssemblyName_24_4 44 | { 45 | public IntPtr name; // const char* 46 | public IntPtr culture; // const char* 47 | public IntPtr public_key; // const char* 48 | public uint hash_alg; 49 | public int hash_len; 50 | public uint flags; 51 | public int major; 52 | public int minor; 53 | public int build; 54 | public int revision; 55 | public long public_key_token; // PUBLIC_KEY_BYTE_LENGTH 56 | } 57 | 58 | internal class NativeAssemblyStruct : INativeAssemblyStruct 59 | { 60 | public NativeAssemblyStruct(IntPtr pointer) 61 | { 62 | Pointer = pointer; 63 | } 64 | 65 | public IntPtr Pointer { get; } 66 | 67 | public Il2CppAssembly* AssemblyPointer => (Il2CppAssembly*)Pointer; 68 | 69 | private Il2CppAssembly_24_4* NativeAssembly => (Il2CppAssembly_24_4*)Pointer; 70 | 71 | public ref Il2CppImage* Image => ref NativeAssembly->image; 72 | 73 | public ref IntPtr Name => ref NativeAssembly->aname.name; 74 | 75 | public ref int Major => ref NativeAssembly->aname.major; 76 | 77 | public ref int Minor => ref NativeAssembly->aname.minor; 78 | 79 | public ref int Build => ref NativeAssembly->aname.build; 80 | 81 | public ref int Revision => ref NativeAssembly->aname.revision; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Assembly/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Assembly 4 | { 5 | public interface INativeAssemblyStructHandler : INativeStructHandler 6 | { 7 | INativeAssemblyStruct CreateNewAssemblyStruct(); 8 | unsafe INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer); 9 | IntPtr il2cpp_assembly_get_name(IntPtr assembly); 10 | #if DEBUG 11 | string GetName(); 12 | #endif 13 | } 14 | 15 | public interface INativeAssemblyStruct : INativeStruct 16 | { 17 | unsafe Il2CppAssembly* AssemblyPointer { get; } 18 | 19 | unsafe ref Il2CppImage* Image { get; } 20 | 21 | ref IntPtr Name { get; } 22 | 23 | ref int Major { get; } 24 | 25 | ref int Minor { get; } 26 | 27 | ref int Build { get; } 28 | 29 | ref int Revision { get; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Class/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnhollowerBaseLib.Runtime.VersionSpecific.Type; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Class 5 | { 6 | public interface INativeClassStructHandler : INativeStructHandler 7 | { 8 | INativeClassStruct CreateNewClassStruct(int vTableSlots); 9 | unsafe INativeClassStruct Wrap(Il2CppClass* classPointer); 10 | #if DEBUG 11 | string GetName(); 12 | #endif 13 | } 14 | 15 | public interface INativeClassStruct : INativeStruct 16 | { 17 | unsafe Il2CppClass* ClassPointer { get; } 18 | IntPtr VTable { get; } 19 | 20 | ref uint InstanceSize { get; } 21 | ref ushort VtableCount { get; } 22 | ref ushort InterfaceCount { get; } 23 | ref ushort InterfaceOffsetsCount { get; } 24 | ref byte TypeHierarchyDepth { get; } 25 | ref int NativeSize { get; } 26 | ref uint ActualSize { get; } 27 | ref ushort MethodCount { get; } 28 | ref Il2CppClassAttributes Flags { get; } 29 | 30 | bool ValueType { get; set; } 31 | bool EnumType { get; set; } 32 | bool IsGeneric { get; set; } 33 | bool Initialized { get; set; } 34 | bool InitializedAndNoError { get; set; } 35 | bool SizeInited { get; set; } 36 | bool HasFinalize { get; set; } 37 | bool IsVtableInitialized { get; set; } 38 | 39 | ref IntPtr Name { get; } 40 | ref IntPtr Namespace { get; } 41 | 42 | INativeTypeStruct ByValArg { get; } 43 | INativeTypeStruct ThisArg { get; } 44 | 45 | unsafe ref Il2CppImage* Image { get; } 46 | unsafe ref Il2CppClass* Parent { get; } 47 | unsafe ref Il2CppClass* ElementClass { get; } 48 | unsafe ref Il2CppClass* CastClass { get; } 49 | unsafe ref Il2CppClass* Class { get; } 50 | 51 | unsafe ref Il2CppMethodInfo** Methods { get; } 52 | unsafe ref Il2CppClass** ImplementedInterfaces { get; } 53 | unsafe ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets { get; } 54 | unsafe ref Il2CppClass** TypeHierarchy { get; } 55 | } 56 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.EventInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativeEventInfoStructHandler_16_0 : INativeEventInfoStructHandler 8 | { 9 | public INativeEventInfoStruct CreateNewEventInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppEventInfo_16_0*)pointer = default; 14 | 15 | return new NativeEventInfoStruct(pointer); 16 | } 17 | 18 | public INativeEventInfoStruct Wrap(Il2CppEventInfo* eventInfoPointer) 19 | { 20 | if ((IntPtr)eventInfoPointer == IntPtr.Zero) return null; 21 | else return new NativeEventInfoStruct((IntPtr)eventInfoPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeEventInfoStructHandler_16_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppEventInfo_16_0 30 | { 31 | public IntPtr name; // const char* 32 | public Il2CppTypeStruct* eventType; // const 33 | public Il2CppClass* parent; // non const 34 | public Il2CppMethodInfo* add; // const 35 | public Il2CppMethodInfo* remove; // const 36 | public Il2CppMethodInfo* raise; // const 37 | public int customAttributeIndex; 38 | } 39 | 40 | internal class NativeEventInfoStruct : INativeEventInfoStruct 41 | { 42 | public NativeEventInfoStruct(IntPtr pointer) 43 | { 44 | Pointer = pointer; 45 | } 46 | 47 | public IntPtr Pointer { get; } 48 | 49 | public Il2CppEventInfo* EventInfoPointer => (Il2CppEventInfo*)Pointer; 50 | 51 | private Il2CppEventInfo_16_0* NativeEvent => (Il2CppEventInfo_16_0*)Pointer; 52 | 53 | public ref IntPtr Name => ref NativeEvent->name; 54 | 55 | public ref Il2CppTypeStruct* EventType => ref NativeEvent->eventType; 56 | 57 | public ref Il2CppClass* Parent => ref NativeEvent->parent; 58 | 59 | public ref Il2CppMethodInfo* Add => ref NativeEvent->add; 60 | 61 | public ref Il2CppMethodInfo* Remove => ref NativeEvent->remove; 62 | 63 | public ref Il2CppMethodInfo* Raise => ref NativeEvent->raise; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.EventInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.2")] 7 | public unsafe class NativeEventInfoStructHandler_19_0 : INativeEventInfoStructHandler 8 | { 9 | public INativeEventInfoStruct CreateNewEventInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppEventInfo_19_0*)pointer = default; 14 | 15 | return new NativeEventInfoStruct(pointer); 16 | } 17 | 18 | public INativeEventInfoStruct Wrap(Il2CppEventInfo* eventInfoPointer) 19 | { 20 | if ((IntPtr)eventInfoPointer == IntPtr.Zero) return null; 21 | else return new NativeEventInfoStruct((IntPtr)eventInfoPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeEventInfoStructHandler_19_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppEventInfo_19_0 30 | { 31 | public IntPtr name; // const char* 32 | public Il2CppTypeStruct* eventType; // const 33 | public Il2CppClass* parent; // non const 34 | public Il2CppMethodInfo* add; // const 35 | public Il2CppMethodInfo* remove; // const 36 | public Il2CppMethodInfo* raise; // const 37 | public int customAttributeIndex; 38 | public uint token; 39 | } 40 | 41 | internal class NativeEventInfoStruct : INativeEventInfoStruct 42 | { 43 | public NativeEventInfoStruct(IntPtr pointer) 44 | { 45 | Pointer = pointer; 46 | } 47 | 48 | public IntPtr Pointer { get; } 49 | 50 | public Il2CppEventInfo* EventInfoPointer => (Il2CppEventInfo*)Pointer; 51 | 52 | private Il2CppEventInfo_19_0* NativeEvent => (Il2CppEventInfo_19_0*)Pointer; 53 | 54 | public ref IntPtr Name => ref NativeEvent->name; 55 | 56 | public ref Il2CppTypeStruct* EventType => ref NativeEvent->eventType; 57 | 58 | public ref Il2CppClass* Parent => ref NativeEvent->parent; 59 | 60 | public ref Il2CppMethodInfo* Add => ref NativeEvent->add; 61 | 62 | public ref Il2CppMethodInfo* Remove => ref NativeEvent->remove; 63 | 64 | public ref Il2CppMethodInfo* Raise => ref NativeEvent->raise; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/EventInfo/EventInfo_24_1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.EventInfo 5 | { 6 | [ApplicableToUnityVersionsSince("2018.3.0")] 7 | public unsafe class NativeEventInfoStructHandler_24_1 : INativeEventInfoStructHandler 8 | { 9 | public INativeEventInfoStruct CreateNewEventInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppEventInfo_24_1*)pointer = default; 14 | 15 | return new NativeEventInfoStruct(pointer); 16 | } 17 | 18 | public INativeEventInfoStruct Wrap(Il2CppEventInfo* eventInfoPointer) 19 | { 20 | if ((IntPtr)eventInfoPointer == IntPtr.Zero) return null; 21 | else return new NativeEventInfoStruct((IntPtr)eventInfoPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeEventInfoStructHandler_24_1"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppEventInfo_24_1 30 | { 31 | public IntPtr name; // const char* 32 | public Il2CppTypeStruct* eventType; // const 33 | public Il2CppClass* parent; // non const 34 | public Il2CppMethodInfo* add; // const 35 | public Il2CppMethodInfo* remove; // const 36 | public Il2CppMethodInfo* raise; // const 37 | public uint token; 38 | } 39 | 40 | internal class NativeEventInfoStruct : INativeEventInfoStruct 41 | { 42 | public NativeEventInfoStruct(IntPtr pointer) 43 | { 44 | Pointer = pointer; 45 | } 46 | 47 | public IntPtr Pointer { get; } 48 | 49 | public Il2CppEventInfo* EventInfoPointer => (Il2CppEventInfo*)Pointer; 50 | 51 | private Il2CppEventInfo_24_1* NativeEvent => (Il2CppEventInfo_24_1*)Pointer; 52 | 53 | public ref IntPtr Name => ref NativeEvent->name; 54 | 55 | public ref Il2CppTypeStruct* EventType => ref NativeEvent->eventType; 56 | 57 | public ref Il2CppClass* Parent => ref NativeEvent->parent; 58 | 59 | public ref Il2CppMethodInfo* Add => ref NativeEvent->add; 60 | 61 | public ref Il2CppMethodInfo* Remove => ref NativeEvent->remove; 62 | 63 | public ref Il2CppMethodInfo* Raise => ref NativeEvent->raise; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/EventInfo/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.EventInfo 4 | { 5 | public interface INativeEventInfoStructHandler : INativeStructHandler 6 | { 7 | INativeEventInfoStruct CreateNewEventInfoStruct(); 8 | unsafe INativeEventInfoStruct Wrap(Il2CppEventInfo* eventInfoPointer); 9 | #if DEBUG 10 | string GetName(); 11 | #endif 12 | } 13 | 14 | public interface INativeEventInfoStruct : INativeStruct 15 | { 16 | unsafe Il2CppEventInfo* EventInfoPointer { get; } 17 | 18 | ref IntPtr Name { get; } 19 | 20 | unsafe ref Il2CppTypeStruct* EventType { get; } 21 | 22 | unsafe ref Il2CppClass* Parent { get; } 23 | 24 | unsafe ref Il2CppMethodInfo* Add { get; } 25 | 26 | unsafe ref Il2CppMethodInfo* Remove { get; } 27 | 28 | unsafe ref Il2CppMethodInfo* Raise { get; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Exception/Exception_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Exception 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativeExceptionStructHandler_16_0 : INativeExceptionStructHandler 8 | { 9 | public INativeExceptionStruct CreateNewExceptionStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppException_16_0*)pointer = default; 14 | 15 | return new NativeExceptionStruct(pointer); 16 | } 17 | 18 | public INativeExceptionStruct Wrap(Il2CppException* exceptionPointer) 19 | { 20 | if ((IntPtr)exceptionPointer == IntPtr.Zero) return null; 21 | else return new NativeExceptionStruct((IntPtr)exceptionPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeExceptionStructHandler_16_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppException_16_0 30 | { 31 | public Il2CppObject @object; 32 | public IntPtr /* Il2CppArray* */ trace_ips; 33 | public IntPtr /* Il2CppObject* */ inner_ex; 34 | public IntPtr /* Il2CppString* */ message; 35 | public IntPtr /* Il2CppString* */ help_link; 36 | public IntPtr /* Il2CppString* */ class_name; 37 | public IntPtr /* Il2CppString* */ stack_trace; 38 | public IntPtr /* Il2CppString* */ remote_stack_trace; 39 | public int remote_stack_index; 40 | public int hresult; 41 | public IntPtr /* Il2CppString* */ source; 42 | public IntPtr /* Il2CppObject* */ _data; 43 | } 44 | 45 | internal class NativeExceptionStruct : INativeExceptionStruct 46 | { 47 | public NativeExceptionStruct(IntPtr pointer) 48 | { 49 | Pointer = pointer; 50 | } 51 | 52 | public IntPtr Pointer { get; } 53 | 54 | public Il2CppException* ExceptionPointer => (Il2CppException*)Pointer; 55 | 56 | private Il2CppException_16_0* NativeException => (Il2CppException_16_0*)Pointer; 57 | 58 | private Il2CppException* dummyInnerException = (Il2CppException*)IntPtr.Zero; 59 | 60 | public ref Il2CppException* InnerException => ref dummyInnerException; 61 | 62 | public INativeExceptionStruct InnerExceptionWrapped 63 | { 64 | get 65 | { 66 | IntPtr ptr = (IntPtr)InnerException; 67 | if (ptr == IntPtr.Zero) return null; 68 | else return new NativeExceptionStruct(ptr); 69 | } 70 | } 71 | 72 | public ref IntPtr Message => ref NativeException->message; 73 | 74 | public ref IntPtr HelpLink => ref NativeException->help_link; 75 | 76 | public ref IntPtr ClassName => ref NativeException->class_name; 77 | 78 | public ref IntPtr StackTrace => ref NativeException->stack_trace; 79 | 80 | public ref IntPtr RemoteStackTrace => ref NativeException->remote_stack_trace; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Exception/Exception_21_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Exception 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.5")] 7 | public unsafe class NativeExceptionStructHandler_21_0 : INativeExceptionStructHandler 8 | { 9 | public INativeExceptionStruct CreateNewExceptionStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppException_21_0*)pointer = default; 14 | 15 | return new NativeExceptionStruct(pointer); 16 | } 17 | 18 | public INativeExceptionStruct Wrap(Il2CppException* exceptionPointer) 19 | { 20 | if ((IntPtr)exceptionPointer == IntPtr.Zero) return null; 21 | else return new NativeExceptionStruct((IntPtr)exceptionPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeExceptionStructHandler_21_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppException_21_0 30 | { 31 | public Il2CppObject @object; 32 | public IntPtr /* Il2CppArray* */ trace_ips; 33 | public Il2CppException* inner_ex; 34 | public IntPtr /* Il2CppString* */ message; 35 | public IntPtr /* Il2CppString* */ help_link; 36 | public IntPtr /* Il2CppString* */ class_name; 37 | public IntPtr /* Il2CppString* */ stack_trace; 38 | public IntPtr /* Il2CppString* */ remote_stack_trace; 39 | public int remote_stack_index; 40 | public int hresult; 41 | public IntPtr /* Il2CppString* */ source; 42 | public IntPtr /* Il2CppObject* */ _data; 43 | } 44 | 45 | internal class NativeExceptionStruct : INativeExceptionStruct 46 | { 47 | public NativeExceptionStruct(IntPtr pointer) 48 | { 49 | Pointer = pointer; 50 | } 51 | 52 | public IntPtr Pointer { get; } 53 | 54 | public Il2CppException* ExceptionPointer => (Il2CppException*)Pointer; 55 | 56 | private Il2CppException_21_0* NativeException => (Il2CppException_21_0*)Pointer; 57 | 58 | public ref Il2CppException* InnerException => ref NativeException->inner_ex; 59 | 60 | public INativeExceptionStruct InnerExceptionWrapped 61 | { 62 | get 63 | { 64 | IntPtr ptr = (IntPtr)NativeException->inner_ex; 65 | if (ptr == IntPtr.Zero) return null; 66 | else return new NativeExceptionStruct(ptr); 67 | } 68 | } 69 | 70 | public ref IntPtr Message => ref NativeException->message; 71 | 72 | public ref IntPtr HelpLink => ref NativeException->help_link; 73 | 74 | public ref IntPtr ClassName => ref NativeException->class_name; 75 | 76 | public ref IntPtr StackTrace => ref NativeException->stack_trace; 77 | 78 | public ref IntPtr RemoteStackTrace => ref NativeException->remote_stack_trace; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Exception/Exception_22_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Exception 5 | { 6 | [ApplicableToUnityVersionsSince("5.5.0")] 7 | public unsafe class NativeExceptionStructHandler_22_0 : INativeExceptionStructHandler 8 | { 9 | public INativeExceptionStruct CreateNewExceptionStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppException_22_0*)pointer = default; 14 | 15 | return new NativeExceptionStruct(pointer); 16 | } 17 | 18 | public INativeExceptionStruct Wrap(Il2CppException* exceptionPointer) 19 | { 20 | if ((IntPtr)exceptionPointer == IntPtr.Zero) return null; 21 | else return new NativeExceptionStruct((IntPtr)exceptionPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeExceptionStructHandler_22_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppException_22_0 30 | { 31 | Il2CppObject @object; 32 | public IntPtr /* Il2CppString* */ className; 33 | public IntPtr /* Il2CppString* */ message; 34 | public IntPtr /* Il2CppObject* */ _data; 35 | public Il2CppException* inner_ex; 36 | public IntPtr /* Il2CppString* */ _helpURL; 37 | public IntPtr /* Il2CppArray* */ trace_ips; 38 | public IntPtr /* Il2CppString* */ stack_trace; 39 | public IntPtr /* Il2CppString* */ remote_stack_trace; 40 | public int remote_stack_index; 41 | public IntPtr /* Il2CppObject* */ _dynamicMethods; 42 | public int hresult; 43 | public IntPtr /* Il2CppString* */ source; 44 | public IntPtr /* Il2CppObject* */ safeSerializationManager; 45 | public IntPtr /* Il2CppArray* */ captured_traces; 46 | public IntPtr /* Il2CppArray* */ native_trace_ips; 47 | } 48 | 49 | internal class NativeExceptionStruct : INativeExceptionStruct 50 | { 51 | public NativeExceptionStruct(IntPtr pointer) 52 | { 53 | Pointer = pointer; 54 | } 55 | 56 | public IntPtr Pointer { get; } 57 | 58 | public Il2CppException* ExceptionPointer => (Il2CppException*)Pointer; 59 | 60 | private Il2CppException_22_0* NativeException => (Il2CppException_22_0*)Pointer; 61 | 62 | public ref Il2CppException* InnerException => ref NativeException->inner_ex; 63 | 64 | public INativeExceptionStruct InnerExceptionWrapped 65 | { 66 | get 67 | { 68 | IntPtr ptr = (IntPtr)NativeException->inner_ex; 69 | if (ptr == IntPtr.Zero) return null; 70 | else return new NativeExceptionStruct(ptr); 71 | } 72 | } 73 | 74 | public ref IntPtr Message => ref NativeException->message; 75 | 76 | public ref IntPtr HelpLink => ref NativeException->_helpURL; 77 | 78 | public ref IntPtr ClassName => ref NativeException->className; 79 | 80 | public ref IntPtr StackTrace => ref NativeException->stack_trace; 81 | 82 | public ref IntPtr RemoteStackTrace => ref NativeException->remote_stack_trace; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Exception/Exception_27_3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Exception 5 | { 6 | [ApplicableToUnityVersionsSince("2021.2.0")] 7 | public unsafe class NativeExceptionStructHandler_27_3 : INativeExceptionStructHandler 8 | { 9 | public INativeExceptionStruct CreateNewExceptionStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppException_27_3*)pointer = default; 14 | 15 | return new NativeExceptionStruct(pointer); 16 | } 17 | 18 | public INativeExceptionStruct Wrap(Il2CppException* exceptionPointer) 19 | { 20 | if ((IntPtr)exceptionPointer == IntPtr.Zero) return null; 21 | else return new NativeExceptionStruct((IntPtr)exceptionPointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeExceptionStructHandler_27_3"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppException_27_3 30 | { 31 | Il2CppObject @object; 32 | public IntPtr /* Il2CppString* */ className; 33 | public IntPtr /* Il2CppString* */ message; 34 | public IntPtr /* Il2CppObject* */ _data; 35 | public Il2CppException* inner_ex; 36 | public IntPtr /* Il2CppString* */ _helpURL; 37 | public IntPtr /* Il2CppArray* */ trace_ips; 38 | public IntPtr /* Il2CppString* */ stack_trace; 39 | public IntPtr /* Il2CppString* */ remote_stack_trace; 40 | public int remote_stack_index; 41 | public IntPtr /* Il2CppObject* */ _dynamicMethods; 42 | public int hresult; 43 | public IntPtr /* Il2CppString* */ source; 44 | public IntPtr /* Il2CppObject* */ safeSerializationManager; 45 | public IntPtr /* Il2CppArray* */ captured_traces; 46 | public IntPtr /* Il2CppArray* */ native_trace_ips; 47 | public int caught_in_unmanaged; 48 | } 49 | 50 | internal class NativeExceptionStruct : INativeExceptionStruct 51 | { 52 | public NativeExceptionStruct(IntPtr pointer) 53 | { 54 | Pointer = pointer; 55 | } 56 | 57 | public IntPtr Pointer { get; } 58 | 59 | public Il2CppException* ExceptionPointer => (Il2CppException*)Pointer; 60 | 61 | private Il2CppException_27_3* NativeException => (Il2CppException_27_3*)Pointer; 62 | 63 | public ref Il2CppException* InnerException => ref NativeException->inner_ex; 64 | 65 | public INativeExceptionStruct InnerExceptionWrapped 66 | { 67 | get 68 | { 69 | IntPtr ptr = (IntPtr)NativeException->inner_ex; 70 | if (ptr == IntPtr.Zero) return null; 71 | else return new NativeExceptionStruct(ptr); 72 | } 73 | } 74 | 75 | public ref IntPtr Message => ref NativeException->message; 76 | 77 | public ref IntPtr HelpLink => ref NativeException->_helpURL; 78 | 79 | public ref IntPtr ClassName => ref NativeException->className; 80 | 81 | public ref IntPtr StackTrace => ref NativeException->stack_trace; 82 | 83 | public ref IntPtr RemoteStackTrace => ref NativeException->remote_stack_trace; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Exception/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Exception 4 | { 5 | public interface INativeExceptionStructHandler : INativeStructHandler 6 | { 7 | INativeExceptionStruct CreateNewExceptionStruct(); 8 | unsafe INativeExceptionStruct Wrap(Il2CppException* exceptionPointer); 9 | #if DEBUG 10 | string GetName(); 11 | #endif 12 | } 13 | 14 | public interface INativeExceptionStruct : INativeStruct 15 | { 16 | unsafe Il2CppException* ExceptionPointer { get; } 17 | 18 | unsafe ref Il2CppException* InnerException { get; } 19 | 20 | INativeExceptionStruct InnerExceptionWrapped { get; } 21 | 22 | ref IntPtr Message { get; } 23 | 24 | ref IntPtr HelpLink { get; } 25 | 26 | ref IntPtr ClassName { get; } 27 | 28 | ref IntPtr StackTrace { get; } 29 | 30 | ref IntPtr RemoteStackTrace { get; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.FieldInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativeFieldInfoStructHandler_16_0 : INativeFieldInfoStructHandler 8 | { 9 | public INativeFieldInfoStruct CreateNewFieldInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppFieldInfo_16_0*)pointer = default; 14 | 15 | return new NativeFieldInfoStruct(pointer); 16 | } 17 | 18 | public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* fieldInfoPointer) 19 | { 20 | if ((IntPtr)fieldInfoPointer == IntPtr.Zero) return null; 21 | else return new NativeFieldInfoStruct((IntPtr)fieldInfoPointer); 22 | } 23 | 24 | public IntPtr il2cpp_field_get_name(IntPtr field) => ((Il2CppFieldInfo_16_0*)field)->name; 25 | public uint il2cpp_field_get_offset(IntPtr field) => (uint)((Il2CppFieldInfo_16_0*)field)->offset; 26 | public IntPtr il2cpp_field_get_parent(IntPtr field) => (IntPtr)((Il2CppFieldInfo_16_0*)field)->parent; 27 | public IntPtr il2cpp_field_get_type(IntPtr field) => (IntPtr)((Il2CppFieldInfo_16_0*)field)->type; 28 | 29 | #if DEBUG 30 | public string GetName() => "NativeFieldInfoStructHandler_16_0"; 31 | #endif 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct Il2CppFieldInfo_16_0 35 | { 36 | public IntPtr name; // const char* 37 | public Il2CppTypeStruct* type; // const 38 | public Il2CppClass* parent; // non-const? 39 | public int offset; // If offset is -1, then it's thread static 40 | public int customAttributeIndex; 41 | } 42 | 43 | internal class NativeFieldInfoStruct : INativeFieldInfoStruct 44 | { 45 | public NativeFieldInfoStruct(IntPtr pointer) 46 | { 47 | Pointer = pointer; 48 | } 49 | 50 | public IntPtr Pointer { get; } 51 | 52 | public Il2CppFieldInfo* FieldInfoPointer => (Il2CppFieldInfo*)Pointer; 53 | 54 | private Il2CppFieldInfo_16_0* NativeField => (Il2CppFieldInfo_16_0*)Pointer; 55 | 56 | public ref IntPtr Name => ref NativeField->name; 57 | 58 | public ref Il2CppTypeStruct* Type => ref NativeField->type; 59 | 60 | public ref Il2CppClass* Parent => ref NativeField->parent; 61 | 62 | public ref int Offset => ref NativeField->offset; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.FieldInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.2")] 7 | public unsafe class NativeFieldInfoStructHandler_19_0 : INativeFieldInfoStructHandler 8 | { 9 | public INativeFieldInfoStruct CreateNewFieldInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppFieldInfo_19_0*)pointer = default; 14 | 15 | return new NativeFieldInfoStruct(pointer); 16 | } 17 | 18 | public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* fieldInfoPointer) 19 | { 20 | if ((IntPtr)fieldInfoPointer == IntPtr.Zero) return null; 21 | else return new NativeFieldInfoStruct((IntPtr)fieldInfoPointer); 22 | } 23 | 24 | public IntPtr il2cpp_field_get_name(IntPtr field) => ((Il2CppFieldInfo_19_0*)field)->name; 25 | public uint il2cpp_field_get_offset(IntPtr field) => (uint)((Il2CppFieldInfo_19_0*)field)->offset; 26 | public IntPtr il2cpp_field_get_parent(IntPtr field) => (IntPtr)((Il2CppFieldInfo_19_0*)field)->parent; 27 | public IntPtr il2cpp_field_get_type(IntPtr field) => (IntPtr)((Il2CppFieldInfo_19_0*)field)->type; 28 | 29 | #if DEBUG 30 | public string GetName() => "NativeFieldInfoStructHandler_19_0"; 31 | #endif 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct Il2CppFieldInfo_19_0 35 | { 36 | public IntPtr name; // const char* 37 | public Il2CppTypeStruct* type; // const 38 | public Il2CppClass* parent; // non-const? 39 | public int offset; // If offset is -1, then it's thread static 40 | public int customAttributeIndex; 41 | public uint token; 42 | } 43 | 44 | internal class NativeFieldInfoStruct : INativeFieldInfoStruct 45 | { 46 | public NativeFieldInfoStruct(IntPtr pointer) 47 | { 48 | Pointer = pointer; 49 | } 50 | 51 | public IntPtr Pointer { get; } 52 | 53 | public Il2CppFieldInfo* FieldInfoPointer => (Il2CppFieldInfo*)Pointer; 54 | 55 | private Il2CppFieldInfo_19_0* NativeField => (Il2CppFieldInfo_19_0*)Pointer; 56 | 57 | public ref IntPtr Name => ref NativeField->name; 58 | 59 | public ref Il2CppTypeStruct* Type => ref NativeField->type; 60 | 61 | public ref Il2CppClass* Parent => ref NativeField->parent; 62 | 63 | public ref int Offset => ref NativeField->offset; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.FieldInfo 5 | { 6 | [ApplicableToUnityVersionsSince("2018.3.0")] 7 | public unsafe class NativeFieldInfoStructHandler_24_1 : INativeFieldInfoStructHandler 8 | { 9 | public INativeFieldInfoStruct CreateNewFieldInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppFieldInfo_24_1*)pointer = default; 14 | 15 | return new NativeFieldInfoStruct(pointer); 16 | } 17 | 18 | public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* fieldInfoPointer) 19 | { 20 | if ((IntPtr)fieldInfoPointer == IntPtr.Zero) return null; 21 | else return new NativeFieldInfoStruct((IntPtr)fieldInfoPointer); 22 | } 23 | 24 | public IntPtr il2cpp_field_get_name(IntPtr field) => ((Il2CppFieldInfo_24_1*)field)->name; 25 | public uint il2cpp_field_get_offset(IntPtr field) => (uint)((Il2CppFieldInfo_24_1*)field)->offset; 26 | public IntPtr il2cpp_field_get_parent(IntPtr field) => (IntPtr)((Il2CppFieldInfo_24_1*)field)->parent; 27 | public IntPtr il2cpp_field_get_type(IntPtr field) => (IntPtr)((Il2CppFieldInfo_24_1*)field)->type; 28 | 29 | #if DEBUG 30 | public string GetName() => "NativeFieldInfoStructHandler_24_1"; 31 | #endif 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct Il2CppFieldInfo_24_1 35 | { 36 | public IntPtr name; // const char* 37 | public Il2CppTypeStruct* type; // const 38 | public Il2CppClass* parent; // non-const? 39 | public int offset; // If offset is -1, then it's thread static 40 | public uint token; 41 | } 42 | 43 | internal class NativeFieldInfoStruct : INativeFieldInfoStruct 44 | { 45 | public NativeFieldInfoStruct(IntPtr pointer) 46 | { 47 | Pointer = pointer; 48 | } 49 | 50 | public IntPtr Pointer { get; } 51 | 52 | public Il2CppFieldInfo* FieldInfoPointer => (Il2CppFieldInfo*)Pointer; 53 | 54 | private Il2CppFieldInfo_24_1* NativeField => (Il2CppFieldInfo_24_1*)Pointer; 55 | 56 | public ref IntPtr Name => ref NativeField->name; 57 | 58 | public ref Il2CppTypeStruct* Type => ref NativeField->type; 59 | 60 | public ref Il2CppClass* Parent => ref NativeField->parent; 61 | 62 | public ref int Offset => ref NativeField->offset; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/FieldInfo/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.FieldInfo 4 | { 5 | public interface INativeFieldInfoStructHandler : INativeStructHandler 6 | { 7 | INativeFieldInfoStruct CreateNewFieldInfoStruct(); 8 | unsafe INativeFieldInfoStruct Wrap(Il2CppFieldInfo* fieldInfoPointer); 9 | IntPtr il2cpp_field_get_name(IntPtr field); 10 | uint il2cpp_field_get_offset(IntPtr field); 11 | IntPtr il2cpp_field_get_parent(IntPtr field); 12 | IntPtr il2cpp_field_get_type(IntPtr field); 13 | #if DEBUG 14 | string GetName(); 15 | #endif 16 | } 17 | 18 | public interface INativeFieldInfoStruct : INativeStruct 19 | { 20 | unsafe Il2CppFieldInfo* FieldInfoPointer { get; } 21 | 22 | ref IntPtr Name { get; } 23 | 24 | unsafe ref Il2CppTypeStruct* Type { get; } 25 | 26 | unsafe ref Il2CppClass* Parent { get; } 27 | 28 | ref int Offset { get; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativeImageStructHandler_16_0 : INativeImageStructHandler 8 | { 9 | public INativeImageStruct CreateNewImageStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppImage_16_0*)pointer = default; 14 | 15 | return new NativeImageStruct(pointer); 16 | } 17 | 18 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 19 | { 20 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 21 | else return new NativeImageStruct((IntPtr)imagePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeImageStructHandler_16_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppImage_16_0 30 | { 31 | public IntPtr name; // const char* 32 | public /*AssemblyIndex*/ int assemblyIndex; 33 | 34 | public /*TypeDefinitionIndex*/ int typeStart; 35 | public uint typeCount; 36 | 37 | public /*MethodIndex*/ int entryPointIndex; 38 | 39 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 40 | } 41 | 42 | internal class NativeImageStruct : INativeImageStruct 43 | { 44 | private static byte dynamicDummy; 45 | 46 | public NativeImageStruct(IntPtr pointer) 47 | { 48 | Pointer = pointer; 49 | } 50 | 51 | public IntPtr Pointer { get; } 52 | 53 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 54 | 55 | private Il2CppImage_16_0* NativeImage => (Il2CppImage_16_0*)Pointer; 56 | 57 | public ref Il2CppAssembly* Assembly => throw new NotSupportedException(); 58 | 59 | public ref byte Dynamic => ref dynamicDummy; 60 | 61 | public ref IntPtr Name => ref NativeImage->name; 62 | 63 | public bool HasNameNoExt => false; 64 | 65 | public ref IntPtr NameNoExt => throw new NotSupportedException(); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_19_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.2")] 7 | public unsafe class NativeImageStructHandler_19_0 : INativeImageStructHandler 8 | { 9 | public INativeImageStruct CreateNewImageStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppImage_19_0*)pointer = default; 14 | 15 | return new NativeImageStruct(pointer); 16 | } 17 | 18 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 19 | { 20 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 21 | else return new NativeImageStruct((IntPtr)imagePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeImageStructHandler_19_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppImage_19_0 30 | { 31 | public IntPtr name; // const char* 32 | public /*AssemblyIndex*/ int assemblyIndex; 33 | 34 | public /*TypeDefinitionIndex*/ int typeStart; 35 | public uint typeCount; 36 | 37 | public /*MethodIndex*/ int entryPointIndex; 38 | 39 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 40 | 41 | public uint token; 42 | } 43 | 44 | internal class NativeImageStruct : INativeImageStruct 45 | { 46 | private static byte dynamicDummy; 47 | 48 | public NativeImageStruct(IntPtr pointer) 49 | { 50 | Pointer = pointer; 51 | } 52 | 53 | public IntPtr Pointer { get; } 54 | 55 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 56 | 57 | private Il2CppImage_19_0* NativeImage => (Il2CppImage_19_0*)Pointer; 58 | 59 | public ref Il2CppAssembly* Assembly => throw new NotSupportedException(); 60 | 61 | public ref byte Dynamic => ref dynamicDummy; 62 | 63 | public ref IntPtr Name => ref NativeImage->name; 64 | 65 | public bool HasNameNoExt => false; 66 | 67 | public ref IntPtr NameNoExt => throw new NotSupportedException(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_24_0_A.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("2017.1.0")] 7 | [ApplicableToUnityVersionsSince("2017.2.0")] 8 | public unsafe class NativeImageStructHandler_24_0_A : INativeImageStructHandler 9 | { 10 | public INativeImageStruct CreateNewImageStruct() 11 | { 12 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 13 | 14 | *(Il2CppImage_24_0_A*)pointer = default; 15 | 16 | return new NativeImageStruct(pointer); 17 | } 18 | 19 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 20 | { 21 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 22 | else return new NativeImageStruct((IntPtr)imagePointer); 23 | } 24 | 25 | #if DEBUG 26 | public string GetName() => "NativeImageStructHandler_24_0_A"; 27 | #endif 28 | 29 | [StructLayout(LayoutKind.Sequential)] 30 | internal struct Il2CppImage_24_0_A 31 | { 32 | public IntPtr name; // const char* 33 | public /*AssemblyIndex*/ int assemblyIndex; 34 | 35 | public /*TypeDefinitionIndex*/ int typeStart; 36 | public uint typeCount; 37 | 38 | public /*TypeDefinitionIndex*/ int exportedTypeStart; 39 | public uint exportedTypeCount; 40 | 41 | public /*MethodIndex*/ int entryPointIndex; 42 | 43 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 44 | 45 | public uint token; 46 | } 47 | 48 | internal class NativeImageStruct : INativeImageStruct 49 | { 50 | private static byte dynamicDummy; 51 | 52 | public NativeImageStruct(IntPtr pointer) 53 | { 54 | Pointer = pointer; 55 | } 56 | 57 | public IntPtr Pointer { get; } 58 | 59 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 60 | 61 | private Il2CppImage_24_0_A* NativeImage => (Il2CppImage_24_0_A*)Pointer; 62 | 63 | public ref Il2CppAssembly* Assembly => throw new NotSupportedException(); 64 | 65 | public ref byte Dynamic => ref dynamicDummy; 66 | 67 | public ref IntPtr Name => ref NativeImage->name; 68 | 69 | public bool HasNameNoExt => false; 70 | 71 | public ref IntPtr NameNoExt => throw new NotSupportedException(); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_24_0_B.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("2017.1.3")] 7 | [ApplicableToUnityVersionsSince("2017.2.1")] 8 | public unsafe class NativeImageStructHandler_24_0_B : INativeImageStructHandler 9 | { 10 | public INativeImageStruct CreateNewImageStruct() 11 | { 12 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 13 | 14 | *(Il2CppImage_24_0_B*)pointer = default; 15 | 16 | return new NativeImageStruct(pointer); 17 | } 18 | 19 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 20 | { 21 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 22 | else return new NativeImageStruct((IntPtr)imagePointer); 23 | } 24 | 25 | #if DEBUG 26 | public string GetName() => "NativeImageStructHandler_24_0_B"; 27 | #endif 28 | 29 | [StructLayout(LayoutKind.Sequential)] 30 | internal struct Il2CppImage_24_0_B 31 | { 32 | public IntPtr name; // const char* 33 | public IntPtr nameNoExt; // const char* 34 | public /*AssemblyIndex*/ int assemblyIndex; 35 | 36 | public /*TypeDefinitionIndex*/ int typeStart; 37 | public uint typeCount; 38 | 39 | public /*TypeDefinitionIndex*/ int exportedTypeStart; 40 | public uint exportedTypeCount; 41 | 42 | public /*MethodIndex*/ int entryPointIndex; 43 | 44 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 45 | 46 | public uint token; 47 | } 48 | 49 | internal class NativeImageStruct : INativeImageStruct 50 | { 51 | private static byte dynamicDummy; 52 | 53 | public NativeImageStruct(IntPtr pointer) 54 | { 55 | Pointer = pointer; 56 | } 57 | 58 | public IntPtr Pointer { get; } 59 | 60 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 61 | 62 | private Il2CppImage_24_0_B* NativeImage => (Il2CppImage_24_0_B*)Pointer; 63 | 64 | public ref Il2CppAssembly* Assembly => throw new NotSupportedException(); 65 | 66 | public ref byte Dynamic => ref dynamicDummy; 67 | 68 | public ref IntPtr Name => ref NativeImage->name; 69 | 70 | public bool HasNameNoExt => true; 71 | 72 | public ref IntPtr NameNoExt => ref NativeImage->nameNoExt; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_24_0_C.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("2018.1.0")] 7 | public unsafe class NativeImageStructHandler_24_0_C : INativeImageStructHandler 8 | { 9 | public INativeImageStruct CreateNewImageStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppImage_24_0_C*)pointer = default; 14 | 15 | return new NativeImageStruct(pointer); 16 | } 17 | 18 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 19 | { 20 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 21 | else return new NativeImageStruct((IntPtr)imagePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeImageStructHandler_24_0_C"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppImage_24_0_C 30 | { 31 | public IntPtr name; // const char* 32 | public IntPtr nameNoExt; // const char* 33 | public Il2CppAssembly* assembly; 34 | 35 | public /*TypeDefinitionIndex*/ int typeStart; 36 | public uint typeCount; 37 | 38 | public /*TypeDefinitionIndex*/ int exportedTypeStart; 39 | public uint exportedTypeCount; 40 | 41 | public /*MethodIndex*/ int entryPointIndex; 42 | 43 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 44 | 45 | public uint token; 46 | public byte dynamic; 47 | } 48 | 49 | internal class NativeImageStruct : INativeImageStruct 50 | { 51 | public NativeImageStruct(IntPtr pointer) 52 | { 53 | Pointer = pointer; 54 | } 55 | 56 | public IntPtr Pointer { get; } 57 | 58 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 59 | 60 | private Il2CppImage_24_0_C* NativeImage => (Il2CppImage_24_0_C*)Pointer; 61 | 62 | public ref Il2CppAssembly* Assembly => ref NativeImage->assembly; 63 | 64 | public ref byte Dynamic => ref NativeImage->dynamic; 65 | 66 | public ref IntPtr Name => ref NativeImage->name; 67 | 68 | public bool HasNameNoExt => true; 69 | 70 | public ref IntPtr NameNoExt => ref NativeImage->nameNoExt; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_24_1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("2018.3.0")] 7 | public unsafe class NativeImageStructHandler_24_1 : INativeImageStructHandler 8 | { 9 | public INativeImageStruct CreateNewImageStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppImage_24_1*)pointer = default; 14 | 15 | return new NativeImageStruct(pointer); 16 | } 17 | 18 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 19 | { 20 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 21 | else return new NativeImageStruct((IntPtr)imagePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeImageStructHandler_24_1"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppImage_24_1 30 | { 31 | public IntPtr name; // const char* 32 | public IntPtr nameNoExt; // const char* 33 | public Il2CppAssembly* assembly; 34 | 35 | public /*TypeDefinitionIndex*/ int typeStart; 36 | public uint typeCount; 37 | 38 | public /*TypeDefinitionIndex*/ int exportedTypeStart; 39 | public uint exportedTypeCount; 40 | 41 | public /*CustomAttributeIndex*/ int customAttributeStart; 42 | public uint customAttributeCount; 43 | 44 | public /*MethodIndex*/ int entryPointIndex; 45 | 46 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 47 | 48 | public uint token; 49 | public byte dynamic; 50 | } 51 | 52 | internal class NativeImageStruct : INativeImageStruct 53 | { 54 | public NativeImageStruct(IntPtr pointer) 55 | { 56 | Pointer = pointer; 57 | } 58 | 59 | public IntPtr Pointer { get; } 60 | 61 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 62 | 63 | private Il2CppImage_24_1* NativeImage => (Il2CppImage_24_1*)Pointer; 64 | 65 | public ref Il2CppAssembly* Assembly => ref NativeImage->assembly; 66 | 67 | public ref byte Dynamic => ref NativeImage->dynamic; 68 | 69 | public ref IntPtr Name => ref NativeImage->name; 70 | 71 | public bool HasNameNoExt => true; 72 | 73 | public ref IntPtr NameNoExt => ref NativeImage->nameNoExt; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_24_2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("2019.1.0")] 7 | public unsafe class NativeImageStructHandler_24_2 : INativeImageStructHandler 8 | { 9 | public INativeImageStruct CreateNewImageStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppImage_24_2*)pointer = default; 14 | 15 | return new NativeImageStruct(pointer); 16 | } 17 | 18 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 19 | { 20 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 21 | else return new NativeImageStruct((IntPtr)imagePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeImageStructHandler_24_2"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppImage_24_2 30 | { 31 | public IntPtr name; // const char* 32 | public IntPtr nameNoExt; // const char* 33 | public Il2CppAssembly* assembly; 34 | 35 | public /*TypeDefinitionIndex*/ int typeStart; 36 | public uint typeCount; 37 | 38 | public /*TypeDefinitionIndex*/ int exportedTypeStart; 39 | public uint exportedTypeCount; 40 | 41 | public /*CustomAttributeIndex*/ int customAttributeStart; 42 | public uint customAttributeCount; 43 | 44 | public /*MethodIndex*/ int entryPointIndex; 45 | 46 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 47 | 48 | public /*Il2CppCodeGenModule*/ IntPtr codeGenModule; 49 | 50 | public uint token; 51 | public byte dynamic; 52 | } 53 | 54 | internal class NativeImageStruct : INativeImageStruct 55 | { 56 | public NativeImageStruct(IntPtr pointer) 57 | { 58 | Pointer = pointer; 59 | } 60 | 61 | public IntPtr Pointer { get; } 62 | 63 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 64 | 65 | private Il2CppImage_24_2* NativeImage => (Il2CppImage_24_2*)Pointer; 66 | 67 | public ref Il2CppAssembly* Assembly => ref NativeImage->assembly; 68 | 69 | public ref byte Dynamic => ref NativeImage->dynamic; 70 | 71 | public ref IntPtr Name => ref NativeImage->name; 72 | 73 | public bool HasNameNoExt => true; 74 | 75 | public ref IntPtr NameNoExt => ref NativeImage->nameNoExt; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Images_27_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 5 | { 6 | [ApplicableToUnityVersionsSince("2020.2.0")] 7 | public unsafe class NativeImageStructHandler_27_0 : INativeImageStructHandler 8 | { 9 | public INativeImageStruct CreateNewImageStruct() 10 | { 11 | var pointer = (Il2CppImage_27_0*) Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | var metadataPointer = (Il2CppImageGlobalMetadata_27_0*) Marshal.AllocHGlobal(Marshal.SizeOf()); 13 | 14 | *pointer = default; 15 | *metadataPointer = default; 16 | pointer->metadataHandle = metadataPointer; 17 | metadataPointer->image = pointer; 18 | 19 | return new NativeImageStruct((IntPtr) pointer); 20 | } 21 | 22 | public INativeImageStruct Wrap(Il2CppImage* imagePointer) 23 | { 24 | if ((IntPtr)imagePointer == IntPtr.Zero) return null; 25 | else return new NativeImageStruct((IntPtr)imagePointer); 26 | } 27 | 28 | #if DEBUG 29 | public string GetName() => "NativeImageStructHandler_27_0"; 30 | #endif 31 | 32 | [StructLayout(LayoutKind.Sequential)] 33 | internal struct Il2CppImage_27_0 34 | { 35 | public IntPtr name; // const char* 36 | public IntPtr nameNoExt; // const char* 37 | public Il2CppAssembly* assembly; 38 | 39 | public uint typeCount; 40 | 41 | public uint exportedTypeCount; 42 | public uint customAttributeCount; 43 | 44 | public Il2CppImageGlobalMetadata_27_0* metadataHandle; 45 | 46 | public /*Il2CppNameToTypeDefinitionIndexHashTable **/ IntPtr nameToClassHashTable; 47 | public IntPtr codeGenModule; 48 | 49 | public uint token; 50 | public byte dynamic; 51 | } 52 | 53 | [StructLayout(LayoutKind.Sequential)] 54 | internal struct Il2CppImageGlobalMetadata_27_0 55 | { 56 | public int typeStart; 57 | public int exportedTypeStart; 58 | public int customAttributeStart; 59 | public int entryPointIndex; 60 | public Il2CppImage_27_0* image; 61 | } 62 | 63 | internal class NativeImageStruct : INativeImageStruct 64 | { 65 | public NativeImageStruct(IntPtr pointer) 66 | { 67 | Pointer = pointer; 68 | } 69 | 70 | public IntPtr Pointer { get; } 71 | 72 | public Il2CppImage* ImagePointer => (Il2CppImage*)Pointer; 73 | 74 | private Il2CppImage_27_0* NativeImage => (Il2CppImage_27_0*)Pointer; 75 | 76 | public ref Il2CppAssembly* Assembly => ref NativeImage->assembly; 77 | 78 | public ref byte Dynamic => ref NativeImage->dynamic; 79 | 80 | public ref IntPtr Name => ref NativeImage->name; 81 | 82 | public bool HasNameNoExt => true; 83 | 84 | public ref IntPtr NameNoExt => ref NativeImage->nameNoExt; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Image/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Image 4 | { 5 | public interface INativeImageStructHandler : INativeStructHandler 6 | { 7 | INativeImageStruct CreateNewImageStruct(); 8 | unsafe INativeImageStruct Wrap(Il2CppImage* imagePointer); 9 | #if DEBUG 10 | string GetName(); 11 | #endif 12 | } 13 | 14 | public interface INativeImageStruct : INativeStruct 15 | { 16 | unsafe Il2CppImage* ImagePointer { get; } 17 | 18 | unsafe ref Il2CppAssembly* Assembly { get; } 19 | 20 | ref byte Dynamic { get; } 21 | 22 | ref IntPtr Name { get; } 23 | 24 | bool HasNameNoExt { get; } 25 | 26 | ref IntPtr NameNoExt { get; } 27 | } 28 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/MethodInfo/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.MethodInfo 4 | { 5 | public interface INativeMethodInfoStructHandler : INativeStructHandler 6 | { 7 | INativeMethodInfoStruct CreateNewMethodStruct(); 8 | unsafe INativeMethodInfoStruct Wrap(Il2CppMethodInfo* methodPointer); 9 | IntPtr GetMethodFromReflection(IntPtr method); 10 | IntPtr CopyMethodInfoStruct(IntPtr origMethodInfo); 11 | IntPtr il2cpp_method_get_class(IntPtr method); 12 | IntPtr il2cpp_method_get_name(IntPtr method); 13 | uint il2cpp_method_get_param_count(IntPtr method); 14 | IntPtr il2cpp_method_get_return_type(IntPtr method); 15 | uint il2cpp_method_get_token(IntPtr method); 16 | #if DEBUG 17 | string GetName(); 18 | #endif 19 | } 20 | 21 | 22 | public interface INativeMethodInfoStruct : INativeStruct 23 | { 24 | int StructSize { get; } 25 | unsafe Il2CppMethodInfo* MethodInfoPointer { get; } 26 | ref IntPtr Name { get; } 27 | ref ushort Slot { get; } 28 | ref IntPtr MethodPointer { get; } 29 | unsafe ref Il2CppClass* Class { get; } 30 | ref IntPtr InvokerMethod { get; } 31 | unsafe ref Il2CppTypeStruct* ReturnType { get; } 32 | ref Il2CppMethodFlags Flags { get; } 33 | ref byte ParametersCount { get; } 34 | unsafe ref Il2CppParameterInfo* Parameters { get; } 35 | bool IsGeneric { get; set; } 36 | bool IsInflated { get; set; } 37 | bool IsMarshalledFromNative { get; set; } 38 | } 39 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/ParameterInfo/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.ParameterInfo 4 | { 5 | public interface INativeParameterInfoStructHandler : INativeStructHandler 6 | { 7 | unsafe Il2CppParameterInfo*[] CreateNewParameterInfoArray(int paramCount); 8 | unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoPointer); 9 | unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoListBegin, int index); 10 | bool HasNamePosToken { get; } 11 | #if DEBUG 12 | string GetName(); 13 | #endif 14 | } 15 | 16 | public interface INativeParameterInfoStruct : INativeStruct 17 | { 18 | unsafe Il2CppParameterInfo* ParameterInfoPointer { get; } 19 | bool HasNamePosToken { get; } 20 | ref IntPtr Name { get; } 21 | ref int Position { get; } 22 | ref uint Token { get; } 23 | unsafe ref Il2CppTypeStruct* ParameterType { get; } 24 | } 25 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.ParameterInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | internal class NativeParameterInfoStructHandler_16_0 : INativeParameterInfoStructHandler 8 | { 9 | public unsafe Il2CppParameterInfo*[] CreateNewParameterInfoArray(int paramCount) 10 | { 11 | var ptr = (Il2CppParameterInfo_16_0*) Marshal.AllocHGlobal(Marshal.SizeOf() * paramCount); 12 | var res = new Il2CppParameterInfo*[paramCount]; 13 | for (var i = 0; i < paramCount; i++) 14 | { 15 | ptr[i] = default; 16 | res[i] = (Il2CppParameterInfo*) &ptr[i]; 17 | } 18 | return res; 19 | } 20 | 21 | public unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoPointer) 22 | { 23 | if ((IntPtr)paramInfoPointer == IntPtr.Zero) return null; 24 | else return new NativeParameterInfoStructWrapper((IntPtr) paramInfoPointer); 25 | } 26 | 27 | public unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoListBegin, int index) 28 | { 29 | if ((IntPtr)paramInfoListBegin == IntPtr.Zero) return null; 30 | else return new NativeParameterInfoStructWrapper((IntPtr) paramInfoListBegin + (Marshal.SizeOf() * index)); 31 | } 32 | 33 | public bool HasNamePosToken => true; 34 | 35 | #if DEBUG 36 | public string GetName() => "NativeParameterInfoStructHandler_16_0"; 37 | #endif 38 | 39 | [StructLayout(LayoutKind.Sequential)] 40 | internal unsafe struct Il2CppParameterInfo_16_0 41 | { 42 | public IntPtr name; // const char* 43 | public int position; 44 | public uint token; 45 | public int customAttributeIndex; 46 | public Il2CppTypeStruct* parameter_type; // const 47 | } 48 | 49 | internal unsafe class NativeParameterInfoStructWrapper : INativeParameterInfoStruct 50 | { 51 | public NativeParameterInfoStructWrapper(IntPtr pointer) 52 | { 53 | Pointer = pointer; 54 | } 55 | 56 | public IntPtr Pointer { get; } 57 | 58 | public Il2CppParameterInfo* ParameterInfoPointer => (Il2CppParameterInfo*)Pointer; 59 | 60 | public bool HasNamePosToken => true; 61 | 62 | private Il2CppParameterInfo_16_0* NativeParameter => (Il2CppParameterInfo_16_0*)Pointer; 63 | 64 | public ref IntPtr Name => ref NativeParameter->name; 65 | 66 | public ref int Position => ref NativeParameter->position; 67 | 68 | public ref uint Token => ref NativeParameter->token; 69 | 70 | public ref Il2CppTypeStruct* ParameterType => ref NativeParameter->parameter_type; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.ParameterInfo 5 | { 6 | [ApplicableToUnityVersionsSince("2018.3.0")] 7 | internal class NativeParameterInfoStructHandler_24_1 : INativeParameterInfoStructHandler 8 | { 9 | public unsafe Il2CppParameterInfo*[] CreateNewParameterInfoArray(int paramCount) 10 | { 11 | var ptr = (Il2CppParameterInfo_24_1*) Marshal.AllocHGlobal(Marshal.SizeOf() * paramCount); 12 | var res = new Il2CppParameterInfo*[paramCount]; 13 | for (var i = 0; i < paramCount; i++) 14 | { 15 | ptr[i] = default; 16 | res[i] = (Il2CppParameterInfo*) &ptr[i]; 17 | } 18 | return res; 19 | } 20 | 21 | public unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoPointer) 22 | { 23 | if ((IntPtr)paramInfoPointer == IntPtr.Zero) return null; 24 | else return new NativeParameterInfoStructWrapper((IntPtr) paramInfoPointer); 25 | } 26 | 27 | public unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoListBegin, int index) 28 | { 29 | if ((IntPtr)paramInfoListBegin == IntPtr.Zero) return null; 30 | else return new NativeParameterInfoStructWrapper((IntPtr) paramInfoListBegin + (Marshal.SizeOf() * index)); 31 | } 32 | 33 | public bool HasNamePosToken => true; 34 | 35 | #if DEBUG 36 | public string GetName() => "NativeParameterInfoStructHandler_24_1"; 37 | #endif 38 | 39 | [StructLayout(LayoutKind.Sequential)] 40 | internal unsafe struct Il2CppParameterInfo_24_1 41 | { 42 | public IntPtr name; // const char* 43 | public int position; 44 | public uint token; 45 | public Il2CppTypeStruct* parameter_type; // const 46 | } 47 | 48 | internal unsafe class NativeParameterInfoStructWrapper : INativeParameterInfoStruct 49 | { 50 | public NativeParameterInfoStructWrapper(IntPtr pointer) 51 | { 52 | Pointer = pointer; 53 | } 54 | 55 | public IntPtr Pointer { get; } 56 | 57 | public Il2CppParameterInfo* ParameterInfoPointer => (Il2CppParameterInfo*)Pointer; 58 | 59 | public bool HasNamePosToken => true; 60 | 61 | private Il2CppParameterInfo_24_1* NativeParameter => (Il2CppParameterInfo_24_1*)Pointer; 62 | 63 | public ref IntPtr Name => ref NativeParameter->name; 64 | 65 | public ref int Position => ref NativeParameter->position; 66 | 67 | public ref uint Token => ref NativeParameter->token; 68 | 69 | public ref Il2CppTypeStruct* ParameterType => ref NativeParameter->parameter_type; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.ParameterInfo 5 | { 6 | [ApplicableToUnityVersionsSince("2021.2.0")] 7 | internal class NativeParameterInfoStructHandler_27_3 : INativeParameterInfoStructHandler 8 | { 9 | public unsafe Il2CppParameterInfo*[] CreateNewParameterInfoArray(int paramCount) 10 | { 11 | var ptr = (Il2CppParameterInfo_27_3*)Marshal.AllocHGlobal(Marshal.SizeOf() * paramCount); 12 | var res = new Il2CppParameterInfo*[paramCount]; 13 | for (var i = 0; i < paramCount; i++) 14 | { 15 | ptr[i] = default; 16 | res[i] = (Il2CppParameterInfo*)&ptr[i]; 17 | } 18 | return res; 19 | } 20 | 21 | public unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoPointer) 22 | { 23 | if ((IntPtr)paramInfoPointer == IntPtr.Zero) return null; 24 | else return new NativeParameterInfoStructWrapper((IntPtr)paramInfoPointer); 25 | } 26 | 27 | public unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* paramInfoListBegin, int index) 28 | { 29 | if ((IntPtr)paramInfoListBegin == IntPtr.Zero) return null; 30 | else return new NativeParameterInfoStructWrapper((IntPtr) paramInfoListBegin + (Marshal.SizeOf() * index)); 31 | } 32 | 33 | public bool HasNamePosToken => false; 34 | 35 | #if DEBUG 36 | public string GetName() => "NativeParameterInfoStructHandler_27_3"; 37 | #endif 38 | 39 | //Doesn't actually exist; just using this for type pointer storage in MethodInfo 27_3 + 40 | [StructLayout(LayoutKind.Sequential)] 41 | internal unsafe struct Il2CppParameterInfo_27_3 42 | { 43 | public Il2CppTypeStruct* parameter_type; 44 | } 45 | 46 | internal unsafe class NativeParameterInfoStructWrapper : INativeParameterInfoStruct 47 | { 48 | public NativeParameterInfoStructWrapper(IntPtr pointer) 49 | { 50 | Pointer = pointer; 51 | } 52 | 53 | public IntPtr Pointer { get; } 54 | 55 | public Il2CppParameterInfo* ParameterInfoPointer => (Il2CppParameterInfo*)Pointer; 56 | 57 | public bool HasNamePosToken => false; 58 | 59 | private Il2CppParameterInfo_27_3* NativeParameter => (Il2CppParameterInfo_27_3*)Pointer; 60 | 61 | public ref IntPtr Name => throw new NotSupportedException("ParameterInfo does not exist in Unity 2021.2.0+"); 62 | 63 | public ref int Position => throw new NotSupportedException("ParameterInfo does not exist in Unity 2021.2.0+"); 64 | 65 | public ref uint Token => throw new NotSupportedException("ParameterInfo does not exist in Unity 2021.2.0+"); 66 | 67 | public ref Il2CppTypeStruct* ParameterType => ref NativeParameter->parameter_type; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/PropertyInfo/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.PropertyInfo 4 | { 5 | public interface INativePropertyInfoStructHandler : INativeStructHandler 6 | { 7 | INativePropertyInfoStruct CreateNewPropertyInfoStruct(); 8 | unsafe INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* propertyInfoPointer); 9 | IntPtr il2cpp_property_get_name(IntPtr prop); 10 | IntPtr il2cpp_property_get_parent(IntPtr prop); 11 | IntPtr il2cpp_property_get_get_method(IntPtr prop); 12 | IntPtr il2cpp_property_get_set_method(IntPtr prop); 13 | #if DEBUG 14 | string GetName(); 15 | #endif 16 | } 17 | 18 | public interface INativePropertyInfoStruct : INativeStruct 19 | { 20 | unsafe Il2CppPropertyInfo* PropertyInfoPointer { get; } 21 | 22 | ref IntPtr Name { get; } 23 | 24 | unsafe ref Il2CppClass* Parent { get; } 25 | 26 | unsafe ref Il2CppMethodInfo* Get { get; } 27 | 28 | unsafe ref Il2CppMethodInfo* Set { get; } 29 | 30 | ref uint Attrs { get; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.PropertyInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativePropertyInfoStructHandler_16_0 : INativePropertyInfoStructHandler 8 | { 9 | public INativePropertyInfoStruct CreateNewPropertyInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppPropertyInfo_16_0*)pointer = default; 14 | 15 | return new NativePropertyInfoStruct(pointer); 16 | } 17 | 18 | public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* propertyInfoPointer) 19 | { 20 | if ((IntPtr)propertyInfoPointer == IntPtr.Zero) return null; 21 | else return new NativePropertyInfoStruct((IntPtr)propertyInfoPointer); 22 | } 23 | 24 | public IntPtr il2cpp_property_get_name(IntPtr prop) => ((Il2CppPropertyInfo_16_0*)prop)->name; 25 | public IntPtr il2cpp_property_get_parent(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_16_0*)prop)->parent; 26 | public IntPtr il2cpp_property_get_get_method(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_16_0*)prop)->get; 27 | public IntPtr il2cpp_property_get_set_method(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_16_0*)prop)->set; 28 | 29 | #if DEBUG 30 | public string GetName() => "NativePropertyInfoStructHandler_16_0"; 31 | #endif 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct Il2CppPropertyInfo_16_0 35 | { 36 | public Il2CppClass* parent; 37 | public IntPtr name; // const char* 38 | public Il2CppMethodInfo* get; // const 39 | public Il2CppMethodInfo* set; // const 40 | public uint attrs; 41 | public int customAttributeIndex; 42 | } 43 | 44 | internal class NativePropertyInfoStruct : INativePropertyInfoStruct 45 | { 46 | public NativePropertyInfoStruct(IntPtr pointer) 47 | { 48 | Pointer = pointer; 49 | } 50 | 51 | public IntPtr Pointer { get; } 52 | 53 | public Il2CppPropertyInfo* PropertyInfoPointer => (Il2CppPropertyInfo*)Pointer; 54 | 55 | private Il2CppPropertyInfo_16_0* NativeProperty => (Il2CppPropertyInfo_16_0*)Pointer; 56 | 57 | public ref IntPtr Name => ref NativeProperty->name; 58 | 59 | public ref Il2CppClass* Parent => ref NativeProperty->parent; 60 | 61 | public ref Il2CppMethodInfo* Get => ref NativeProperty->get; 62 | 63 | public ref Il2CppMethodInfo* Set => ref NativeProperty->set; 64 | 65 | public ref uint Attrs => ref NativeProperty->attrs; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.PropertyInfo 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.2")] 7 | public unsafe class NativePropertyInfoStructHandler_19_0 : INativePropertyInfoStructHandler 8 | { 9 | public INativePropertyInfoStruct CreateNewPropertyInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppPropertyInfo_19_0*)pointer = default; 14 | 15 | return new NativePropertyInfoStruct(pointer); 16 | } 17 | 18 | public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* propertyInfoPointer) 19 | { 20 | if ((IntPtr)propertyInfoPointer == IntPtr.Zero) return null; 21 | else return new NativePropertyInfoStruct((IntPtr)propertyInfoPointer); 22 | } 23 | 24 | public IntPtr il2cpp_property_get_name(IntPtr prop) => ((Il2CppPropertyInfo_19_0*)prop)->name; 25 | public IntPtr il2cpp_property_get_parent(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_19_0*)prop)->parent; 26 | public IntPtr il2cpp_property_get_get_method(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_19_0*)prop)->get; 27 | public IntPtr il2cpp_property_get_set_method(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_19_0*)prop)->set; 28 | 29 | #if DEBUG 30 | public string GetName() => "NativePropertyInfoStructHandler_19_0"; 31 | #endif 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct Il2CppPropertyInfo_19_0 35 | { 36 | public Il2CppClass* parent; 37 | public IntPtr name; // const char* 38 | public Il2CppMethodInfo* get; // const 39 | public Il2CppMethodInfo* set; // const 40 | public uint attrs; 41 | public int customAttributeIndex; 42 | public uint token; 43 | } 44 | 45 | internal class NativePropertyInfoStruct : INativePropertyInfoStruct 46 | { 47 | public NativePropertyInfoStruct(IntPtr pointer) 48 | { 49 | Pointer = pointer; 50 | } 51 | 52 | public IntPtr Pointer { get; } 53 | 54 | public Il2CppPropertyInfo* PropertyInfoPointer => (Il2CppPropertyInfo*)Pointer; 55 | 56 | private Il2CppPropertyInfo_19_0* NativeProperty => (Il2CppPropertyInfo_19_0*)Pointer; 57 | 58 | public ref IntPtr Name => ref NativeProperty->name; 59 | 60 | public ref Il2CppClass* Parent => ref NativeProperty->parent; 61 | 62 | public ref Il2CppMethodInfo* Get => ref NativeProperty->get; 63 | 64 | public ref Il2CppMethodInfo* Set => ref NativeProperty->set; 65 | 66 | public ref uint Attrs => ref NativeProperty->attrs; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.PropertyInfo 5 | { 6 | [ApplicableToUnityVersionsSince("2018.3.0")] 7 | public unsafe class NativePropertyInfoStructHandler_24_1 : INativePropertyInfoStructHandler 8 | { 9 | public INativePropertyInfoStruct CreateNewPropertyInfoStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppPropertyInfo_24_1*)pointer = default; 14 | 15 | return new NativePropertyInfoStruct(pointer); 16 | } 17 | 18 | public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* propertyInfoPointer) 19 | { 20 | if ((IntPtr)propertyInfoPointer == IntPtr.Zero) return null; 21 | else return new NativePropertyInfoStruct((IntPtr)propertyInfoPointer); 22 | } 23 | 24 | public IntPtr il2cpp_property_get_name(IntPtr prop) => ((Il2CppPropertyInfo_24_1*)prop)->name; 25 | public IntPtr il2cpp_property_get_parent(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_24_1*)prop)->parent; 26 | public IntPtr il2cpp_property_get_get_method(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_24_1*)prop)->get; 27 | public IntPtr il2cpp_property_get_set_method(IntPtr prop) => (IntPtr)((Il2CppPropertyInfo_24_1*)prop)->set; 28 | 29 | #if DEBUG 30 | public string GetName() => "NativePropertyInfoStructHandler_24_1"; 31 | #endif 32 | 33 | [StructLayout(LayoutKind.Sequential)] 34 | internal struct Il2CppPropertyInfo_24_1 35 | { 36 | public Il2CppClass* parent; 37 | public IntPtr name; // const char* 38 | public Il2CppMethodInfo* get; // const 39 | public Il2CppMethodInfo* set; // const 40 | public uint attrs; 41 | public uint token; 42 | } 43 | 44 | internal class NativePropertyInfoStruct : INativePropertyInfoStruct 45 | { 46 | public NativePropertyInfoStruct(IntPtr pointer) 47 | { 48 | Pointer = pointer; 49 | } 50 | 51 | public IntPtr Pointer { get; } 52 | 53 | public Il2CppPropertyInfo* PropertyInfoPointer => (Il2CppPropertyInfo*)Pointer; 54 | 55 | private Il2CppPropertyInfo_24_1* NativeProperty => (Il2CppPropertyInfo_24_1*)Pointer; 56 | 57 | public ref IntPtr Name => ref NativeProperty->name; 58 | 59 | public ref Il2CppClass* Parent => ref NativeProperty->parent; 60 | 61 | public ref Il2CppMethodInfo* Get => ref NativeProperty->get; 62 | 63 | public ref Il2CppMethodInfo* Set => ref NativeProperty->set; 64 | 65 | public ref uint Attrs => ref NativeProperty->attrs; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Type/Interfaces.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Type 4 | { 5 | public interface INativeTypeStructHandler : INativeStructHandler 6 | { 7 | INativeTypeStruct CreateNewTypeStruct(); 8 | unsafe INativeTypeStruct Wrap(Il2CppTypeStruct* typePointer); 9 | #if DEBUG 10 | string GetName(); 11 | #endif 12 | } 13 | 14 | public interface INativeTypeStruct : INativeStruct 15 | { 16 | unsafe Il2CppTypeStruct* TypePointer { get; } 17 | 18 | ref IntPtr Data { get; } 19 | 20 | ref Il2CppTypeEnum Type { get; } 21 | 22 | bool ByRef { get; set; } 23 | 24 | bool Pinned { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Type/Type_16_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Type 5 | { 6 | [ApplicableToUnityVersionsSince("5.3.0")] 7 | public unsafe class NativeTypeStructHandler_16_0 : INativeTypeStructHandler 8 | { 9 | public INativeTypeStruct CreateNewTypeStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppType_16_0*)pointer = default; 14 | 15 | return new NativeTypeStruct(pointer); 16 | } 17 | 18 | public INativeTypeStruct Wrap(Il2CppTypeStruct* typePointer) 19 | { 20 | if ((IntPtr)typePointer == IntPtr.Zero) return null; 21 | else return new NativeTypeStruct((IntPtr)typePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeTypeStructHandler_16_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppType_16_0 30 | { 31 | /*union 32 | { 33 | // We have this dummy field first because pre C99 compilers (MSVC) can only initializer the first value in a union. 34 | void* dummy; 35 | TypeDefinitionIndex klassIndex; /* for VALUETYPE and CLASS #1# 36 | const Il2CppType *type; /* for PTR and SZARRAY #1# 37 | Il2CppArrayType *array; /* for ARRAY #1# 38 | //MonoMethodSignature *method; 39 | GenericParameterIndex genericParameterIndex; /* for VAR and MVAR #1# 40 | Il2CppGenericClass *generic_class; /* for GENERICINST #1# 41 | } data;*/ 42 | public IntPtr data; 43 | 44 | public ushort attrs; 45 | public Il2CppTypeEnum type; 46 | public byte mods_byref_pin; 47 | /*unsigned int attrs : 16; /* param attributes or field flags #1# 48 | Il2CppTypeEnum type : 8; 49 | unsigned int num_mods : 6; /* max 64 modifiers follow at the end #1# 50 | unsigned int byref : 1; 51 | unsigned int pinned : 1; /* valid when included in a local var signature #1#*/ 52 | //MonoCustomMod modifiers [MONO_ZERO_LEN_ARRAY]; /* this may grow */ 53 | } 54 | 55 | private class NativeTypeStruct : INativeTypeStruct 56 | { 57 | public NativeTypeStruct(IntPtr pointer) 58 | { 59 | Pointer = pointer; 60 | } 61 | 62 | private static int mods_byref_pin_offset = 63 | Marshal.OffsetOf(nameof(Il2CppType_16_0.mods_byref_pin)).ToInt32(); 64 | 65 | public IntPtr Pointer { get; } 66 | 67 | public Il2CppTypeStruct* TypePointer => (Il2CppTypeStruct*)Pointer; 68 | 69 | private Il2CppType_16_0* NativeType => (Il2CppType_16_0*)Pointer; 70 | 71 | public ref IntPtr Data => ref NativeType->data; 72 | 73 | public ref Il2CppTypeEnum Type => ref NativeType->type; 74 | 75 | public bool ByRef 76 | { 77 | get => this.CheckBit(mods_byref_pin_offset, 6); 78 | set => this.SetBit(mods_byref_pin_offset, 6, value); 79 | } 80 | 81 | public bool Pinned 82 | { 83 | get => this.CheckBit(mods_byref_pin_offset, 7); 84 | set => this.SetBit(mods_byref_pin_offset, 7, value); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/Runtime/VersionSpecific/Type/Type_27_0.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace UnhollowerBaseLib.Runtime.VersionSpecific.Type 5 | { 6 | [ApplicableToUnityVersionsSince("2020.2.0")] 7 | public unsafe class NativeTypeStructHandler_27_0 : INativeTypeStructHandler 8 | { 9 | public INativeTypeStruct CreateNewTypeStruct() 10 | { 11 | var pointer = Marshal.AllocHGlobal(Marshal.SizeOf()); 12 | 13 | *(Il2CppType_27_0*)pointer = default; 14 | 15 | return new NativeTypeStruct(pointer); 16 | } 17 | 18 | public INativeTypeStruct Wrap(Il2CppTypeStruct* typePointer) 19 | { 20 | if ((IntPtr)typePointer == IntPtr.Zero) return null; 21 | else return new NativeTypeStruct((IntPtr)typePointer); 22 | } 23 | 24 | #if DEBUG 25 | public string GetName() => "NativeTypeStructHandler_27_0"; 26 | #endif 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | internal struct Il2CppType_27_0 30 | { 31 | /*union 32 | { 33 | // We have this dummy field first because pre C99 compilers (MSVC) can only initializer the first value in a union. 34 | void* dummy; 35 | TypeDefinitionIndex klassIndex; /* for VALUETYPE and CLASS #1# 36 | Il2CppMetadataTypeHandle typeHandle; 37 | const Il2CppType *type; /* for PTR and SZARRAY #1# 38 | Il2CppArrayType *array; /* for ARRAY #1# 39 | //MonoMethodSignature *method; 40 | GenericParameterIndex genericParameterIndex; /* for VAR and MVAR #1# 41 | Il2CppMetadataGenericParameterHandle genericParameterHandle; 42 | Il2CppGenericClass *generic_class; /* for GENERICINST #1# 43 | } data;*/ 44 | public IntPtr data; 45 | 46 | public ushort attrs; 47 | public Il2CppTypeEnum type; 48 | public byte mods_byref_pin; 49 | /*unsigned int attrs : 16; /* param attributes or field flags #1# 50 | Il2CppTypeEnum type : 8; 51 | unsigned int num_mods : 6; /* max 64 modifiers follow at the end #1# 52 | unsigned int byref : 1; 53 | unsigned int pinned : 1; /* valid when included in a local var signature #1#*/ 54 | //MonoCustomMod modifiers [MONO_ZERO_LEN_ARRAY]; /* this may grow */ 55 | } 56 | 57 | private class NativeTypeStruct : INativeTypeStruct 58 | { 59 | public NativeTypeStruct(IntPtr pointer) 60 | { 61 | Pointer = pointer; 62 | } 63 | 64 | private static int mods_byref_pin_offset = 65 | Marshal.OffsetOf(nameof(Il2CppType_27_0.mods_byref_pin)).ToInt32(); 66 | 67 | public IntPtr Pointer { get; } 68 | 69 | public Il2CppTypeStruct* TypePointer => (Il2CppTypeStruct*)Pointer; 70 | 71 | private Il2CppType_27_0* NativeType => (Il2CppType_27_0*)Pointer; 72 | 73 | public ref IntPtr Data => ref NativeType->data; 74 | 75 | public ref Il2CppTypeEnum Type => ref NativeType->type; 76 | 77 | public bool ByRef 78 | { 79 | get => this.CheckBit(mods_byref_pin_offset, 6); 80 | set => this.SetBit(mods_byref_pin_offset, 6, value); 81 | } 82 | 83 | public bool Pinned 84 | { 85 | get => this.CheckBit(mods_byref_pin_offset, 7); 86 | set => this.SetBit(mods_byref_pin_offset, 7, value); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/RuntimeReflectionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Il2CppSystem.Reflection; 3 | using UnhollowerBaseLib; 4 | using RuntimeTypeHandle = Il2CppSystem.RuntimeTypeHandle; 5 | using Type = Il2CppSystem.Type; 6 | 7 | namespace UnhollowerRuntimeLib 8 | { 9 | public static class RuntimeReflectionHelper 10 | { 11 | public static IntPtr GetNestedTypeViaReflection(IntPtr enclosingClass, string nestedTypeName) 12 | { 13 | var reflectionType = Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(enclosingClass)); 14 | var nestedType = reflectionType.GetNestedType(nestedTypeName, BindingFlags.Public | BindingFlags.NonPublic); 15 | 16 | return nestedType != null ? IL2CPP.il2cpp_class_from_system_type(nestedType.Pointer) : IntPtr.Zero; 17 | } 18 | 19 | public static RuntimeTypeHandle GetRuntimeTypeHandle() 20 | { 21 | return Il2CppType.Of().TypeHandle; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/RuntimeSpecificsStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | 5 | namespace UnhollowerBaseLib 6 | { 7 | public static class RuntimeSpecificsStore 8 | { 9 | private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); 10 | private static readonly Dictionary UsesWeakRefsStore = new Dictionary(); 11 | private static readonly Dictionary WasInjectedStore = new Dictionary(); 12 | 13 | public static bool ShouldUseWeakRefs(IntPtr nativeClass) 14 | { 15 | Lock.EnterReadLock(); 16 | try 17 | { 18 | return UsesWeakRefsStore.TryGetValue(nativeClass, out var result) && result; 19 | } 20 | finally 21 | { 22 | Lock.ExitReadLock(); 23 | } 24 | } 25 | 26 | public static bool IsInjected(IntPtr nativeClass) 27 | { 28 | Lock.EnterReadLock(); 29 | try 30 | { 31 | return WasInjectedStore.TryGetValue(nativeClass, out var result) && result; 32 | } 33 | finally 34 | { 35 | Lock.ExitReadLock(); 36 | } 37 | } 38 | 39 | public static void SetClassInfo(IntPtr nativeClass, bool useWeakRefs, bool wasInjected) 40 | { 41 | Lock.EnterWriteLock(); 42 | try 43 | { 44 | UsesWeakRefsStore[nativeClass] = useWeakRefs; 45 | WasInjectedStore[nativeClass] = wasInjected; 46 | } 47 | finally 48 | { 49 | Lock.ExitWriteLock(); 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/UnhollowerBaseLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net4.7.2;netstandard2.1 5 | true 6 | latest 7 | 0.4.18.0 8 | 9 | 10 | 11 | 12 | false 13 | Libs\Il2Cppmscorlib.dll 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | all 29 | runtime; build; native; contentfiles; analyzers; buildtransitive 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /UnhollowerBaseLib/UnhollowerUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Reflection.Emit; 5 | 6 | namespace UnhollowerBaseLib 7 | { 8 | public class UnhollowerUtils 9 | { 10 | private static FieldInfo GetFieldInfoFromMethod(MethodBase method, string prefix) 11 | { 12 | var body = method.GetMethodBody(); 13 | if (body == null) throw new ArgumentException("Target method may not be abstract"); 14 | var methodModule = method.DeclaringType.Assembly.Modules.Single(); 15 | foreach (var (opCode, opArg) in MiniIlParser.Decode(body.GetILAsByteArray())) 16 | { 17 | if (opCode != OpCodes.Ldsfld) continue; 18 | var fieldInfo = methodModule.ResolveField((int) opArg); 19 | if (fieldInfo?.FieldType != typeof(IntPtr) || !fieldInfo.Name.StartsWith(prefix)) continue; 20 | return fieldInfo; 21 | } 22 | return null; 23 | } 24 | 25 | public static FieldInfo GetIl2CppMethodInfoPointerFieldForGeneratedMethod(MethodBase method) 26 | { 27 | return GetFieldInfoFromMethod(method, "NativeMethodInfoPtr_"); 28 | } 29 | 30 | public static FieldInfo GetIl2CppFieldInfoPointerFieldForGeneratedFieldAccessor(MethodBase method) 31 | { 32 | return GetFieldInfoFromMethod(method, "NativeFieldInfoPtr_"); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/XrefScans/XrefInstance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace UnhollowerRuntimeLib.XrefScans 6 | { 7 | public readonly struct XrefInstance 8 | { 9 | public readonly XrefType Type; 10 | public readonly IntPtr Pointer; 11 | public readonly IntPtr FoundAt; 12 | 13 | public XrefInstance(XrefType type, IntPtr pointer, IntPtr foundAt) 14 | { 15 | Type = type; 16 | Pointer = pointer; 17 | FoundAt = foundAt; 18 | } 19 | 20 | internal XrefInstance RelativeToBase(long baseAddress) 21 | { 22 | return new XrefInstance(Type, (IntPtr) ((long) Pointer - baseAddress), (IntPtr) ((long) FoundAt - baseAddress)); 23 | } 24 | 25 | public Il2CppSystem.Object ReadAsObject() 26 | { 27 | if (Type != XrefType.Global) throw new InvalidOperationException("Can't read non-global xref as object"); 28 | 29 | var valueAtPointer = Marshal.ReadIntPtr(Pointer); 30 | if (valueAtPointer == IntPtr.Zero) 31 | return null; 32 | 33 | return new Il2CppSystem.Object(valueAtPointer); 34 | } 35 | 36 | public MethodBase TryResolve() 37 | { 38 | if (Type != XrefType.Method) throw new InvalidOperationException("Can't resolve non-method xrefs"); 39 | 40 | return XrefScanMethodDb.TryResolvePointer(Pointer); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/XrefScans/XrefScanMetadataRuntimeUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | using UnhollowerBaseLib; 6 | using UnhollowerBaseLib.Runtime; 7 | using AppDomain = Il2CppSystem.AppDomain; 8 | using BindingFlags = Il2CppSystem.Reflection.BindingFlags; 9 | 10 | namespace UnhollowerRuntimeLib.XrefScans 11 | { 12 | internal static class XrefScanMetadataRuntimeUtil 13 | { 14 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 15 | internal delegate void InitMetadataForMethod(int metadataUsageToken); 16 | 17 | private static InitMetadataForMethod ourMetadataInitForMethodDelegate; 18 | private static IntPtr ourMetadataInitForMethodPointer; 19 | 20 | private static unsafe void FindMetadataInitForMethod() 21 | { 22 | var unityObjectCctor = AppDomain.CurrentDomain.GetAssemblies() 23 | .Single(it => it.GetSimpleName() == "UnityEngine.CoreModule").GetType("UnityEngine.Object") 24 | .GetConstructors(BindingFlags.Static | BindingFlags.NonPublic).Single(); 25 | var nativeMethodInfo = UnityVersionHandler.GetMethodFromReflection(unityObjectCctor.Pointer); 26 | ourMetadataInitForMethodPointer = XrefScannerLowLevel.JumpTargets(*(IntPtr*) nativeMethodInfo).First(); 27 | ourMetadataInitForMethodDelegate = Marshal.GetDelegateForFunctionPointer(ourMetadataInitForMethodPointer); 28 | } 29 | 30 | internal static unsafe bool CallMetadataInitForMethod(MethodBase method) 31 | { 32 | if (ourMetadataInitForMethodPointer == IntPtr.Zero) 33 | FindMetadataInitForMethod(); 34 | 35 | var nativeMethodInfoObject = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(method)?.GetValue(null); 36 | if (nativeMethodInfoObject == null) return false; 37 | var nativeMethodInfo = (IntPtr) nativeMethodInfoObject; 38 | var codeStart = *(IntPtr*) nativeMethodInfo; 39 | var firstCall = XrefScannerLowLevel.JumpTargets(codeStart).FirstOrDefault(); 40 | if (firstCall != ourMetadataInitForMethodPointer || firstCall == IntPtr.Zero) return false; 41 | 42 | var tokenPointer = XrefScanUtilFinder.FindLastRcxReadAddressBeforeCallTo(codeStart, ourMetadataInitForMethodPointer); 43 | var initFlagPointer = XrefScanUtilFinder.FindByteWriteTargetRightAfterCallTo(codeStart, ourMetadataInitForMethodPointer); 44 | 45 | if (tokenPointer == IntPtr.Zero || initFlagPointer == IntPtr.Zero) return false; 46 | 47 | if (Marshal.ReadByte(initFlagPointer) == 0) 48 | { 49 | ourMetadataInitForMethodDelegate(Marshal.ReadInt32(tokenPointer)); 50 | Marshal.WriteByte(initFlagPointer, 1); 51 | } 52 | 53 | return true; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/XrefScans/XrefScanMethodDb.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | using UnhollowerBaseLib; 7 | using UnhollowerBaseLib.Attributes; 8 | using UnhollowerBaseLib.Maps; 9 | 10 | namespace UnhollowerRuntimeLib.XrefScans 11 | { 12 | public static class XrefScanMethodDb 13 | { 14 | private static readonly MethodAddressToTokenMap MethodMap; 15 | private static readonly MethodXrefScanCache XrefScanCache; 16 | private static readonly long GameAssemblyBase; 17 | 18 | private static XrefScanMetadataRuntimeUtil.InitMetadataForMethod ourMetadataInitForMethodDelegate; 19 | 20 | static XrefScanMethodDb() 21 | { 22 | MethodMap = new MethodAddressToTokenMap(GeneratedDatabasesUtil.GetDatabasePath(MethodAddressToTokenMap.FileName)); 23 | XrefScanCache = new MethodXrefScanCache(GeneratedDatabasesUtil.GetDatabasePath(MethodXrefScanCache.FileName)); 24 | 25 | foreach (ProcessModule module in Process.GetCurrentProcess().Modules) 26 | { 27 | if (module.ModuleName == "GameAssembly.dll") 28 | { 29 | GameAssemblyBase = (long) module.BaseAddress; 30 | break; 31 | } 32 | } 33 | } 34 | 35 | public static MethodBase TryResolvePointer(IntPtr methodStart) 36 | { 37 | return MethodMap.Lookup((long) methodStart - GameAssemblyBase); 38 | } 39 | 40 | internal static IEnumerable ListUsers(CachedScanResultsAttribute attribute) 41 | { 42 | for (var i = attribute.RefRangeStart; i < attribute.RefRangeEnd; i++) 43 | yield return XrefScanCache.GetAt(i).AsXrefInstance(GameAssemblyBase); 44 | } 45 | 46 | internal static IEnumerable CachedXrefScan(CachedScanResultsAttribute attribute) 47 | { 48 | for (var i = attribute.XrefRangeStart; i < attribute.XrefRangeEnd; i++) 49 | yield return XrefScanCache.GetAt(i).AsXrefInstance(GameAssemblyBase); 50 | } 51 | 52 | internal static void CallMetadataInitForMethod(CachedScanResultsAttribute attribute) 53 | { 54 | if (attribute.MetadataInitFlagRva == 0 || attribute.MetadataInitTokenRva == 0) 55 | return; 56 | 57 | if (Marshal.ReadByte((IntPtr) (GameAssemblyBase + attribute.MetadataInitFlagRva)) != 0) 58 | return; 59 | 60 | if (ourMetadataInitForMethodDelegate == null) 61 | ourMetadataInitForMethodDelegate = 62 | Marshal.GetDelegateForFunctionPointer( 63 | (IntPtr) (GameAssemblyBase + XrefScanCache.Header.InitMethodMetadataRva)); 64 | 65 | var token = Marshal.ReadInt32((IntPtr) (GameAssemblyBase + attribute.MetadataInitTokenRva)); 66 | 67 | ourMetadataInitForMethodDelegate(token); 68 | 69 | Marshal.WriteByte((IntPtr) (GameAssemblyBase + attribute.MetadataInitFlagRva), 1); 70 | } 71 | 72 | [Obsolete("Type registration is no longer needed")] 73 | public static void RegisterType(Type type) 74 | { 75 | } 76 | 77 | [Obsolete("Type registration is no longer needed")] 78 | public static void RegisterType() 79 | { 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/XrefScans/XrefScannerLowLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Iced.Intel; 4 | using Decoder = Iced.Intel.Decoder; 5 | 6 | namespace UnhollowerRuntimeLib.XrefScans 7 | { 8 | public static class XrefScannerLowLevel 9 | { 10 | public static IEnumerable JumpTargets(IntPtr codeStart) 11 | { 12 | return JumpTargetsImpl(XrefScanner.DecoderForAddress(codeStart)); 13 | } 14 | 15 | private static IEnumerable JumpTargetsImpl(Decoder myDecoder) 16 | { 17 | while (true) 18 | { 19 | myDecoder.Decode(out var instruction); 20 | if (myDecoder.LastError == DecoderError.NoMoreBytes) yield break; 21 | if (instruction.FlowControl == FlowControl.Return) 22 | yield break; 23 | 24 | if (instruction.FlowControl == FlowControl.UnconditionalBranch || instruction.FlowControl == FlowControl.Call) 25 | { 26 | yield return (IntPtr) ExtractTargetAddress(in instruction); 27 | if(instruction.FlowControl == FlowControl.UnconditionalBranch) yield break; 28 | } 29 | } 30 | } 31 | 32 | public static IEnumerable CallAndIndirectTargets(IntPtr pointer) => CallAndIndirectTargetsImpl(XrefScanner.DecoderForAddress(pointer, 1024 * 1024)); 33 | 34 | private static IEnumerable CallAndIndirectTargetsImpl(Decoder decoder) 35 | { 36 | while (true) 37 | { 38 | decoder.Decode(out var instruction); 39 | if (decoder.LastError == DecoderError.NoMoreBytes) yield break; 40 | 41 | if (instruction.FlowControl == FlowControl.Return) 42 | yield break; 43 | 44 | if (instruction.Mnemonic == Mnemonic.Int || instruction.Mnemonic == Mnemonic.Int1) 45 | yield break; 46 | 47 | if (instruction.Mnemonic == Mnemonic.Call || instruction.Mnemonic == Mnemonic.Jmp) 48 | { 49 | var targetAddress = XrefScanner.ExtractTargetAddress(instruction); 50 | if (targetAddress != 0) 51 | yield return (IntPtr) targetAddress; 52 | continue; 53 | } 54 | 55 | if (instruction.Mnemonic == Mnemonic.Lea) 56 | { 57 | if (instruction.MemoryBase == Register.RIP) 58 | { 59 | var targetAddress = instruction.IPRelativeMemoryAddress; 60 | if (targetAddress != 0) 61 | yield return (IntPtr) targetAddress; 62 | } 63 | } 64 | } 65 | } 66 | 67 | private static ulong ExtractTargetAddress(in Instruction instruction) 68 | { 69 | switch (instruction.Op0Kind) 70 | { 71 | case OpKind.NearBranch16: 72 | return instruction.NearBranch16; 73 | case OpKind.NearBranch32: 74 | return instruction.NearBranch32; 75 | case OpKind.NearBranch64: 76 | return instruction.NearBranch64; 77 | case OpKind.FarBranch16: 78 | return instruction.FarBranch16; 79 | case OpKind.FarBranch32: 80 | return instruction.FarBranch32; 81 | default: 82 | throw new ArgumentOutOfRangeException(); 83 | } 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /UnhollowerBaseLib/XrefScans/XrefType.cs: -------------------------------------------------------------------------------- 1 | namespace UnhollowerRuntimeLib.XrefScans 2 | { 3 | public enum XrefType 4 | { 5 | Global, 6 | Method, 7 | } 8 | } -------------------------------------------------------------------------------- /UnhollowerPdbGen/MethodAddressToTokenMapCecil.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Mono.Cecil; 3 | using UnhollowerBaseLib.Maps; 4 | 5 | #nullable enable 6 | 7 | namespace UnhollowerPdbGen 8 | { 9 | public class MethodAddressToTokenMapCecil : MethodAddressToTokenMapBase 10 | { 11 | public MethodAddressToTokenMapCecil(string filePath) : base(filePath) 12 | { 13 | } 14 | 15 | protected override AssemblyDefinition? LoadAssembly(string assemblyName) 16 | { 17 | var filesDirt = Path.GetDirectoryName(myFilePath)!; 18 | assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); 19 | return AssemblyDefinition.ReadAssembly(Path.Combine(filesDirt, assemblyName + ".dll")); 20 | } 21 | 22 | protected override MethodDefinition? ResolveMethod(AssemblyDefinition? assembly, int token) 23 | { 24 | return (MethodDefinition?) assembly?.MainModule.LookupToken(token); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /UnhollowerPdbGen/UnhollowerPdbGen.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | Exe 6 | true 7 | latest 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /UnhollowerRuntimeLib/Forwarders.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using UnhollowerRuntimeLib; 3 | using UnhollowerRuntimeLib.XrefScans; 4 | 5 | #pragma warning disable CS0618 6 | 7 | [assembly:TypeForwardedTo(typeof(Il2CppType))] 8 | [assembly:TypeForwardedTo(typeof(Il2CppTypeOf<>))] 9 | [assembly:TypeForwardedTo(typeof(RuntimeReflectionHelper))] 10 | [assembly:TypeForwardedTo(typeof(ClassInjector))] 11 | [assembly:TypeForwardedTo(typeof(DelegateSupport))] 12 | [assembly:TypeForwardedTo(typeof(XrefInstance))] 13 | [assembly:TypeForwardedTo(typeof(XrefScanner))] 14 | [assembly:TypeForwardedTo(typeof(XrefScanMethodDb))] 15 | [assembly:TypeForwardedTo(typeof(XrefScannerLowLevel))] 16 | [assembly:TypeForwardedTo(typeof(XrefType))] 17 | 18 | namespace UnhollowerRuntimeLib 19 | { 20 | public static class RuntimeLibMarker 21 | { 22 | } 23 | } -------------------------------------------------------------------------------- /UnhollowerRuntimeLib/UnhollowerRuntimeLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net4.7.2;netstandard2.1 5 | true 6 | latest 7 | 0.4.10.0 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------