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

Commit

Permalink
Added warning when module is installed in /Modules and subscribed on …
Browse files Browse the repository at this point in the history
…Workshop at the same time
  • Loading branch information
Aragas committed Nov 30, 2022
1 parent f3c338a commit 858e8d1
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 71 deletions.
4 changes: 2 additions & 2 deletions build/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

<!--Development Variables-->
<PropertyGroup>
<Version>1.10.4</Version>
<Version>1.11.0</Version>
<HarmonyVersion>2.2.2</HarmonyVersion>
<BUTRSharedVersion>3.0.0.122</BUTRSharedVersion>
<BUTRSharedVersion>3.0.0.124</BUTRSharedVersion>
<BUTRModuleManagerVersion>4.0.150</BUTRModuleManagerVersion>
<HarmonyExtensionsVersion>3.1.0.68</HarmonyExtensionsVersion>
<HarmonyAnalyzerVersion>1.0.1.44</HarmonyAnalyzerVersion>
Expand Down
4 changes: 4 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
---------------------------------------------------------------------------------------------------
Version: 1.11.0
Game Versions: v1.0.0,v1.0.1,v1.0.2
* Added warning when module is installed in /Modules and subscribed on Workshop at the same time
---------------------------------------------------------------------------------------------------
Version: 1.10.4
Game Versions: v1.0.0,v1.0.1,v1.0.2
* Improved the obfuscation check
Expand Down
60 changes: 60 additions & 0 deletions src/Bannerlord.BUTRLoader.LauncherEx/Helpers/ModuleChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Bannerlord.BUTR.Shared.Helpers;
using Bannerlord.ModuleManager;

using Mono.Cecil;
using Mono.Cecil.Rocks;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using TaleWorlds.Library;
using TaleWorlds.MountAndBlade;

