#nullable enable using IPA.AntiMalware.ComAPI; using IPA.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace IPA.AntiMalware { internal class WindowsCOMAntiMalware : IAntiMalware { internal static WindowsCOMAntiMalware? TryInitialize() { // Mono's COM interop *fundamentally doesn't work.* // End of story. #if false try { return new(); } catch (Exception e) { Logger.AntiMalware.Warn("Could not initialize COM-based antimalware engine:"); Logger.AntiMalware.Warn(e); } #endif return null; } private readonly IAntimalware amInterface; private WindowsCOMAntiMalware() { var hr = CoCreateInstanceAM(AmsiConstants.CAntimalwareGuid, null, 0x1 | 0x4 /* inproc server, local server */, AmsiConstants.IAntimalwareGuid, out var antimalware); Marshal.ThrowExceptionForHR(hr); amInterface = antimalware; } [DllImport("ole32", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = false, EntryPoint = "CoCreateInstance")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] private static extern int CoCreateInstanceAM( [In] in Guid clsid, [In, MarshalAs(UnmanagedType.Interface)] object? unkOuter, [In] int dwClsContext, [In] in Guid iid, [Out, MarshalAs(UnmanagedType.Interface)] out IAntimalware @interface); private static ScanResult ScanResultFromAmsiResult(AmsiResult result) => result switch { AmsiResult.Clean => ScanResult.KnownSafe, AmsiResult.NotDetected => ScanResult.NotDetected, AmsiResult.Detected => ScanResult.Detected, _ => ScanResult.MaybeMalware }; public ScanResult ScanFile(FileInfo file) { using var stream = new AmsiFileStream(file, IntPtr.Zero); amInterface.Scan(stream, out var result, out var provider); Logger.AntiMalware.Trace($"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.Trace($"Scanned data named '{contentName}' with {provider.DisplayName()}, and got '{result}'"); return ScanResultFromAmsiResult(result); } } }