diff --git a/IPA.Injector/Injector.cs b/IPA.Injector/Injector.cs
index 26542ea9..edaa9ea2 100644
--- a/IPA.Injector/Injector.cs
+++ b/IPA.Injector/Injector.cs
@@ -85,8 +85,7 @@ namespace IPA.Injector
GameVersionEarly.Load();
- // load the anti-malware engine
- _ = AntiMalwareEngine.Engine;
+ AntiMalwareEngine.Initialize();
Updates.InstallPendingUpdates();
diff --git a/IPA.Loader/AntiMalware/AntiMalwareEngine.cs b/IPA.Loader/AntiMalware/AntiMalwareEngine.cs
index 501aa0d3..dc9aef79 100644
--- a/IPA.Loader/AntiMalware/AntiMalwareEngine.cs
+++ b/IPA.Loader/AntiMalware/AntiMalwareEngine.cs
@@ -1,6 +1,7 @@
#nullable enable
using IPA.Config;
using IPA.Logging;
+using System;
namespace IPA.AntiMalware
{
@@ -11,12 +12,21 @@ namespace IPA.AntiMalware
///
public static class AntiMalwareEngine
{
+ private static IAntiMalware? engine;
+
///
/// Gets the current Anti-Malware engine.
///
- public static IAntiMalware Engine { get; } = InitializeEngine();
+ public static IAntiMalware Engine => engine ?? throw new InvalidOperationException();
+
+ internal static bool IsInitialized => engine != null;
+
+ internal static void Initialize()
+ {
+ engine = CreateEngine();
+ }
- private static IAntiMalware InitializeEngine()
+ private static IAntiMalware CreateEngine()
{
IAntiMalware? engine = null;
if (SelfConfig.AntiMalware_.UseIfAvailable_)
diff --git a/IPA.Loader/Loader/LibLoader.cs b/IPA.Loader/Loader/LibLoader.cs
index 3f0a0076..710375b4 100644
--- a/IPA.Loader/Loader/LibLoader.cs
+++ b/IPA.Loader/Loader/LibLoader.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
@@ -9,6 +10,8 @@ using System.Linq;
using IPA.Logging;
using IPA.Utilities;
using Mono.Cecil;
+using IPA.AntiMalware;
+using IPA.Config;
#if NET3
using Net3_Proxy;
using Directory = Net3_Proxy.Directory;
@@ -50,7 +53,7 @@ namespace IPA.Loader
{
internal static string LibraryPath => Path.Combine(Environment.CurrentDirectory, "Libs");
internal static string NativeLibraryPath => Path.Combine(LibraryPath, "Native");
- internal static Dictionary FilenameLocations;
+ internal static Dictionary FilenameLocations = null!;
internal static void Configure()
{
@@ -113,13 +116,13 @@ namespace IPA.Loader
}
}
- public static Assembly AssemblyLibLoader(object source, ResolveEventArgs e)
+ public static Assembly? AssemblyLibLoader(object source, ResolveEventArgs e)
{
var asmName = new AssemblyName(e.Name);
return LoadLibrary(asmName);
}
- internal static Assembly LoadLibrary(AssemblyName asmName)
+ internal static Assembly? LoadLibrary(AssemblyName asmName)
{
Log(Logger.Level.Debug, $"Resolving library {asmName}");
@@ -131,19 +134,13 @@ namespace IPA.Loader
if (FilenameLocations.TryGetValue(testFile, out var path))
{
Log(Logger.Level.Debug, $"Found file {testFile} as {path}");
- if (File.Exists(path))
- return Assembly.LoadFrom(path);
-
- Log(Logger.Level.Critical, $"but {path} no longer exists!");
+ return LoadSafe(path);
}
else if (FilenameLocations.TryGetValue(testFile = $"{asmName.Name}.{asmName.Version}.dll", out path))
{
Log(Logger.Level.Debug, $"Found file {testFile} as {path}");
Log(Logger.Level.Warning, $"File {testFile} should be renamed to just {asmName.Name}.dll");
- if (File.Exists(path))
- return Assembly.LoadFrom(path);
-
- Log(Logger.Level.Critical, $"but {path} no longer exists!");
+ return LoadSafe(path);
}
Log(Logger.Level.Critical, $"No library {asmName} found");
@@ -151,7 +148,33 @@ namespace IPA.Loader
return null;
}
- internal static void Log(Logger.Level lvl, string message)
+ private static Assembly? LoadSafe(string path)
+ {
+ if (!File.Exists(path))
+ {
+ Log(Logger.Level.Critical, $"{path} no longer exists!");
+ return null;
+ }
+
+ if (AntiMalwareEngine.IsInitialized)
+ {
+ var result = AntiMalwareEngine.Engine.ScanFile(new FileInfo(path));
+ if (result is ScanResult.Detected)
+ {
+ Log(Logger.Level.Error, $"Scan of '{path}' found malware; not loading");
+ return null;
+ }
+ if (!SelfConfig.AntiMalware_.RunPartialThreatCode_ && result is not ScanResult.KnownSafe and not ScanResult.NotDetected)
+ {
+ Log(Logger.Level.Error, $"Scan of '{path}' found partial threat; not loading. To load this, enable AntiMalware.RunPartialThreatCode in the config.");
+ return null;
+ }
+ }
+
+ return Assembly.LoadFrom(path);
+ }
+
+ internal static void Log(Logger.Level lvl, string message)
{ // multiple proxy methods to delay loading of assemblies until it's done
if (Logger.LogCreated)
AssemblyLibLoaderCallLogger(lvl, message);
@@ -172,7 +195,7 @@ namespace IPA.Loader
private static void AssemblyLibLoaderCallLogger(Logger.Level lvl, Exception message) => Logger.libLoader.Log(lvl, message);
// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree
- private static IEnumerable TraverseTree(string root, Func dirValidator = null)
+ private static IEnumerable TraverseTree(string root, Func? dirValidator = null)
{
if (dirValidator == null) dirValidator = s => true;