namespace Bannerlord.BUTRLoader.Helpers
{
internal static class ModuleChecker
{
private static readonly HashSet<string> MainModules = ModuleInfoHelper.GetPhysicalModules().Select(x => x.Id).ToHashSet();
private static readonly HashSet<string> ExternalModules = ModuleInfoHelper.GetPlatformModules().Select(x => x.Id).ToHashSet();

public static bool IsInstalledInMainAndExternalModuleDirectory(ModuleInfoExtendedWithMetadata moduleInfoExtended) =>
MainModules.Contains(moduleInfoExtended.Id) && ExternalModules.Contains(moduleInfoExtended.Id);

public static bool IsObfuscated(ModuleInfoExtendedWithMetadata moduleInfoExtended)
{
static bool CanBeLoaded(SubModuleInfoExtended x) =>
ModuleInfoHelper.CheckIfSubModuleCanBeLoaded(x, ApplicationPlatform.CurrentPlatform, ApplicationPlatform.CurrentRuntimeLibrary, DedicatedServerType.None, false);

foreach (var subModule in moduleInfoExtended.SubModules.Where(CanBeLoaded))
{
var asm = Path.GetFullPath(Path.Combine(moduleInfoExtended.Path, "bin", "Win64_Shipping_Client", subModule.DLLName));

try
{
using var moduleDefinition = ModuleDefinition.ReadModule(asm);

var hasObfuscationAttributeUsed = moduleDefinition.GetCustomAttributes().Any(x => x.Constructor.DeclaringType.Name switch
{
"ConfusedByAttribute" => true,
_ => false
});
var hasObfuscationAttributeDeclared = moduleDefinition.Types.Any(x => x.Name switch
{
"ConfusedByAttribute" => true,
_ => false
});
// Every module should have a module initializer. If it's missing, someone is hiding it
var hasModuleInitializer = moduleDefinition.GetAllTypes().Any(x => x.Name == "<Module>");

return hasObfuscationAttributeUsed || hasObfuscationAttributeDeclared || !hasModuleInitializer;
}
// Failing to read the metadata is a direct sign of metadata manipulation
catch (Exception) { return true; }
}

return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,9 @@
using Bannerlord.BUTR.Shared.Utils;
using Bannerlord.BUTRLoader.Extensions;
using Bannerlord.BUTRLoader.Helpers;
using Bannerlord.ModuleManager;

using HarmonyLib.BUTR.Extensions;

using Mono.Cecil;
using Mono.Cecil.Rocks;

using System;
using System.IO;
using System.Linq;

using TaleWorlds.Library;
using TaleWorlds.MountAndBlade;
using TaleWorlds.MountAndBlade.Launcher.Library;

namespace Bannerlord.BUTRLoader.Patches.Mixins
Expand Down Expand Up @@ -67,16 +57,16 @@ public bool IsNoUpdateAvailable
}
private bool _isNoUpdateAvailable;

public LauncherHintVM DependencyHint2 { get; }
public LauncherHintVM? DependencyHint2 { get; }
public bool AnyDependencyAvailable2 { get; }

public bool IsDangerous2 { get; }


public bool IsDisabled2 { get; }


private readonly LauncherModuleVM _launcherModuleVM;
private readonly string _moduleId;

public LauncherModuleVMMixin(LauncherModuleVM launcherModuleVM)
{
Expand All @@ -97,80 +87,46 @@ void SetVMProperty(string property)
SetVMProperty(nameof(IsDisabled2));
SetVMProperty(nameof(IsDangerous2));

var id = _launcherModuleVM.Info.Id ?? string.Empty;
var moduleInfoExtended = ModuleInfoHelper.LoadFromId(id);
if (moduleInfoExtended is not null && ModuleInfoHelper2.GetDependencyHint(moduleInfoExtended) is { } str)
if (ModuleInfoHelper.LoadFromId(_launcherModuleVM.Info.Id) is { } moduleInfoExtended)
{
DependencyHint2 = new LauncherHintVM(str);
AnyDependencyAvailable2 = !string.IsNullOrEmpty(str);
SetVMProperty(nameof(DependencyHint2));
SetVMProperty(nameof(AnyDependencyAvailable2));
}
if (ModuleInfoHelper2.GetDependencyHint(moduleInfoExtended) is { } str)
{
DependencyHint2 = new LauncherHintVM(str);
AnyDependencyAvailable2 = !string.IsNullOrEmpty(str);
SetVMProperty(nameof(DependencyHint2));
SetVMProperty(nameof(AnyDependencyAvailable2));
}

_moduleId = _launcherModuleVM.Info.Id ?? string.Empty;
var dangerous = string.Empty;
if (ModuleChecker.IsInstalledInMainAndExternalModuleDirectory(moduleInfoExtended))
dangerous += "The Module is installed in the game's /Modules folder and on Steam Workshop!\nThe /Modules version will be used!\n";
if (ModuleChecker.IsObfuscated(moduleInfoExtended))
dangerous += "The DLL is obfuscated!\nThere is no guarantee that the code is safe!\nThe BUTR Team warns of consequences arising from running obfuscated code!\n";
if (!string.IsNullOrEmpty(dangerous))
{
IsDangerous2 = true;
_launcherModuleVM.DangerousHint = new LauncherHintVM(dangerous);
}
}

IsDisabled2 = LauncherModuleVMPatch.AreAllDepenenciesPresentReferences.TryGetValue(launcherModuleVM, out var del)
? !(bool) del.DynamicInvoke(_launcherModuleVM.Info)
: true;

UpdateIssues();
UpdateIssues(_launcherModuleVM.Info.Id);

if (CheckModuleDangerous(moduleInfoExtended))
{
IsDangerous2 = true;
_launcherModuleVM.DangerousHint = new LauncherHintVM(
"The DLL is obfuscated!\nThere is no guarantee that the code is safe!\nThe BUTR Team warns of consequences arising from running obfuscated code!");
}
_launcherModuleVM.PropertyChanged += (_, e) =>
{
if (e.PropertyName == "Refresh_Command")
UpdateIssues();
UpdateIssues(_launcherModuleVM.Info.Id);
};
}

public void UpdateIssues()
private void UpdateIssues(string id)
{
IssuesText = IssueStorage.Issues.TryGetValue(_moduleId, out var issues) && issues.Count > 0
IssuesText = IssueStorage.Issues.TryGetValue(id, out var issues) && issues.Count > 0
? string.Join("\n", issues)
: string.Empty;
}

private static bool CheckModuleDangerous(ModuleInfoExtended? moduleInfoExtended)
{
static bool CanBeLoaded(SubModuleInfoExtended x) =>
ModuleInfoHelper.CheckIfSubModuleCanBeLoaded(x, ApplicationPlatform.CurrentPlatform, ApplicationPlatform.CurrentRuntimeLibrary, DedicatedServerType.None, false);

if (moduleInfoExtended is not ModuleInfoExtendedWithMetadata moduleInfoExtendedWithMetadata)
return false;

foreach (var subModule in moduleInfoExtended.SubModules.Where(CanBeLoaded))
{
var asm = Path.GetFullPath(Path.Combine(moduleInfoExtendedWithMetadata.Path, "bin", "Win64_Shipping_Client", subModule.DLLName));

try
{
using var moduleDefinition = ModuleDefinition.ReadModule(asm);

var hasObfuscationAttributeUsed = moduleDefinition.GetCustomAttributes().Any(x => x.Constructor.DeclaringType.Name switch
{
"ConfusedByAttribute" => true,
_ => false
});
var hasObfuscationAttributeDeclared = moduleDefinition.Types.Any(x => x.Name switch
{
"ConfusedByAttribute" => true,
_ => false
});
// Every module should have a module initializer. If it's missing, someone is hiding it
var hasModuleInitializer = moduleDefinition.GetAllTypes().Any(x => x.Name == "<Module>");

return hasObfuscationAttributeUsed || hasObfuscationAttributeDeclared || !hasModuleInitializer;
}
// Failing to read the metadata is a direct sign of metadata manipulation
catch (Exception) { return true; }
}

return false;
}
}
}

0 comments on commit 858e8d1

Please sign in to comment.