diff --git a/Config.cs b/Config.cs index ccbf606..b4ea6a7 100644 --- a/Config.cs +++ b/Config.cs @@ -5,10 +5,14 @@ namespace undead_universal_patch_il2cpp public static class GenericConfig { public static ConfigEntry LogAllRequests; + public static ConfigEntry CertificatePatch; + public static ConfigEntry HilePatch; } public static class GenericConfigDefaults { public static bool LogAllRequests = false; + public static bool CertificatePatch = false; + public static bool HilePatch = false; } public static class NameserverConfig { diff --git a/LICENSE.txt b/LICENSE.txt index 8aa2645..6bf5246 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) [year] [fullname] +Copyright (c) 2024 proxnet.dev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/Patches/BestHTTP.cs b/Patches/BestHTTP.cs index 96af726..531bc6a 100644 --- a/Patches/BestHTTP.cs +++ b/Patches/BestHTTP.cs @@ -31,10 +31,7 @@ namespace undead_universal_patch_il2cpp.Patches return true; } - static MethodBase TargetMethod() - { - return targetMethod; - } + static MethodBase TargetMethod() => targetMethod; [HarmonyPrefix] static bool Prefix(ref object request) @@ -46,7 +43,7 @@ namespace undead_universal_patch_il2cpp.Patches return false; } - var uriInstance = (Uri)uriProperty.GetValue(request, null); + var uriInstance = (Il2CppSystem.Uri)uriProperty.GetValue(request, null); if (uriInstance == null) { Plugin.Log.LogFatal("BestHTTP_Unob failed: uriInstance was null."); @@ -55,11 +52,11 @@ namespace undead_universal_patch_il2cpp.Patches if (GenericConfig.LogAllRequests.Value) Plugin.Log.LogInfo($"BestHTTP_Unob request (Before) URL: {uriInstance.ToString()}"); - Uri newUri = new(NameserverConfig.NewUrl.Value); + Il2CppSystem.Uri newUri = new(uriInstance.ToString().Contains("ns.rec.net") ? NameserverConfig.NewUrl.Value : uriInstance.ToString()); if (GenericConfig.LogAllRequests.Value) Plugin.Log.LogInfo($"BestHTTP_Unob request (After) URL: {newUri.ToString()}"); - uriProperty.SetValue(request, NameserverConfig., null); + uriProperty.SetValue(request, NameserverConfig.Rewrite.Value ? newUri : uriInstance, null); return true; } } diff --git a/Patches/HilePatch.cs b/Patches/HilePatch.cs new file mode 100644 index 0000000..d0fcc1a --- /dev/null +++ b/Patches/HilePatch.cs @@ -0,0 +1,63 @@ +using HarmonyLib; +using System; +using System.Reflection; +using UnityEngine; + +namespace undead_universal_patch_il2cpp.Patches +{ + [HarmonyPatch] + public static class HilePatch + { + public static void Patch() + { + Plugin.Log.LogInfo("Attempting hile patch"); + + HileManager man = GameObject.Find("/GameRoot/Startup/Core Systems/[CheatManager]").GetComponent(); + + string[] asdf = [ + "GameAssembly.dll", + "UnityPlayer.dll", + "WinPixEventRuntime.dll", + "steam_api64.dll", + "steam_api.dll", + "d3d11.dll", + "d3d9.dll", + "d3d8.dll", + "ddraw.dll", + "dxgi.dll", + "winhttp.dll" + ]; + man.KnownDlls = asdf; + + Plugin.Log.LogInfo("Hile patch successful."); + } + + static string TargetTypeName = "BootSequence"; + static string TargetMethodName = "set_CurrentState"; + static string Description = "Add BepInEx to allowed DLLs"; + static Type targetType = AccessTools.TypeByName(TargetTypeName); + static MethodInfo targetMethod = AccessTools.Method(targetType, TargetMethodName); + + static bool Prepare() + { + if (targetMethod == null) + { + Plugin.Log.LogWarning($"'{Description}' disabled. The type for this patch was not found."); + return false; + } + + Plugin.Log.LogInfo($"'{Description}' succeeded validation."); + return true; + } + + static MethodBase TargetMethod() + { + return targetMethod; + } + + static void Prefix(ref BootSequence __instance) + { + if (GenericConfig.HilePatch.Value && __instance.CurrentState == BootSequence.BootSequenceState.RECNET_CONNECTION) Patch(); + } + } +} diff --git a/Patches/Photon.cs b/Patches/Photon.cs index 680d184..fb73575 100644 --- a/Patches/Photon.cs +++ b/Patches/Photon.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using Il2CppInterop.Runtime; using System; using System.Collections.Generic; using System.Reflection; @@ -6,89 +7,44 @@ using UnityEngine; namespace undead_universal_patch_il2cpp.Patches { + [HarmonyPatch] public class PhotonPatchEvent { + static readonly string TargetTypeName = "RecNet.Core"; + static readonly string TargetMethodName = "ConnectToRecNet"; + static readonly string Description = "Photon Patch event method"; + static readonly MethodInfo connectMethod = AccessTools.Method(AccessTools.TypeByName(TargetTypeName), TargetMethodName); + + static bool Prepare() + { + if (connectMethod == null) + { + Plugin.Log.LogWarning($"'{Description}' disabled. The type for this patch was not found."); + return false; + } + Plugin.Log.LogInfo($"'{Description}' succeeded validation."); + return true; + } + static MethodBase TargetMethod() => connectMethod; + static void Prefix() + { + if (PhotonConfig.PatchPhotonIds.Value) Photon.Patch(); + } } public class Photon { - public static object Patch() + public static void Patch() { - Plugin.Log.LogInfo("Attempting Photon patch."); - Type serverSettingsType = AccessTools.TypeByName("ServerSettings"); + /* + Normally, I would be using reflection and AccessTools to create a new instance of ServerSettings and set the value of PhotonNetwork.PhotonServerSettings, + but since it was difficult and confusing with IL2CPP, I ended up just using explicit references.. every targeted game build *should* have these types anyway. + Now I'm wondering if the patch runs faster when using explicit references rather than reflection + */ - Type hostingOptionType = AccessTools.Inner(serverSettingsType, "HostingOption"); - if (serverSettingsType == null) - { - Plugin.Log.LogFatal("Photon patch failed early, this Photon client is unsupported!"); - return null; - } - - ScriptableObject settingsInstance = ScriptableObject.CreateInstance(serverSettingsType); - - object realPhotonServerSettings = Resources.Load("PhotonServerSettings", serverSettingsType); - - try - { - var rpcListField = AccessTools.Field(serverSettingsType, "RpcList"); - if (rpcListField == null) - { - Plugin.Log.LogFatal("Photon patch failed (serverSettingsType did not have an RpcList), this Photon client is unsupported!"); - return null; - } - if (realPhotonServerSettings == null) - { - Plugin.Log.LogFatal("Photon patch failed (existing photon settings was null, is the patch event set to 'Awake'?), this Photon client is unsupported!"); - return null; - } - var existingRpcList = (List)rpcListField.GetValue(realPhotonServerSettings); - rpcListField.SetValue(settingsInstance, existingRpcList); - } - catch (Exception e) - { - Plugin.Log.LogFatal("Photon patch failed (RpcList), this Photon client is unsupported!"); - Plugin.Log.LogDebug(e); - return null; - } - - var appIdField = AccessTools.Field(serverSettingsType, "AppID"); - appIdField.SetValue(settingsInstance, PhotonConfig.AppID.Value); - var voiceAppIdField = AccessTools.Field(serverSettingsType, "VoiceAppID"); - voiceAppIdField.SetValue(settingsInstance, PhotonConfig.VoiceAppID.Value); - - var hostTypeField = AccessTools.Field(serverSettingsType, "HostType"); - if (hostTypeField != null && hostingOptionType != null && hostingOptionType.IsEnum) - { - try - { - object enumValue = Enum.Parse(hostingOptionType, "PhotonCloud"); - hostTypeField.SetValue(settingsInstance, enumValue); - } - catch (ArgumentException ex) - { - Plugin.Log.LogFatal($"Photon patch failed, cannot set HostingOption: {ex.Message}"); - return null; - } - } - - // Save to property - Type photonNetworkType = AccessTools.TypeByName("PhotonNetwork"); - if (photonNetworkType == null) - { - Plugin.Log.LogFatal("Photon patch will not work (class not found). Is this build supported?"); - return null; - } - FieldInfo photonServerSettingsField = photonNetworkType.GetField("PhotonServerSettings"); - if (photonServerSettingsField == null) - { - Plugin.Log.LogFatal("Photon patch will not work (property not found). Is this build supported?"); - return null; - } - photonServerSettingsField.SetValue(serverSettingsType, settingsInstance); - - Plugin.Log.LogInfo("Photon patch was successful."); - return settingsInstance; + PhotonNetwork.PhotonServerSettings.AppID = PhotonConfig.AppID.Value; + PhotonNetwork.PhotonServerSettings.VoiceAppID = PhotonConfig.VoiceAppID.Value; } } } diff --git a/Patches/RealPhotonPatchEvent.cs b/Patches/RealPhotonPatchEvent.cs new file mode 100644 index 0000000..ceaa35f --- /dev/null +++ b/Patches/RealPhotonPatchEvent.cs @@ -0,0 +1,15 @@ +using ExitGames.Client.Photon; +using HarmonyLib; +using System; + +namespace undead_universal_patch_il2cpp.Patches +{ + [HarmonyPatch(typeof(PhotonNetwork), nameof(PhotonNetwork.ConnectUsingSettings))] + public class RealPhotonPatchEvent + { + public static void Prefix() + { + Photon.Patch(); + } + } +} diff --git a/Patches/TLS.cs b/Patches/TLS.cs new file mode 100644 index 0000000..0b79fee --- /dev/null +++ b/Patches/TLS.cs @@ -0,0 +1,41 @@ +using System; +using System.Reflection; +using HarmonyLib; + +namespace undead_universal_patch_il2cpp.Patches +{ + [HarmonyPatch] + public class TLSPatch + { + static string TargetTypeName = "Org.BouncyCastle.Crypto.Tls.LegacyTlsAuthentication"; + static string TargetMethodName = "NotifyServerCertificate"; + static string Description = "Certificate patch"; + static Type targetType = AccessTools.TypeByName(TargetTypeName); + static MethodInfo targetMethod = AccessTools.Method(targetType, TargetMethodName); + + static bool Prepare() + { + if (targetMethod == null) + { + Plugin.Log.LogWarning($"'{Description}' disabled. The type for this patch was not found."); + return false; + } + if (targetMethod == null) + { + Plugin.Log.LogWarning($"'{Description}' disabled. The method for this patch was not found."); + return false; + } + + Plugin.Log.LogInfo($"'{Description}' succeeded validation."); + return true; + } + + static MethodBase TargetMethod() => targetMethod; + + static bool Prefix() + { + return !(GenericConfig.CertificatePatch.Value); + } + + } +} diff --git a/Plugin.cs b/Plugin.cs index 79eb4e3..568f090 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -8,7 +8,7 @@ namespace undead_universal_patch_il2cpp; [BepInPlugin("dev.proxnet.recroom.universalpatch.noneac.il2cpp", "Undead Universal Patch", "1.0.0")] public class Plugin : BasePlugin { - public static new readonly ManualLogSource Log = Logger.CreateLogSource("UUPatch"); + public static new readonly ManualLogSource Log = BepInEx.Logging.Logger.CreateLogSource("UUPatch"); public static Harmony _hi = new("dev.proxnet.recroom.universalpatch.noneac.il2cpp"); @@ -23,6 +23,10 @@ public class Plugin : BasePlugin { GenericConfig.LogAllRequests = Config.Bind("Generic", "LogAllRequests", GenericConfigDefaults.LogAllRequests, "Log all HTTP requests sent by the game."); + GenericConfig.CertificatePatch = Config.Bind("Generic", "CertificatePatch", GenericConfigDefaults.CertificatePatch, + "The game expects a certain SSL certificate from rec.net when making HTTPS requests. Enable this to allow any valid certificate."); + GenericConfig.HilePatch = Config.Bind("Generic", "HilePatch", GenericConfigDefaults.HilePatch, + "The game will send v1/hile and login+shutdown if winhttp.dll is found. Enable this to add winhttp.dll to the list of allowed DLLs."); PhotonConfig.PatchPhotonIds = Config.Bind("Photon", "PatchPhotonIds", PhotonConfigDefaults.PatchPhotonIds, "Enable/disable changing the target IDs in PhotonServerSettings." + "\nCustom server settings are not yet supported."); diff --git a/README.md b/README.md index 59c7fa8..b6894c6 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# undead-universal-patch-il2cpp \ No newline at end of file +# Undead Universal Patch +Non-EAC, IL2CPP build patcher for Rec Room (Dec 2018\*-*Apr 2020) + +Part two of two universal patches. The Mono patch is available at https://git.proxnet.dev/zombieb/undead-universal-patch-mono. + +### BepInEx Development Build +This patch requires that a certain build of BepInEx be used from their GitHub, available at https://github.com/BepInEx/BepInEx/actions/runs/9522461593. + +**When submitting issues**, please submit your BepInEx log file with all log levels enabled. You can do this by setting `Logging.Disk.LogLevels` in `BepInEx.cfg` to `All`. \ No newline at end of file diff --git a/undead-universal-patch-il2cpp.csproj b/undead-universal-patch-il2cpp.csproj index c81600e..20f4de1 100644 --- a/undead-universal-patch-il2cpp.csproj +++ b/undead-universal-patch-il2cpp.csproj @@ -27,11 +27,14 @@ G:\rr\2019-10-25 (5120486837419374208)\BepInEx\interop\Il2Cppmscorlib.dll - - G:\rr\2019-10-25 (5120486837419374208)\cpp2il_out\UnityEngine.dll + + G:\rr\2019-10-25 (5120486837419374208)\BepInEx\interop\Il2CppSystem.dll + + + G:\rr\2019-10-25 (5120486837419374208)\cpp2il_out\Photon3Unity3D.dll - G:\rr\2019-10-25 (5120486837419374208)\cpp2il_out\UnityEngine.CoreModule.dll + G:\rr\2019-10-25 (5120486837419374208)\BepInEx\interop\UnityEngine.CoreModule.dll