├── .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 |
--------------------------------------------------------------------------------