Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #49 from ValidHunters/hwid2
Browse files Browse the repository at this point in the history
misandrie authored Oct 5, 2024
2 parents 773421b + 7e8b16e commit 34287e9
Showing 16 changed files with 195 additions and 49 deletions.
8 changes: 7 additions & 1 deletion Marsey/Config/MarseyConf.cs
Original file line number Diff line number Diff line change
@@ -74,6 +74,11 @@ public static class MarseyConf
/// </summary>
public static bool DisableAnyBackports;

/// <summary>
/// Don't run any patches
/// </summary>
public static bool Patchless;

/// <summary>
/// Reflect changes made here to the Dictionary in the launcher's Connector.cs
/// </summary>
@@ -97,7 +102,8 @@ public static class MarseyConf
{ "MARSEY_NO_ANY_BACKPORTS", value => DisableAnyBackports = value == "true" },
{ "MARSEY_FORKID", MarseyPortMan.SetForkID },
{ "MARSEY_ENGINE", MarseyPortMan.SetEngineVer },
{ "MARSEY_HIDE_LEVEL", value => MarseyHide = (HideLevel)Enum.Parse(typeof(HideLevel), value) }
{ "MARSEY_HIDE_LEVEL", value => MarseyHide = (HideLevel)Enum.Parse(typeof(HideLevel), value) },
{ "MARSEY_PATCHLESS", value => Patchless = value == "true"}
};

// Conf variables that do not go into the EnvVarMap go here
8 changes: 5 additions & 3 deletions Marsey/Game/Patcher.cs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
using Marsey.Game.Misc;
using Marsey.Patches;
using Marsey.Misc;
using Marsey.Stealthsey.Reflection;

namespace Marsey.Game;

@@ -25,9 +26,10 @@ public static void Patch<T>(List<T> patchlist) where T : IPatch
PatchAssembly(harmony, patch);
}
}

/// <inheritdoc cref="Patcher.Patch"/>
private static void PatchAssembly<T>(Harmony harmony, T patch) where T : IPatch
[Patching]
private static void PatchAssembly(Harmony harmony, IPatch patch)
{
AssemblyName assemblyName = patch.Asm.GetName();
MarseyLogger.Log(MarseyLogger.LogType.INFO, $"Patching {assemblyName}");
@@ -56,4 +58,4 @@ private static void HandlePatchException(string assemblyName, Exception e)

MarseyLogger.Log(MarseyLogger.LogType.FATL, errorMessage);
}
}
}
54 changes: 43 additions & 11 deletions Marsey/Game/Patches/HWID.cs
Original file line number Diff line number Diff line change
@@ -19,13 +19,12 @@ public static class HWID
/// <summary>
/// Patching the HWId function and replacing it with a custom HWId.
/// </summary>
/// <remarks>Requires Normal or above MarseyHide</remarks>
public static void Force()
{
/// Only accepts a hexidecimal string, so you don't get to write "FUCK YOU PJB/SLOTH/RANE/MOONY/FAYE/SMUG/EXEC/ALLAH/EMO/ONIKS/MORTY".
/// Maybe if you wrote it in entirely numeric, with "Rane" being 18F1F14F5 or something.
/// Nobody will read that anyway - its for ban evasion and thats it.
/// Don't forget a VPN or a proxy!
// TODO: Further work on HWID2
// While currently trust is not used, I suspect having an empty hwid string will harm its value
// This is made so you couldn't hwid ban other people this easily
// As of 10/4/2024 hwid2 instead of this bullshit you can pass an env variable to tell the client that you're not sending your hwid

// Check if forcing is enabled
if (!MarseyConf.ForceHWID)
@@ -79,13 +78,39 @@ public static string GenerateRandom(int length = 64)

private static void PatchCalcMethod()
{
Helpers.PatchMethod(
Helpers.TypeFromQualifiedName("Robust.Shared.Network.HWId"),
"Calc",
typeof(HWID),
"RecalcHwid",
HarmonyPatchType.Postfix
Type? hwid1 = Helpers.TypeFromQualifiedName("Robust.Shared.Network.HWId");
Type? hwid2 = Helpers.TypeFromQualifiedName("Robust.Client.Hwid.BasicHwid");

if (hwid1 is not null)
{
Helpers.PatchMethod(
hwid1,
"Calc",
typeof(HWID),
"RecalcHwid",
HarmonyPatchType.Postfix
);
return;
}

if (hwid2 is not null)
{
Helpers.PatchMethod(
hwid2,
"GetLegacy",
typeof(HWID),
nameof(RecalcHwid),
HarmonyPatchType.Postfix
);

Helpers.PatchMethod(
hwid2,
"GetModern",
typeof(HWID),
nameof(RecalcHwid2),
HarmonyPatchType.Postfix
);
}
}

public static bool CheckHWID(string hwid)
@@ -99,4 +124,11 @@ private static void RecalcHwid(ref byte[] __result)
MarseyLogger.Log(MarseyLogger.LogType.DEBG, "HWIDForcer", $"\"Recalculating\" HWID to {hwidString}");
__result = _hwId;
}

private static void RecalcHwid2(ref byte[] __result)
{
string hwidString = BitConverter.ToString(_hwId).Replace("-", "");
MarseyLogger.Log(MarseyLogger.LogType.DEBG, "HWIDForcer", $"\"Recalculating\" HWID to {hwidString}");
__result = [0, .._hwId];
}
}
2 changes: 2 additions & 0 deletions Marsey/Game/Patches/Marseyports/MarseyPortMan.cs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
using Marsey.Game.Patches.Marseyports.Attributes;
using Marsey.Misc;
using Marsey.Stealthsey;
using Marsey.Stealthsey.Reflection;

