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.

104 lines
3.6 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 WindowsWin32AntiMalware : IAntiMalware, IDisposable
  14. {
  15. internal static WindowsWin32AntiMalware? TryInitialize()
  16. {
  17. try
  18. {
  19. return new();
  20. }
  21. catch (Exception e)
  22. {
  23. Logger.AntiMalware.Warn("Could not initialize antimalware engine:");
  24. Logger.AntiMalware.Warn(e);
  25. return null;
  26. }
  27. }
  28. private readonly IntPtr handle;
  29. private bool disposedValue;
  30. private WindowsWin32AntiMalware()
  31. {
  32. AmsiInitialize(AmsiConstants.AppName, out handle);
  33. }
  34. private static ScanResult ScanResultFromAmsiResult(AmsiResult result)
  35. => result switch
  36. {
  37. AmsiResult.Clean => ScanResult.KnownSafe,
  38. AmsiResult.NotDetected => ScanResult.NotDetected,
  39. AmsiResult.Detected => ScanResult.Detected,
  40. _ => ScanResult.MaybeMalware
  41. };
  42. public ScanResult ScanFile(FileInfo file)
  43. {
  44. var data = File.ReadAllBytes(file.FullName);
  45. return ScanData(data, file.FullName);
  46. }
  47. public ScanResult ScanData(byte[] data, string? contentName = null)
  48. {
  49. contentName ??= $"unknown_data_{Guid.NewGuid()}";
  50. Logger.AntiMalware.Debug($"Scanned data named '{contentName}' with {provider.DisplayName()}, and got '{result}'");
  51. return ScanResultFromAmsiResult(result);
  52. }
  53. protected virtual void Dispose(bool disposing)
  54. {
  55. if (!disposedValue)
  56. {
  57. if (disposing)
  58. {
  59. // we have no disposable managed state
  60. }
  61. AmsiUninitialize(handle);
  62. disposedValue = true;
  63. }
  64. }
  65. ~WindowsWin32AntiMalware()
  66. {
  67. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  68. Dispose(disposing: false);
  69. }
  70. public void Dispose()
  71. {
  72. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  73. Dispose(disposing: true);
  74. GC.SuppressFinalize(this);
  75. }
  76. [DllImport("amsi", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true)]
  77. [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
  78. private static extern void AmsiInitialize([MarshalAs(UnmanagedType.LPWStr)] string appName, [Out] out IntPtr handle);
  79. [DllImport("amsi", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true)]
  80. [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
  81. private static extern void AmsiUninitialize(IntPtr handle);
  82. [DllImport("amsi", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true)]
  83. [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
  84. private static extern void AmsiScanBuffer(IntPtr context,
  85. [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] buffer, uint length,
  86. [MarshalAs(UnmanagedType.LPWStr)] string contentName, IntPtr session, [Out] out AmsiResult result);
  87. }
  88. }