From 97b9eb6c34c9dac726bad5aa5cc74386a17e40c0 Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Tue, 6 Apr 2021 22:11:14 -0500 Subject: [PATCH] Library loader now scans libraries before loading them --- IPA.Injector/Injector.cs | 3 +- IPA.Loader/AntiMalware/AntiMalwareEngine.cs | 14 +++++- IPA.Loader/Loader/LibLoader.cs | 51 +++++++++++++++------ 3 files changed, 50 insertions(+), 18 deletions(-) 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;