namespace Marsey.Game.Patches.Marseyports;

@@ -66,6 +67,7 @@ private static bool ValidateBackport(Type backport)
return true;
}

[Patching]
public static void PatchBackports(bool Content = false)
{
if (_backports == null) return;
51 changes: 38 additions & 13 deletions Marsey/Handbreak/Helpers.cs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ public static class Helpers
Type? t = TypeFromQualifiedName(FullyQualifiedTypeName);

if (t != null) return GetMethod(t, MethodName, parameters);

MarseyLogger.Log(MarseyLogger.LogType.ERRO, $"{FullyQualifiedTypeName} not found.");
return null;
}
@@ -30,7 +30,7 @@ public static class Helpers
{
return AccessTools.Method(type, MethodName, parameters);
}

/// <summary>
/// Patches a method from the given pointers
/// </summary>
@@ -44,14 +44,15 @@ public static class Helpers
public static void PatchMethod(Type? targetType, string targetMethodName, Type? patchType, string patchMethodName, HarmonyPatchType patchingType, Type[]? targetMethodParameters = null, Type[]? patchMethodParameters = null)
{
ValidateTypes(targetType, patchType);

MethodInfo? targetMethod = GetAndValidateMethod(targetType, targetMethodName, targetMethodParameters, "target");
MethodInfo? patchMethod = GetAndValidateMethod(patchType, patchMethodName, patchMethodParameters, "patch");

if (Manual.Patch(targetMethod, patchMethod, patchingType))
LogPatchSuccess(patchingType, targetMethodName, patchMethodName);
}

