diff --git a/Marsey/Stealthsey/Hidesey.cs b/Marsey/Stealthsey/Hidesey.cs index 60a5921..c367f99 100644 --- a/Marsey/Stealthsey/Hidesey.cs +++ b/Marsey/Stealthsey/Hidesey.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq; -using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; using System.Runtime.Loader; using HarmonyLib; @@ -62,7 +60,7 @@ public static class Hidesey { private static List _hideseys = new List(); private static bool _initialized; - private static bool _caching; + internal static bool caching; /// /// Starts Hidesey. Patches GetAssemblies, GetReferencedAssemblies and hides Harmony from assembly list. @@ -122,6 +120,7 @@ public static void Disperse() /// public static void PostLoad() { + Veil.Patch(); HWID.Force(); DiscordRPC.Patch(); @@ -143,8 +142,8 @@ public static void Cleanup() private static void ToggleCaching() { - MarseyLogger.Log(MarseyLogger.LogType.DEBG, $"Caching is set to {!_caching}"); - _caching = !_caching; + MarseyLogger.Log(MarseyLogger.LogType.DEBG, $"Caching is set to {!caching}"); + caching = !caching; } /// @@ -184,7 +183,7 @@ public static void HidePatch(Assembly marsey) } /// - /// Undermines system functions, hides what doesnt belong from view + /// Undermines system functions, hides what doesn't belong from view /// /// Thrown if ThrowOnFail is true and any of the patches fails to apply private static void Perjurize() @@ -260,7 +259,7 @@ public static AssemblyName[] LyingReference(AssemblyName[] original) public static Type[] LyingTyper(Type[] original) { IEnumerable hiddentypes = Facade.GetTypes(); - if (!_caching) + if (!caching) return original.Except(hiddentypes).ToArray(); Type[] cached = Facade.Cached; @@ -275,4 +274,27 @@ public static Type[] LyingTyper(Type[] original) #endregion + /// + /// Checks if the call was made by or concerns the content pack + /// + internal static bool FromContent() + { + StackTrace stackTrace = new(); + //MarseyLogger.Log(MarseyLogger.LogType.TRCE, "Veil", $"Stacktrace check called, given {stackTrace.GetFrames().Length} frames."); + + foreach (StackFrame frame in stackTrace.GetFrames()) + { + MethodBase? method = frame.GetMethod(); + if (method == null || method.DeclaringType == null) continue; + string? namespaceName = method.DeclaringType.Namespace; + if (!string.IsNullOrEmpty(namespaceName) && namespaceName.StartsWith("Content.")) + { + //MarseyLogger.Log(MarseyLogger.LogType.INFO, "Veil", "Hidden types from a contentpack check!"); + return true; + } + } + + return false; + } + } diff --git a/Marsey/Stealthsey/Veil.cs b/Marsey/Stealthsey/Veil.cs new file mode 100644 index 0000000..a601456 --- /dev/null +++ b/Marsey/Stealthsey/Veil.cs @@ -0,0 +1,86 @@ +using System.Reflection; +using HarmonyLib; +using JetBrains.Annotations; +using Marsey.Handbreak; +using Marsey.Misc; + +namespace Marsey.Stealthsey; + +/// +/// Hide subversions from IReflectionManager +/// +internal static class Veil +{ + private static List HiddenAssemblies = []; + private static IEnumerable _veilCache = []; + + internal static void Patch() + { + Type? CRM = Helpers.TypeFromQualifiedName("Robust.Shared.Reflection.ReflectionManager"); + if (CRM == null) return; + + MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Veil", "Patching."); + + MethodInfo AsmGetter = AccessTools.PropertyGetter(CRM, "Assemblies"); + MethodInfo AsmPrefix = AccessTools.Method(typeof(Veil), "AsmPrefix"); + Manual.Patch(AsmGetter, AsmPrefix, HarmonyPatchType.Prefix); + + MethodInfo FindAllTypes = AccessTools.Method(CRM, "FindAllTypes"); + MethodInfo GetAllChildren = AccessTools.Method(CRM, "GetAllChildren", new[] { typeof(Type), typeof(bool) }); + MethodInfo FindTypesWithAttribute = AccessTools.Method(CRM, "FindTypesWithAttribute", new[] { typeof(Type) }); + MethodInfo TypePost = AccessTools.Method(typeof(Veil), "TypePost"); + + Manual.Patch(FindAllTypes, TypePost, HarmonyPatchType.Postfix); + Manual.Patch(GetAllChildren, TypePost, HarmonyPatchType.Postfix); + Manual.Patch(FindTypesWithAttribute, TypePost, HarmonyPatchType.Postfix); + } + + [UsedImplicitly] + private static bool AsmPrefix(ref IReadOnlyList __result, object __instance) + { + List? originalAssemblies = Traverse.Create(__instance).Field("assemblies").GetValue>(); + if (originalAssemblies == null) + { + __result = new List().AsReadOnly(); + return false; + } + + // Filter out assemblies whose names are in HiddenAssemblies + List veiledAssemblies = originalAssemblies + .Where(asm => + { + string? value = asm.GetName().Name; + return value != null && !HiddenAssemblies.Contains(value); + }) + .ToList(); + + MarseyLogger.Log(MarseyLogger.LogType.TRCE, "Veil", $"Hidden {HiddenAssemblies.Count} assemblies."); + // Return the filtered list as a read-only list + __result = veiledAssemblies.AsReadOnly(); + return false; + } + + [UsedImplicitly] + private static void TypePost(ref IEnumerable __result) + { + if (!Hidesey.FromContent()) return; + + MarseyLogger.Log(MarseyLogger.LogType.TRCE, "Passed fromcontent check with negative?"); + + if (Hidesey.caching && _veilCache.Any()) + { + __result = _veilCache; + return; + } + + IEnumerable hiddenTypes = Facade.GetTypes(); + _veilCache = __result.Except(hiddenTypes).AsEnumerable(); + __result = _veilCache; + } + + public static void Hide(Assembly asm) + { + string? name = asm.GetName().Name; + if (name != null) HiddenAssemblies.Add(name); + } +} diff --git a/Marsey/Subversion/Subverse.cs b/Marsey/Subversion/Subverse.cs index 03e7c85..78a5ea8 100644 --- a/Marsey/Subversion/Subverse.cs +++ b/Marsey/Subversion/Subverse.cs @@ -64,6 +64,9 @@ private static void Postfix(object __instance) Assembly subverterAssembly = Assembly.LoadFrom(path); MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Subversion", $"Sideloading {path}"); AssemblyFieldHandler.InitLogger(subverterAssembly, subverterAssembly.FullName); + + // Stealthsey methods + Veil.Hide(subverterAssembly); Sedition.InitSedition(subverterAssembly, subverterAssembly.FullName); loadGameAssemblyMethod.Invoke(__instance, new object[] { subverterAssembly });