using System;
using System.IO;
using Vanara.InteropServices;
using static Vanara.PInvoke.AMSI;
namespace Vanara.PInvoke.Diagnostics
{
/// The ScanResult enumeration specifies the types of results returned by scans.
public enum ScanResult : uint
{
/// Known good. No detection found, and the result is likely not going to change after a future definition update.
Clean = AMSI_RESULT.AMSI_RESULT_CLEAN,
/// No detection found, but the result might change after a future definition update.
NotDetected = AMSI_RESULT.AMSI_RESULT_NOT_DETECTED,
/// A threat level less than the max was found, so there is a potential that the content is considered malware.
PotentialDetected = AMSI_RESULT.AMSI_RESULT_NOT_DETECTED + 1,
/// Detection found. The content is considered malware and should be blocked.
Detected = AMSI_RESULT.AMSI_RESULT_DETECTED,
}
/// Provides scanning of strings and buffers to detect malware using either the system provider or a custom provider.
public static class AntimalwareScan
{
private static SafeHAMSICONTEXT hCtx;
///
/// Gets or sets the provider to use for Antimalware scans. If , the system default provider is used.
///
/// The Antimalware scan provider.
public static IAntimalwareProvider Provider { get; set; }
/// Scans a buffer-full of content for malware.
/// The buffer from which to read the data to be scanned.
/// The filename, URL, unique script ID, or similar of the content being scanned.
/// The result of the scan.
public static ScanResult Scan(byte[] buffer, string contentName = null)
{
unsafe
{
fixed (byte* bufferPtr = buffer)
{
return Scan((IntPtr)bufferPtr, (uint)buffer.Length, contentName);
}
}
}
/// Scans a buffer-full of content for malware.
/// The buffer from which to read the data to be scanned.
/// The length, in bytes, of the data to be read from buffer.
/// The filename, URL, unique script ID, or similar of the content being scanned.
/// The result of the scan.
public static ScanResult Scan(IntPtr buffer, uint bufferLen, string contentName = null)
{
AMSI_RESULT result;
if (Provider is null)
{
EnsureContext();
using SafeHAMSISESSION session = new(hCtx);
AmsiScanBuffer(session.Context, buffer, bufferLen, contentName, session, out result).ThrowIfFailed();
return result.Convert();
}
else
{
using AmsiStream stream = new AmsiStream(new SafeCoTaskMemHandle(buffer, bufferLen, false), false);
Provider.Scan(stream, out result).ThrowIfFailed();
}
return result.Convert();
}
/// Scans a string for malware.
/// The string to be scanned.
/// The filename, URL, unique script ID, or similar of the content being scanned.
/// The result of the scan.
public static ScanResult Scan(string str, string contentName = null)
{
AMSI_RESULT result;
if (Provider is null)
{
EnsureContext();
using SafeHAMSISESSION session = new(hCtx);
AmsiScanString(session.Context, str, contentName, session, out result).ThrowIfFailed();
return result.Convert();
}
else
{
using AmsiStream stream = new AmsiStream(new SafeCoTaskMemString(str), false);
Provider.Scan(stream, out result).ThrowIfFailed();
}
return result.Convert();
}
/// Scans a file for malware.
/// The file from which to read the data to be scanned.
/// The result of the scan.
public static ScanResult Scan(FileInfo file) => Scan(File.ReadAllBytes(file.FullName), file.FullName);
private static ScanResult Convert(this AMSI_RESULT result) => result switch
{
AMSI_RESULT.AMSI_RESULT_CLEAN => ScanResult.Clean,
AMSI_RESULT.AMSI_RESULT_NOT_DETECTED => ScanResult.NotDetected,
>= AMSI_RESULT.AMSI_RESULT_DETECTED => ScanResult.Detected,
_ => ScanResult.PotentialDetected,
};
private static void EnsureContext()
{
if (hCtx is null || hCtx.IsInvalid)
{
AmsiInitialize(Guid.NewGuid().ToString(), out hCtx).ThrowIfFailed();
}
}
}
}