#region Generics
public static void PatchGenericMethod(Type? targetType, string targetMethodName, Type? patchType, string patchMethodName, Type returnType, HarmonyPatchType patchingType)
{
ValidateTypes(targetType, patchType);
@@ -60,26 +61,50 @@ public static void PatchGenericMethod(Type? targetType, string targetMethodName,
MethodInfo? patchMethod = GetAndValidateMethod(patchType, patchMethodName, null, "patch");

MethodInfo? genericMethod = MakeGenericMethod(patchMethod, returnType);

if (Manual.Patch(targetMethod, genericMethod, patchingType))
LogPatchSuccess(patchingType, targetMethodName, patchMethodName);
}

public static void PatchGenericMethod(MethodInfo? target, MethodInfo? patch, Type returnType, HarmonyPatchType patchType)
public static void PatchGenericMethod(MethodInfo? target, Type targetReturnType, MethodInfo? patch, Type patchReturnType, HarmonyPatchType patchType)
{
target = MakeGenericMethod(target, targetReturnType);
patch = MakeGenericMethod(patch, patchReturnType);

if (Manual.Patch(target, patch, patchType))
LogPatchSuccess(patchType, target!.Name, patch!.Name);
}

public static void PatchGenericMethod(MethodInfo? target, MethodInfo? patch, Type patchReturnType, HarmonyPatchType patchType)
{
patch = MakeGenericMethod(patch, patchReturnType);

if (Manual.Patch(target, patch, patchType))
LogPatchSuccess(patchType, target!.Name, patch!.Name);
}

public static void PatchGenericMethod(MethodInfo target, Type targetReturnType, MethodInfo? patch, HarmonyPatchType patchType)
{
MethodInfo? generic = MakeGenericMethod(patch, returnType);

if (Manual.Patch(target, generic, patchType))
target = target.MakeGenericMethod([]);

if (Manual.Patch(target, patch, patchType))
LogPatchSuccess(patchType, target.Name, patch!.Name);
}

public static void PatchGenericMethod(MethodInfo? target, MethodInfo? patch, HarmonyPatchType patchType)
{
if (Manual.Patch(target, patch, patchType))
LogPatchSuccess(patchType, target!.Name, patch!.Name);

}


#endregion

private static void ValidateTypes(Type? targetType, Type? patchType)
{
if (targetType == null || patchType == null)
throw new HandBreakException($"Passed type is null. Target: {targetType}, patch: {patchType}");
}

private static void ValidateMethods(MethodInfo? target, MethodInfo? patch)
{
if (target == null || patch == null)
@@ -97,7 +122,7 @@ private static void ValidateMethods(MethodInfo? target, MethodInfo? patch)
private static MethodInfo? MakeGenericMethod(MethodInfo? method, Type returnType)
{
if (method != null) return method.MakeGenericMethod(returnType);

MarseyLogger.Log(MarseyLogger.LogType.ERRO, "Handbreak", $"Error making generic method");
return null;
}
@@ -106,4 +131,4 @@ private static void LogPatchSuccess(HarmonyPatchType patchingType, string target
{
MarseyLogger.Log(MarseyLogger.LogType.DEBG, "Handbreak", $"{patchingType}: Patched {targetMethodName} with {patchMethodName}.");
}
}
}
6 changes: 4 additions & 2 deletions Marsey/MarseyPatcher.cs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
using Marsey.Stealthsey;
using Marsey.Subversion;
using Marsey.Misc;
using Marsey.Stealthsey.Reflection;

namespace Marsey;

@@ -63,7 +64,7 @@ private MarseyPatcher(Assembly? robClientAssembly, ManualResetEvent mre)
Utility.ReadConf();
HarmonyManager.Init(new Harmony(MarseyVars.Identifier));

MarseyLogger.Log(MarseyLogger.LogType.INFO, $"Marseyloader started, version {MarseyVars.MarseyVersion}");
MarseyLogger.Log(MarseyLogger.LogType.INFO, $"Marseyloader started{(MarseyConf.Patchless ? " in patchless mode" : "")}, version {MarseyVars.MarseyVersion}");

// Init backport manager
MarseyPortMan.Initialize();
@@ -78,7 +79,8 @@ private MarseyPatcher(Assembly? robClientAssembly, ManualResetEvent mre)
}

