You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
3.1 KiB

  1. #nullable enable
  2. using IPA.AntiMalware.ComAPI;
  3. using IPA.Logging;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. namespace IPA.AntiMalware
  12. {
  13. internal class WindowsCOMAntiMalware : IAntiMalware
  14. {
  15. internal static WindowsCOMAntiMalware? TryInitialize()
  16. {
  17. // Mono's COM interop *fundamentally doesn't work.*
  18. // End of story.
  19. #if false
  20. try
  21. {
  22. return new();
  23. }
  24. catch (Exception e)
  25. {
  26. Logger.AntiMalware.Warn("Could not initialize COM-based antimalware engine:");
  27. Logger.AntiMalware.Warn(e);
  28. }
  29. #endif
  30. return null;
  31. }
  32. private readonly IAntimalware amInterface;
  33. private WindowsCOMAntiMalware()
  34. {
  35. var hr = CoCreateInstanceAM(AmsiConstants.CAntimalwareGuid,
  36. null,
  37. 0x1 | 0x4 /* inproc server, local server */,
  38. AmsiConstants.IAntimalwareGuid,
  39. out var antimalware);
  40. Marshal.ThrowExceptionForHR(hr);
  41. amInterface = antimalware;
  42. }
  43. [DllImport("ole32",
  44. CallingConvention = CallingConvention.Winapi,
  45. ExactSpelling = true,
  46. PreserveSig = false,
  47. EntryPoint = "CoCreateInstance")]
  48. [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
  49. private static extern int CoCreateInstanceAM(
  50. [In] in Guid clsid,
  51. [In, MarshalAs(UnmanagedType.Interface)] object? unkOuter,
  52. [In] int dwClsContext,
  53. [In] in Guid iid,
  54. [Out, MarshalAs(UnmanagedType.Interface)] out IAntimalware @interface);
  55. private static ScanResult ScanResultFromAmsiResult(AmsiResult result)
  56. => result switch
  57. {
  58. AmsiResult.Clean => ScanResult.KnownSafe,
  59. AmsiResult.NotDetected => ScanResult.NotDetected,
  60. AmsiResult.Detected => ScanResult.Detected,
  61. _ => ScanResult.MaybeMalware
  62. };
  63. public ScanResult ScanFile(FileInfo file)
  64. {
  65. using var stream = new AmsiFileStream(file, IntPtr.Zero);
  66. amInterface.Scan(stream, out var result, out var provider);
  67. Logger.AntiMalware.Trace($"Scanned file '{file}' with {provider.DisplayName()}, and got '{result}'");
  68. return ScanResultFromAmsiResult(result);
  69. }
  70. public ScanResult ScanData(byte[] data, string? contentName = null)
  71. {
  72. contentName ??= $"unknown_data_{Guid.NewGuid()}";
  73. using var stream = new AmsiMemoryStream(contentName, data, IntPtr.Zero);
  74. amInterface.Scan(stream, out var result, out var provider);
  75. Logger.AntiMalware.Trace($"Scanned data named '{contentName}' with {provider.DisplayName()}, and got '{result}'");
  76. return ScanResultFromAmsiResult(result);
  77. }
  78. }
  79. }