diff --git a/IPA.Loader/AntiMalware/AntiMalwareEngine.cs b/IPA.Loader/AntiMalware/AntiMalwareEngine.cs new file mode 100644 index 00000000..9ca16586 --- /dev/null +++ b/IPA.Loader/AntiMalware/AntiMalwareEngine.cs @@ -0,0 +1,25 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IPA.AntiMalware +{ + public static class AntiMalwareEngine + { + public static IAntiMalware Engine { get; } = InitializeEngine(); + + private static IAntiMalware InitializeEngine() + { + IAntiMalware? engine = null; +#if !NET35 + engine = WindowsAntiMalware.TryInitialize(); +#endif + engine ??= new NoopAntiMalware(); + + return engine; + } + } +} diff --git a/IPA.Loader/AntiMalware/IAntiMalware.cs b/IPA.Loader/AntiMalware/IAntiMalware.cs new file mode 100644 index 00000000..0d974a34 --- /dev/null +++ b/IPA.Loader/AntiMalware/IAntiMalware.cs @@ -0,0 +1,11 @@ +#nullable enable +using System.IO; + +namespace IPA.AntiMalware +{ + public interface IAntiMalware + { + ScanResult ScanFile(FileInfo file); + ScanResult ScanData(byte[] data, string? contentName = null); + } +} diff --git a/IPA.Loader/AntiMalware/NoopAntiMalware.cs b/IPA.Loader/AntiMalware/NoopAntiMalware.cs new file mode 100644 index 00000000..60609898 --- /dev/null +++ b/IPA.Loader/AntiMalware/NoopAntiMalware.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IPA.AntiMalware +{ + internal class NoopAntiMalware : IAntiMalware + { + public ScanResult ScanData(byte[] data, string contentName = null) => ScanResult.NotDetected; + public ScanResult ScanFile(FileInfo file) => ScanResult.NotDetected; + } +} diff --git a/IPA.Loader/AntiMalware/ScanResult.cs b/IPA.Loader/AntiMalware/ScanResult.cs new file mode 100644 index 00000000..ba17fde9 --- /dev/null +++ b/IPA.Loader/AntiMalware/ScanResult.cs @@ -0,0 +1,11 @@ + +namespace IPA.AntiMalware +{ + public enum ScanResult + { + KnownSafe, + NotDetected, + Detected, + BlockedByPolicy + } +} diff --git a/IPA.Loader/AntiMalware/WinAPI/AmsiFileStream.cs b/IPA.Loader/AntiMalware/_HideInNet3/WinAPI/AmsiFileStream.cs similarity index 100% rename from IPA.Loader/AntiMalware/WinAPI/AmsiFileStream.cs rename to IPA.Loader/AntiMalware/_HideInNet3/WinAPI/AmsiFileStream.cs diff --git a/IPA.Loader/AntiMalware/WinAPI/AmsiMemoryStream.cs b/IPA.Loader/AntiMalware/_HideInNet3/WinAPI/AmsiMemoryStream.cs similarity index 100% rename from IPA.Loader/AntiMalware/WinAPI/AmsiMemoryStream.cs rename to IPA.Loader/AntiMalware/_HideInNet3/WinAPI/AmsiMemoryStream.cs diff --git a/IPA.Loader/AntiMalware/WinAPI/Constants.cs b/IPA.Loader/AntiMalware/_HideInNet3/WinAPI/Constants.cs similarity index 53% rename from IPA.Loader/AntiMalware/WinAPI/Constants.cs rename to IPA.Loader/AntiMalware/_HideInNet3/WinAPI/Constants.cs index e841cb6c..65dc96cc 100644 --- a/IPA.Loader/AntiMalware/WinAPI/Constants.cs +++ b/IPA.Loader/AntiMalware/_HideInNet3/WinAPI/Constants.cs @@ -9,6 +9,7 @@ namespace IPA.AntiMalware.WinAPI { internal static class AmsiConstants { - public static const string AppName = "BSIPA/" + Config.SelfConfig.IPAVersion; + public const string AppName = "BSIPA/" + Config.SelfConfig.IPAVersion; + public static readonly Guid CAntimalwareGuid = new("fdb00e52-a214-4aa1-8fba-4357bb0072ec"); } } diff --git a/IPA.Loader/AntiMalware/WinAPI/IAntimalware.cs b/IPA.Loader/AntiMalware/_HideInNet3/WinAPI/IAntimalware.cs similarity index 100% rename from IPA.Loader/AntiMalware/WinAPI/IAntimalware.cs rename to IPA.Loader/AntiMalware/_HideInNet3/WinAPI/IAntimalware.cs diff --git a/IPA.Loader/AntiMalware/_HideInNet3/WindowsAntiMalware.cs b/IPA.Loader/AntiMalware/_HideInNet3/WindowsAntiMalware.cs new file mode 100644 index 00000000..d5bc671c --- /dev/null +++ b/IPA.Loader/AntiMalware/_HideInNet3/WindowsAntiMalware.cs @@ -0,0 +1,64 @@ +#nullable enable +using IPA.AntiMalware.WinAPI; +using IPA.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IPA.AntiMalware +{ + internal class WindowsAntiMalware : IAntiMalware + { + internal static WindowsAntiMalware? TryInitialize() + { + try + { + return new(); + } + catch (Exception e) + { + Logger.AntiMalware.Warn("Could not initialize antimalware engine:"); + Logger.AntiMalware.Warn(e); + return null; + } + } + + private readonly IAntimalware amInterface; + + private WindowsAntiMalware() + { + var amType = Type.GetTypeFromCLSID(AmsiConstants.CAntimalwareGuid, true); + amInterface = (IAntimalware)Activator.CreateInstance(amType); + } + + private static ScanResult ScanResultFromAmsiResult(AmsiResult result) + => result switch + { + AmsiResult.Clean => ScanResult.KnownSafe, + AmsiResult.NotDetected => ScanResult.NotDetected, + AmsiResult.Detected => ScanResult.Detected, + var a when a is >= AmsiResult.BlockedByAdminStart and <= AmsiResult.BlockedByAdminEnd => ScanResult.BlockedByPolicy, + _ => ScanResult.NotDetected, + }; + + public ScanResult ScanFile(FileInfo file) + { + using var stream = new AmsiFileStream(file, IntPtr.Zero); + amInterface.Scan(stream, out var result, out var provider); + Logger.AntiMalware.Debug($"Scanned file '{file}' with {provider.DisplayName()}, and got '{result}'"); + return ScanResultFromAmsiResult(result); + } + + public ScanResult ScanData(byte[] data, string? contentName = null) + { + contentName ??= $"unknown_data_{Guid.NewGuid()}"; + using var stream = new AmsiMemoryStream(contentName, data, IntPtr.Zero); + amInterface.Scan(stream, out var result, out var provider); + Logger.AntiMalware.Debug($"Scanned data named '{contentName}' with {provider.DisplayName()}, and got '{result}'"); + return ScanResultFromAmsiResult(result); + } + } +} diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj index 6d3ff5e4..c14a9de5 100644 --- a/IPA.Loader/IPA.Loader.csproj +++ b/IPA.Loader/IPA.Loader.csproj @@ -70,8 +70,8 @@ - - + + diff --git a/IPA.Loader/Logging/Logger.cs b/IPA.Loader/Logging/Logger.cs index 13d2d8c3..d89f4f50 100644 --- a/IPA.Loader/Logging/Logger.cs +++ b/IPA.Loader/Logging/Logger.cs @@ -33,6 +33,7 @@ namespace IPA.Logging } } + internal static Logger AntiMalware => log.GetChildLogger("AntiMalware"); internal static Logger updater => log.GetChildLogger("Updater"); internal static Logger libLoader => log.GetChildLogger("LibraryLoader"); internal static Logger injector => log.GetChildLogger("Injector");