// We might want to patch things before the loader has even a chance to execute anything
public void Preload()
[Patching]
private void Preload()
{
Sentry.Patch();

4 changes: 2 additions & 2 deletions Marsey/Stealthsey/Hidesey.cs
Original file line number Diff line number Diff line change
@@ -73,7 +73,7 @@ public static void Initialize() // Finally, a patch loader that loads with a pat

_initialized = true;

HideLevelExec.Initialize();
HideseyAttributeManager.Initialize();

Load();
}
@@ -203,7 +203,7 @@ private static void Perjurize()
Helpers.PatchGenericMethod(
target: targetMethod,
patch: Lie,
returnType: returnType,
patchReturnType: returnType,
patchType: HarmonyPatchType.Postfix
);
}
2 changes: 2 additions & 0 deletions Marsey/Stealthsey/HideseyPatches.cs
Original file line number Diff line number Diff line change
@@ -34,6 +34,8 @@ public static void Lie<T>(ref T __result)
/// </summary>
public static bool Skip() => false;

public static bool SkipPatchless() => !MarseyConf.Patchless;

/// <summary>
/// Prefix patch that checks if MarseyHide matches or above the attributed HideLevelRequirement
/// </summary>
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ namespace Marsey.Stealthsey.Reflection;
/// <summary>
/// Manages methods with the HideLevelRequirement attribute, patching them with a prefix.
/// </summary>
public static class HideLevelExec
public static class HideseyAttributeManager
{
/// <summary>
/// Initializes the HideLevelExec by finding and patching methods with HideLevelRequirement attributes.
@@ -21,40 +21,51 @@ public static void Initialize()
{
Assembly assembly = Assembly.GetExecutingAssembly();
IEnumerable<Type> types = assembly.GetTypes();
IEnumerable<Type> marseyTypes = types.Where(t => t.Namespace != null && t.Namespace.StartsWith("Marsey"));

IEnumerable<Type> marseyTypes = Assembly.GetExecutingAssembly().ExportedTypes;

foreach (Type type in marseyTypes)
{
CheckAndExecute(type);
}
}

/// <summary>
/// Checks each type for methods with HideLevelRequirement attributes and executes them if the hide level is met.
/// </summary>
private static void CheckAndExecute(Type type)
{
// Get all methods from the given type
IEnumerable<MethodInfo> methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance);
IEnumerable<MethodInfo> methods = AccessTools.GetDeclaredMethods(type);

foreach (MethodInfo method in methods)
{
ExecIfLevelMet(method);
SetExecLevels(method);
SetPatchless(method);
}
}

/// <summary>
/// Executes the method if the current hide level meets or exceeds the required level specified by the HideLevelRequirement attribute.
/// </summary>
private static void ExecIfLevelMet(MethodInfo method)
private static void SetExecLevels(MethodInfo method)
{
HideLevelRequirement? hideLevelRequirement = method.GetCustomAttribute<HideLevelRequirement>();
HideLevelRestriction? hideLevelRestriction = method.GetCustomAttribute<HideLevelRestriction>();

if (hideLevelRequirement == null && hideLevelRestriction == null) return;

MethodInfo? prefix = typeof(HideseyPatches).GetMethod("LevelCheck", BindingFlags.Public | BindingFlags.Static);
Manual.Patch(method, prefix, HarmonyPatchType.Prefix);
}
}

private static void SetPatchless(MethodInfo method)
{
if (method.GetCustomAttribute<Patching>() is null) return;
if (method.IsGenericMethod) throw new InvalidOperationException("Patching attribute not allowed on generic methods.");

MethodInfo? prefix = AccessTools.Method(typeof(HideseyPatches), nameof(HideseyPatches.SkipPatchless));

Manual.Patch(method, prefix, HarmonyPatchType.Prefix);
}
}
10 changes: 10 additions & 0 deletions Marsey/Stealthsey/Reflection/PatchingAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Reflection;

namespace Marsey.Stealthsey.Reflection;

