public static void RegisterTypeInIl2Cpp <T>() where T : class { var type = typeof(T); if (type.IsGenericType || type.IsGenericTypeDefinition) { throw new ArgumentException($"Type {type} is generic and can't be used in il2cpp"); } var currentPointer = Il2CppClassPointerStore <T> .NativeClassPtr; if (currentPointer != IntPtr.Zero) { throw new ArgumentException($"Type {type} is already registered in il2cpp"); } var baseType = type.BaseType; var baseClassPointer = UnityVersionHandler.Wrap((Il2CppClass *)ReadClassPointerForType(baseType)); if (baseClassPointer == null) { throw new ArgumentException($"Base class {baseType} of class {type} is not registered in il2cpp"); } if ((baseClassPointer.Part2->bitfield_1 & ClassBitfield1.valuetype) != 0 || (baseClassPointer.Part2->bitfield_1 & ClassBitfield1.enumtype) != 0) { throw new ArgumentException($"Base class {baseType} is value type and can't be inherited from"); } if ((baseClassPointer.Part2->bitfield_1 & ClassBitfield1.is_generic) != 0) { throw new ArgumentException($"Base class {baseType} is generic and can't be inherited from"); } if ((baseClassPointer.Part2->flags & Il2CppClassAttributes.TYPE_ATTRIBUTE_SEALED) != 0) { throw new ArgumentException($"Base class {baseType} is sealed and can't be inherited from"); } if ((baseClassPointer.Part2->flags & Il2CppClassAttributes.TYPE_ATTRIBUTE_INTERFACE) != 0) { throw new ArgumentException($"Base class {baseType} is an interface and can't be inherited from"); } lock (InjectedTypes) if (!InjectedTypes.Add(typeof(T).FullName)) { throw new ArgumentException($"Type with FullName {typeof(T).FullName} is already injected. Don't inject the same type twice, or use a different namespace"); } if (ourOriginalTypeToClassMethod == null) { HookClassFromType(); } var classPointer = UnityVersionHandler.NewClass(baseClassPointer.Part2->vtable_count); classPointer.Part1->image = FakeImage; classPointer.Part1->parent = baseClassPointer.ClassPointer; classPointer.Part1->element_class = classPointer.Part1->klass = classPointer.Part1->castClass = classPointer.ClassPointer; classPointer.Part2->native_size = -1; classPointer.Part2->actualSize = classPointer.Part2->instance_size = baseClassPointer.Part2->instance_size + (uint)IntPtr.Size; classPointer.Part2->bitfield_1 = ClassBitfield1.initialized | ClassBitfield1.initialized_and_no_error | ClassBitfield1.size_inited; classPointer.Part2->bitfield_2 = ClassBitfield2.has_finalize | ClassBitfield2.is_vtable_initialized; classPointer.Part1->name = Marshal.StringToHGlobalAnsi(type.Name); classPointer.Part1->namespaze = Marshal.StringToHGlobalAnsi(type.Namespace); classPointer.Part1->this_arg.type = classPointer.Part1->byval_arg.type = Il2CppTypeEnum.IL2CPP_TYPE_CLASS; classPointer.Part1->this_arg.mods_byref_pin = 64; classPointer.Part2->flags = baseClassPointer.Part2->flags; // todo: adjust flags? var eligibleMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Where(IsMethodEligible).ToArray(); var methodCount = 2 + eligibleMethods.Length; // 1 is the finalizer, 1 is empty ctor classPointer.Part2->method_count = (ushort)methodCount; var methodPointerArray = (Il2CppMethodInfo **)Marshal.AllocHGlobal(methodCount * IntPtr.Size); classPointer.Part1->methods = methodPointerArray; methodPointerArray[0] = ConvertStaticMethod(FinalizeDelegate, "Finalize", classPointer); methodPointerArray[1] = ConvertStaticMethod(CreateEmptyCtor(type), ".ctor", classPointer); for (var i = 0; i < eligibleMethods.Length; i++) { var methodInfo = eligibleMethods[i]; methodPointerArray[i + 2] = ConvertMethodInfo(methodInfo, classPointer); } var vTablePointer = (VirtualInvokeData *)classPointer.VTable; var baseVTablePointer = (VirtualInvokeData *)baseClassPointer.VTable; classPointer.Part2->vtable_count = baseClassPointer.Part2->vtable_count; for (var i = 0; i < classPointer.Part2->vtable_count; i++) { vTablePointer[i] = baseVTablePointer[i]; if (Marshal.PtrToStringAnsi(vTablePointer[i].method->name) == "Finalize") // slot number is not static { vTablePointer[i].method = methodPointerArray[0]; vTablePointer[i].methodPtr = methodPointerArray[0]->methodPointer; } } var newCounter = Interlocked.Decrement(ref ourClassOverrideCounter); FakeTokenClasses[newCounter] = classPointer.Pointer; classPointer.Part1->byval_arg.data = classPointer.Part1->this_arg.data = (IntPtr)newCounter; RuntimeSpecificsStore.SetClassInfo(classPointer.Pointer, true, true); Il2CppClassPointerStore <T> .NativeClassPtr = classPointer.Pointer; LogSupport.Info($"Registered mono type {typeof(T)} in il2cpp domain"); }
private static ISupportModule Initialize() { LogSupport.RemoveAllHandlers(); if (Console.Enabled || Imports.IsDebugMode()) { LogSupport.InfoHandler += MelonModLogger.Log; } LogSupport.WarningHandler += MelonModLogger.LogWarning; LogSupport.ErrorHandler += MelonModLogger.LogError; if (Imports.IsDebugMode()) { LogSupport.TraceHandler += MelonModLogger.Log; } try { Assembly il2cppSystem = Assembly.Load("Il2CppSystem"); if (il2cppSystem != null) { Type unitytls = il2cppSystem.GetType("Il2CppMono.Unity.UnityTls"); if (unitytls != null) { unsafe { var tlsHookTarget = typeof(Uri).Assembly.GetType("Mono.Unity.UnityTls").GetMethod("GetUnityTlsInterface", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).MethodHandle.GetFunctionPointer(); var unityMethodField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(unitytls.GetMethod("GetUnityTlsInterface", BindingFlags.Public | BindingFlags.Static)); var unityMethodPtr = (IntPtr)unityMethodField.GetValue(null); var unityMethod = *(IntPtr *)unityMethodPtr; Imports.Hook((IntPtr)(&tlsHookTarget), unityMethod); } } else { throw new Exception("Failed to get Type Il2CppMono.Unity.UnityTls!"); } } else { throw new Exception("Failed to get Assembly Il2CppSystem!"); } } catch (Exception ex) { MelonModLogger.LogWarning("Exception while setting up TLS, mods will not be able to use HTTPS: " + ex); } if (MelonLoader.Main.IsVRChat) { try { Assembly Transmtn = Assembly.Load("Transmtn"); if (Transmtn != null) { Type Transmtn_HttpConnection = Transmtn.GetType("Transmtn.HttpConnection"); if (Transmtn_HttpConnection != null) { Il2CppSystem_Console_WriteLine = typeof(Il2CppSystem.Console).GetMethods(BindingFlags.Public | BindingFlags.Static).First(x => (x.Name.Equals("WriteLine") && (x.GetParameters().Count() == 1) && (x.GetParameters()[0].ParameterType == typeof(string)))); if (harmonyInstance == null) { harmonyInstance = HarmonyInstance.Create("MelonLoader.Support.Il2Cpp"); } harmonyInstance.Patch(Transmtn_HttpConnection.GetMethod("get", BindingFlags.Public | BindingFlags.Instance), new HarmonyMethod(typeof(Main).GetMethod("Transmtn_HttpConnection_get_Prefix", BindingFlags.NonPublic | BindingFlags.Static)), new HarmonyMethod(typeof(Main).GetMethod("Transmtn_HttpConnection_get_Postfix", BindingFlags.NonPublic | BindingFlags.Static))); } else { throw new Exception("Failed to get Type Transmtn.HttpConnection!"); } } else { throw new Exception("Failed to get Assembly Transmtn!"); } } catch (Exception ex) { MelonModLogger.LogWarning("Exception while setting up Auth Token Hider, Auth Tokens may show in Console: " + ex); } } ClassInjector.DoHook += Imports.Hook; GetUnityVersionNumbers(out var major, out var minor, out var patch); UnityVersionHandler.Initialize(major, minor, patch); SetAsLastSiblingDelegateField = IL2CPP.ResolveICall <SetAsLastSiblingDelegate>("UnityEngine.Transform::SetAsLastSibling"); ClassInjector.RegisterTypeInIl2Cpp <MelonLoaderComponent>(); MelonLoaderComponent.Create(); SceneManager.sceneLoaded = ( (SceneManager.sceneLoaded == null) ? new Action <Scene, LoadSceneMode>(OnSceneLoad) : Il2CppSystem.Delegate.Combine(SceneManager.sceneLoaded, (UnityAction <Scene, LoadSceneMode>) new Action <Scene, LoadSceneMode>(OnSceneLoad)).Cast <UnityAction <Scene, LoadSceneMode> >() ); Camera.onPostRender = ( (Camera.onPostRender == null) ? new Action <Camera>(OnPostRender) : Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback) new Action <Camera>(OnPostRender)).Cast <Camera.CameraCallback>() ); return(new Module()); }
public static void Run() { try { HarmonyBackendFix.Initialize(); ConsoleManager.Initialize(false, false); PreloaderLog = new PreloaderConsoleListener(); Logger.Listeners.Add(PreloaderLog); if (ConsoleManager.ConsoleEnabled) { ConsoleManager.CreateConsole(); Logger.Listeners.Add(new ConsoleLogListener()); } ChainloaderLogHelper.PrintLogInfo(Log); Log.Log(LogLevel.Debug, $"Game executable path: {Paths.ExecutablePath}"); Log.Log(LogLevel.Debug, $"Unhollowed assembly directory: {IL2CPPUnhollowedPath}"); Log.Log(LogLevel.Debug, $"BepInEx root path: {Paths.BepInExRootPath}"); UnhollowerLog = Logger.CreateLogSource("Unhollower"); LogSupport.InfoHandler += UnhollowerLog.LogInfo; LogSupport.WarningHandler += UnhollowerLog.LogWarning; LogSupport.TraceHandler += UnhollowerLog.LogDebug; LogSupport.ErrorHandler += UnhollowerLog.LogError; InitializeUnityVersion(); if (ProxyAssemblyGenerator.CheckIfGenerationRequired()) { ProxyAssemblyGenerator.GenerateAssemblies(); } UnityVersionHandler.Initialize(UnityVersion.Major, UnityVersion.Minor, UnityVersion.Build); using (var assemblyPatcher = new AssemblyPatcher()) { assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath); Log.LogInfo($"{assemblyPatcher.PatcherContext.PatcherPlugins.Count} patcher plugin{(assemblyPatcher.PatcherContext.PatcherPlugins.Count == 1 ? "" : "s")} loaded"); assemblyPatcher.LoadAssemblyDirectories(IL2CPPUnhollowedPath); Log.LogInfo($"{assemblyPatcher.PatcherContext.PatcherPlugins.Count} assemblies discovered"); assemblyPatcher.PatchAndLoad(); } Logger.Listeners.Remove(PreloaderLog); Chainloader = new IL2CPPChainloader(); Chainloader.Initialize(); } catch (Exception ex) { Log.Log(LogLevel.Fatal, ex); throw; } }
private static ISupportModule Initialize() { if (Console.Enabled || Imports.IsDebugMode()) { LogSupport.InfoHandler -= System.Console.WriteLine; LogSupport.InfoHandler += MelonModLogger.Log; } LogSupport.WarningHandler -= System.Console.WriteLine; LogSupport.WarningHandler += MelonModLogger.LogWarning; LogSupport.ErrorHandler -= System.Console.WriteLine; LogSupport.ErrorHandler += MelonModLogger.LogError; if (Imports.IsDebugMode()) { LogSupport.TraceHandler -= System.Console.WriteLine; LogSupport.TraceHandler += MelonModLogger.Log; } try { Assembly il2cppSystem = Assembly.Load("Il2CppSystem"); if (il2cppSystem != null) { Type unitytls = il2cppSystem.GetType("Il2CppMono.Unity.UnityTls"); if (unitytls != null) { unsafe { var tlsHookTarget = typeof(Uri).Assembly.GetType("Mono.Unity.UnityTls").GetMethod("GetUnityTlsInterface", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).MethodHandle.GetFunctionPointer(); var unityMethodField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(unitytls.GetMethod("GetUnityTlsInterface", BindingFlags.Public | BindingFlags.Static)); var unityMethodPtr = (IntPtr)unityMethodField.GetValue(null); var unityMethod = *(IntPtr *)unityMethodPtr; Imports.Hook((IntPtr)(&tlsHookTarget), unityMethod); } } else { throw new Exception("Failed to get Type Il2CppMono.Unity.UnityTls!"); } } else { throw new Exception("Failed to get Assembly Il2CppSystem!"); } } catch (Exception ex) { MelonModLogger.LogWarning("Exception while setting up TLS, mods will not be able to use HTTPS: " + ex); } ClassInjector.DoHook += Imports.Hook; GetUnityVersionNumbers(out var major, out var minor, out var patch); UnityVersionHandler.Initialize(major, minor, patch); ClassInjector.RegisterTypeInIl2Cpp <MelonLoaderComponent>(); MelonLoaderComponent.Create(); SceneManager.sceneLoaded = ( (SceneManager.sceneLoaded == null) ? new Action <Scene, LoadSceneMode>(OnSceneLoad) : Il2CppSystem.Delegate.Combine(SceneManager.sceneLoaded, (UnityAction <Scene, LoadSceneMode>) new Action <Scene, LoadSceneMode>(OnSceneLoad)).Cast <UnityAction <Scene, LoadSceneMode> >() ); Camera.onPostRender = ( (Camera.onPostRender == null) ? new Action <Camera>(OnPostRender) : Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback) new Action <Camera>(OnPostRender)).Cast <Camera.CameraCallback>() ); return(new Module()); }
private static ISupportModule Initialize() { LogSupport.RemoveAllHandlers(); if (MelonConsole.Enabled || Imports.IsDebugMode()) { LogSupport.InfoHandler += MelonLogger.Log; } LogSupport.WarningHandler += MelonLogger.LogWarning; LogSupport.ErrorHandler += MelonLogger.LogError; if (Imports.IsDebugMode()) { LogSupport.TraceHandler += MelonLogger.Log; } if (MelonLoaderBase.IsVRChat) { try { Assembly Transmtn = Assembly.Load("Transmtn"); if (Transmtn != null) { Type Transmtn_HttpConnection = Transmtn.GetType("Transmtn.HttpConnection"); if (Transmtn_HttpConnection != null) { Il2CppSystem_Console_WriteLine = typeof(Il2CppSystem.Console).GetMethods(BindingFlags.Public | BindingFlags.Static).First(x => (x.Name.Equals("WriteLine") && (x.GetParameters().Count() == 1) && (x.GetParameters()[0].ParameterType == typeof(string)))); if (harmonyInstance == null) { harmonyInstance = HarmonyInstance.Create("MelonLoader.Support.Il2Cpp"); } harmonyInstance.Patch(Transmtn_HttpConnection.GetMethod("get", BindingFlags.Public | BindingFlags.Instance), new HarmonyMethod(typeof(Main).GetMethod("Transmtn_HttpConnection_get_Prefix", BindingFlags.NonPublic | BindingFlags.Static)), new HarmonyMethod(typeof(Main).GetMethod("Transmtn_HttpConnection_get_Postfix", BindingFlags.NonPublic | BindingFlags.Static))); } else { throw new Exception("Failed to get Type Transmtn.HttpConnection!"); } } else { throw new Exception("Failed to get Assembly Transmtn!"); } } catch (Exception ex) { MelonLogger.LogWarning("Exception while setting up Auth Token Hider, Auth Tokens may show in Console: " + ex); } } ClassInjector.DoHook += Imports.Hook; GetUnityVersionNumbers(out var major, out var minor, out var patch); UnityVersionHandler.Initialize(major, minor, patch); SetAsLastSiblingDelegateField = IL2CPP.ResolveICall <SetAsLastSiblingDelegate>("UnityEngine.Transform::SetAsLastSibling"); ClassInjector.RegisterTypeInIl2Cpp <MelonLoaderComponent>(); MelonLoaderComponent.Create(); SceneManager.sceneLoaded = ( (SceneManager.sceneLoaded == null) ? new Action <Scene, LoadSceneMode>(OnSceneLoad) : Il2CppSystem.Delegate.Combine(SceneManager.sceneLoaded, (UnityAction <Scene, LoadSceneMode>) new Action <Scene, LoadSceneMode>(OnSceneLoad)).Cast <UnityAction <Scene, LoadSceneMode> >() ); Camera.onPostRender = ( (Camera.onPostRender == null) ? new Action <Camera>(OnPostRender) : Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback) new Action <Camera>(OnPostRender)).Cast <Camera.CameraCallback>() ); return(new Module()); }