/// <summary>
/// Method is patching the game in some form
/// <remarks> Does not execute if <see cref="Patching"/> is true </remarks>
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class Patching : Attribute;
1 change: 1 addition & 0 deletions Marsey/Subversion/Subverse.cs
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ public static bool CheckSubversions()
/// This is done as we attach to the assembly loading function
/// </summary>
[HideLevelRestriction(HideLevel.Unconditional)]
[Patching]
public static void PatchSubverter()
{

6 changes: 5 additions & 1 deletion SS14.Launcher/Models/Connector.cs
Original file line number Diff line number Diff line change
@@ -573,6 +573,9 @@ private async Task<ProcessStartInfo> GetLoaderStartInfo(string engineVersion, lo
startInfo.EnvironmentVariables["SS14_LOADER_CONTENT_VERSION"] = contentVersion.ToString();
startInfo.EnvironmentVariables["SS14_LAUNCHER_PATH"] = Process.GetCurrentProcess().MainModule!.FileName;

if (_cfg.GetCVar(CVars.DisallowHwid))
startInfo.EnvironmentVariables["ROBUST_AUTH_ALLOW_HWID"] = "0";

return startInfo;
}

@@ -611,7 +614,8 @@ private void ConfigureMarsey()
{ "MARSEY_BACKPORTS", _cfg.GetCVar(CVars.Backports) ? "true" : null },
{ "MARSEY_NO_ANY_BACKPORTS", _cfg.GetCVar(CVars.DisableAnyEngineBackports) ? "true" : null },
{ "MARSEY_DISABLE_STRICT", _cfg.GetCVar(CVars.DisableStrict) ? "true" : null },
{ "MARSEY_DUMP_ASSEMBLIES", MarseyConf.Dumper ? "true" : null }
{ "MARSEY_DUMP_ASSEMBLIES", MarseyConf.Dumper ? "true" : null },
{ "MARSEY_PATCHLESS", _cfg.GetCVar(CVars.Patchless) ? "true" : null }
};

// Serialize environment variables
10 changes: 10 additions & 0 deletions SS14.Launcher/Models/Data/CVars.cs
Original file line number Diff line number Diff line change
@@ -259,6 +259,16 @@ public static readonly CVarDef<bool> HasDismissedEarlyAccessWarning
/// Username used in guest mode
/// </summary>
public static readonly CVarDef<string> GuestUsername = CVarDef.Create("GuestUsername", "Guest");

/// <summary>
/// Do not patch anything in the game modules
/// </summary>
public static readonly CVarDef<bool> Patchless = CVarDef.Create("Patchless", false);

/// <summary>
/// HWID2 - Disallow sending hwid to server.
/// </summary>
public static readonly CVarDef<bool> DisallowHwid = CVarDef.Create("DisallowHwid", false);
}

/// <summary>
20 changes: 20 additions & 0 deletions SS14.Launcher/ViewModels/MainWindowTabs/OptionsTabViewModel.cs
Original file line number Diff line number Diff line change
@@ -272,7 +272,7 @@
}
}

private string _RPCUsername = "";

Check warning on line 275 in SS14.Launcher/ViewModels/MainWindowTabs/OptionsTabViewModel.cs

GitHub Actions / build

The field 'OptionsTabViewModel._RPCUsername' is assigned but its value is never used
public string RPCUsername
{
get => Cfg.GetCVar(CVars.RPCUsername);
@@ -499,6 +499,26 @@
set => MarseyConf.Dumper = value;
}

public bool HWID2OptOut
{
get => Cfg.GetCVar(CVars.DisallowHwid);
set
{
Cfg.SetCVar(CVars.DisallowHwid, value);
Cfg.CommitConfig();
}
}

public bool Patchless
{
get => Cfg.GetCVar(CVars.Patchless);
set
{
Cfg.SetCVar(CVars.Patchless, value);
Cfg.CommitConfig();
}
}

public bool ResourceOverride
{
get => Cfg.GetCVar(CVars.DisableStrict);
15 changes: 15 additions & 0 deletions SS14.Launcher/Views/MainWindowTabs/OptionsTabView.xaml
Original file line number Diff line number Diff line change
@@ -19,6 +19,14 @@
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<DockPanel>
<StackPanel Orientation="Vertical">
<CheckBox VerticalAlignment="Center" Margin="4" IsChecked="{Binding HWID2OptOut}">Explicitly disallow HWID</CheckBox>
<StackPanel Margin="8">
<TextBlock VerticalAlignment="Center" TextWrapping="Wrap"
Text="[Patchless] HWId2 - Opt out of sending your HWId to the server."/>
<TextBlock VerticalAlignment="Center" FontWeight="Bold" TextWrapping="Wrap"
Text="Servers may require a HWId in the future, as HWId2 works (sort of) on Linux."/>
</StackPanel>

<CheckBox VerticalAlignment="Center" Margin="4" IsChecked="{Binding CompatMode}">Compatibility Mode</CheckBox>
<TextBlock VerticalAlignment="Center" TextWrapping="Wrap"
Text="This uses OpenGL ES 2 (via ANGLE if necessary), which is less likely to suffer from driver bugs. Try this if you are experiencing graphical issues or crashes."
@@ -127,6 +135,8 @@
Text="Gives a random HWId each time you connect to a server."/>
<TextBlock VerticalAlignment="Center" FontWeight="Bold" TextWrapping="Wrap"
Text="Detection vector. Don't use on main accounts."/>
<TextBlock VerticalAlignment="Center" FontWeight="Bold" TextWrapping="Wrap"
Text="HWId2 - a lot of hwids on one account may harm trust in the future."/>
</StackPanel>

<TextBlock Margin="4, 0" Text="Patching" Classes="NanoHeadingMedium" />
@@ -251,6 +261,11 @@
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<DockPanel>
<StackPanel Orientation="Vertical">
<CheckBox VerticalAlignment="Center" Margin="4" IsChecked="{Binding Patchless}">Run patchless</CheckBox>
<TextBlock VerticalAlignment="Center" TextWrapping="Wrap"
Text="Disables any patching except hiding harmony, essentially acting like a killswitch. Useful when game breaks due to the launcher itself."
Margin="8" />

<TextBlock Margin="4, 0" Text="Patches" Classes="NanoHeadingMedium" />
<CheckBox VerticalAlignment="Center" Margin="4" IsChecked="{Binding DumpAssemblies}">Dump Resources</CheckBox>
<TextBlock VerticalAlignment="Center" TextWrapping="Wrap"
14 changes: 9 additions & 5 deletions SS14.Launcher/Views/MainWindowTabs/PatchesTabView.xaml
Original file line number Diff line number Diff line change
@@ -120,11 +120,15 @@
</ScrollViewer>
</TabItem>
</TabControl>
<StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Right">
<Button Content="Open mod directory" Margin="4, 0" HorizontalAlignment="Right"
Command="{Binding OpenPatchDirectoryCommand}" Height="30"/>
<Button Content="Recheck mods" Margin="4, 0" HorizontalAlignment="Right"
Command="{Binding ReloadModsCommand}" Height="30"/>
<StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Center">
<DockPanel LastChildFill="True">
<TextBlock Text="Patches are unsandboxed, run at own risk."
VerticalAlignment="Bottom" FontWeight="Bold" HorizontalAlignment="Left" DockPanel.Dock="Left"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Open mod directory" Margin="4, 0" Command="{Binding OpenPatchDirectoryCommand}" Height="30"/>
<Button Content="Recheck mods" Margin="4, 0" Command="{Binding ReloadModsCommand}" Height="30"/>
</StackPanel>
</DockPanel>
</StackPanel>
</Grid>
</ScrollViewer>

0 comments on commit 34287e9

Please sign in to comment.