using System;
using System.Runtime.InteropServices;
namespace Vanara.PInvoke
{
/// Items from the AMSI.dll.
public static partial class AMSI
{
private const string Lib_Amsi = "amsi.dll";
/// The AMSI_ATTRIBUTE enumeration specifies the types of attributes that can be requested by IAmsiStream::GetAttribute.
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/ne-amsi-amsi_attribute typedef enum AMSI_ATTRIBUTE {
// AMSI_ATTRIBUTE_APP_NAME, AMSI_ATTRIBUTE_CONTENT_NAME, AMSI_ATTRIBUTE_CONTENT_SIZE, AMSI_ATTRIBUTE_CONTENT_ADDRESS,
// AMSI_ATTRIBUTE_SESSION, AMSI_ATTRIBUTE_REDIRECT_CHAIN_SIZE, AMSI_ATTRIBUTE_REDIRECT_CHAIN_ADDRESS, AMSI_ATTRIBUTE_ALL_SIZE,
// AMSI_ATTRIBUTE_ALL_ADDRESS, AMSI_ATTRIBUTE_QUIET } ;
[PInvokeData("amsi.h", MSDNShortId = "NE:amsi.AMSI_ATTRIBUTE")]
public enum AMSI_ATTRIBUTE
{
///
/// Return the name, version, or GUID string of the calling application, copied from a LPWSTR.
///
AMSI_ATTRIBUTE_APP_NAME = 0,
///
/// Return the filename, URL, unique script ID, or similar of the content, copied from a LPWSTR.
///
AMSI_ATTRIBUTE_CONTENT_NAME,
///
/// Return the size of the input, as a ULONGLONG.
///
AMSI_ATTRIBUTE_CONTENT_SIZE,
/// Return the memory address if the content is fully loaded into memory.
AMSI_ATTRIBUTE_CONTENT_ADDRESS,
///
/// Session is used to associate different scan calls, such as if the contents to be scanned belong to the sample original
/// script. Return a PVOID to the next portion of the content to be scanned. Return NULL if the content is self-contained.
///
AMSI_ATTRIBUTE_SESSION,
///
AMSI_ATTRIBUTE_REDIRECT_CHAIN_SIZE,
///
AMSI_ATTRIBUTE_REDIRECT_CHAIN_ADDRESS,
///
AMSI_ATTRIBUTE_ALL_SIZE,
///
AMSI_ATTRIBUTE_ALL_ADDRESS,
///
AMSI_ATTRIBUTE_QUIET,
}
/// The AMSI_RESULT enumeration specifies the types of results returned by scans.
///
///
/// The antimalware provider may return a result between 1 and 32767, inclusive, as an estimated risk level. The larger the result,
/// the riskier it is to continue with the content. These values are provider specific, and may indicate a malware family or ID.
///
///
/// Results within the range of AMSI_RESULT_BLOCKED_BY_ADMIN_START and AMSI_RESULT_BLOCKED_BY_ADMIN_END values
/// (inclusive) are officially blocked by the admin specified policy. In these cases, the script in question will be blocked from
/// executing. The range is large to accommodate future additions in functionality.
///
///
/// Any return result equal to or larger than 32768 is considered malware, and the content should be blocked. An app should use
/// AmsiResultIsMalware to determine if this is the case.
///
///
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/ne-amsi-amsi_result typedef enum AMSI_RESULT { AMSI_RESULT_CLEAN,
// AMSI_RESULT_NOT_DETECTED, AMSI_RESULT_BLOCKED_BY_ADMIN_START, AMSI_RESULT_BLOCKED_BY_ADMIN_END, AMSI_RESULT_DETECTED } ;
[PInvokeData("amsi.h", MSDNShortId = "NE:amsi.AMSI_RESULT")]
public enum AMSI_RESULT : uint
{
/// Known good. No detection found, and the result is likely not going to change after a future definition update.
AMSI_RESULT_CLEAN = 0,
/// No detection found, but the result might change after a future definition update.
AMSI_RESULT_NOT_DETECTED = 1,
/// Administrator policy blocked this content on this machine (beginning of range).
AMSI_RESULT_BLOCKED_BY_ADMIN_START = 0x4000,
/// Administrator policy blocked this content on this machine (end of range).
AMSI_RESULT_BLOCKED_BY_ADMIN_END = 0x4fff,
/// Detection found. The content is considered malware and should be blocked.
AMSI_RESULT_DETECTED = 32768,
}
/// Close a session that was opened by AmsiOpenSession.
/// The handle of type HAMSICONTEXT that was initially received from AmsiInitialize.
/// The handle of type HAMSISESSION that was initially received from AmsiOpenSession.
/// None
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiclosesession void AmsiCloseSession( [in] HAMSICONTEXT
// amsiContext, [in] HAMSISESSION amsiSession );
[DllImport(Lib_Amsi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiCloseSession")]
public static extern void AmsiCloseSession([In] HAMSICONTEXT amsiContext, [In] HAMSISESSION amsiSession);
/// Initialize the AMSI API.
/// The name, version, or GUID string of the app calling the AMSI API.
/// A handle of type HAMSICONTEXT that must be passed to all subsequent calls to the AMSI API.
/// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
/// When the app is finished with the AMSI API it must call AmsiUninitialize.
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiinitialize HRESULT AmsiInitialize( [in] LPCWSTR appName, [out]
// HAMSICONTEXT *amsiContext );
[DllImport(Lib_Amsi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiInitialize")]
public static extern HRESULT AmsiInitialize([MarshalAs(UnmanagedType.LPWStr)] string appName, out SafeHAMSICONTEXT amsiContext);
///
/// Sends to the antimalware provider a notification of an arbitrary operation. The notification doesn't imply the request of an
/// antivirus scan. Rather, IAntimalwareProvider2::Notify is designed to provide a quick and lightweight mechanism to
/// communicate to the antimalware provider that an event has taken place. In general, the antimalware provider should process the
/// notification, and return to the caller as quickly as possible.
///
///
/// Type: _In_ HAMSICONTEXT
/// The handle (of type HAMSICONTEXT) that was initially received from AmsiInitialize.
///
///
/// Type: _In_reads_bytes_(length) PVOID
/// The buffer that contains the notification data.
///
///
/// Type: _In_ ULONG
/// The length, in bytes, of the data to be read from buffer.
///
///
/// Type: _In_opt_ LPCWSTR
/// The filename, URL, unique script ID, or similar of the content being scanned.
///
///
/// Type: _Out_ AMSI_RESULT*
/// The result of the scan.
/// You should use AmsiResultIsMalware to determine whether the content should be blocked.
///
/// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsinotifyoperation HRESULT AmsiNotifyOperation( HAMSICONTEXT
// amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, AMSI_RESULT *result );
[DllImport(Lib_Amsi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiNotifyOperation")]
public static extern HRESULT AmsiNotifyOperation([In] HAMSICONTEXT amsiContext, [In] IntPtr buffer, [In] uint length,
[Optional, MarshalAs(UnmanagedType.LPWStr)] string contentName, out AMSI_RESULT result);
/// Opens a session within which multiple scan requests can be correlated.
/// The handle of type HAMSICONTEXT that was initially received from AmsiInitialize.
///
/// A handle of type HAMSISESSION that must be passed to all subsequent calls to the AMSI API within the session.
///
/// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
/// When the app is finished with the session it must call AmsiCloseSession.
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiopensession HRESULT AmsiOpenSession( [in] HAMSICONTEXT
// amsiContext, [out] HAMSISESSION *amsiSession );
public static HRESULT AmsiOpenSession([In] HAMSICONTEXT amsiContext, out SafeHAMSISESSION amsiSession)
{
HRESULT hr = AmsiOpenSessionInternal(amsiContext, out HAMSISESSION h);
amsiSession = hr.Succeeded ? new SafeHAMSISESSION((IntPtr)h, true) : new SafeHAMSISESSION(IntPtr.Zero, false);
return hr;
}
/// Determines if the result of a scan indicates that the content should be blocked.
/// The AMSI_RESULT returned by AmsiScanBuffer or AmsiScanString.
/// None
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiresultismalware void AmsiResultIsMalware( [in] r );
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiResultIsMalware")]
public static bool AmsiResultIsMalware(AMSI_RESULT r) => r >= AMSI_RESULT.AMSI_RESULT_DETECTED;
/// Scans a buffer-full of content for malware.
/// The handle of type HAMSICONTEXT that was initially received from AmsiInitialize.
/// 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.
///
/// If multiple scan requests are to be correlated within a session, set session to the handle of type HAMSISESSION that was
/// initially received from AmsiOpenSession. Otherwise, set session to nullptr.
///
///
/// The result of the scan. See AMSI_RESULT.
/// An app should use AmsiResultIsMalware to determine whether the content should be blocked.
///
/// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanbuffer HRESULT AmsiScanBuffer( [in] HAMSICONTEXT
// amsiContext, [in] PVOID buffer, [in] ULONG length, [in] LPCWSTR contentName, [in, optional] HAMSISESSION amsiSession, [out]
// AMSI_RESULT *result );
[DllImport(Lib_Amsi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiScanBuffer")]
public static extern HRESULT AmsiScanBuffer([In] HAMSICONTEXT amsiContext, [In] IntPtr buffer, uint length,
[Optional, MarshalAs(UnmanagedType.LPWStr)] string contentName, [In, Optional] HAMSISESSION amsiSession, out AMSI_RESULT result);
/// Scans a string for malware.
/// The handle of type HAMSICONTEXT that was initially received from AmsiInitialize.
/// The string to be scanned.
/// The filename, URL, unique script ID, or similar of the content being scanned.
///
/// If multiple scan requests are to be correlated within a session, set session to the handle of type HAMSISESSION that was
/// initially received from AmsiOpenSession. Otherwise, set session to nullptr.
///
///
/// The result of the scan. See AMSI_RESULT.
/// An app should use AmsiResultIsMalware to determine whether the content should be blocked.
///
/// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanstring HRESULT AmsiScanString( [in] HAMSICONTEXT
// amsiContext, [in] LPCWSTR string, [in] LPCWSTR contentName, [in, optional] HAMSISESSION amsiSession, [out] AMSI_RESULT *result );
[DllImport(Lib_Amsi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiScanString")]
public static extern HRESULT AmsiScanString(HAMSICONTEXT amsiContext, [MarshalAs(UnmanagedType.LPWStr)] string str,
[Optional, MarshalAs(UnmanagedType.LPWStr)] string contentName, [In, Optional] HAMSISESSION amsiSession, out AMSI_RESULT result);
/// Remove the instance of the AMSI API that was originally opened by AmsiInitialize.
/// The handle of type HAMSICONTEXT that was initially received from AmsiInitialize.
/// None
// https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiuninitialize void AmsiUninitialize( [in] HAMSICONTEXT
// amsiContext );
[DllImport(Lib_Amsi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("amsi.h", MSDNShortId = "NF:amsi.AmsiUninitialize")]
public static extern void AmsiUninitialize(HAMSICONTEXT amsiContext);
[DllImport(Lib_Amsi, SetLastError = false, EntryPoint = "AmsiOpenSession")]
private static extern HRESULT AmsiOpenSessionInternal([In] HAMSICONTEXT amsiContext, out HAMSISESSION amsiSession);
/// Provides a handle to an AMSI context.
[StructLayout(LayoutKind.Sequential)]
public struct HAMSICONTEXT : IHandle
{
private readonly IntPtr handle;
/// Initializes a new instance of the struct.
/// An object that represents the pre-existing handle to use.
public HAMSICONTEXT(IntPtr preexistingHandle) => handle = preexistingHandle;
/// Returns an invalid handle by instantiating a object with .
public static HAMSICONTEXT NULL { get; } = default;
/// Gets a value indicating whether this instance is a null handle.
public bool IsNull => handle == IntPtr.Zero;
/// Performs an explicit conversion from to .
/// The handle.
/// The result of the conversion.
public static explicit operator IntPtr(HAMSICONTEXT h) => h.handle;
/// Performs an implicit conversion from to .
/// The pointer to a handle.
/// The result of the conversion.
public static implicit operator HAMSICONTEXT(IntPtr h) => new(h);
/// Implements the operator !=.
/// The first handle.
/// The second handle.
/// The result of the operator.
public static bool operator !=(HAMSICONTEXT h1, HAMSICONTEXT h2) => h1.handle != h2.handle;
/// Implements the operator ==.
/// The first handle.
/// The second handle.
/// The result of the operator.
public static bool operator ==(HAMSICONTEXT h1, HAMSICONTEXT h2) => h1.handle == h2.handle;
///
public override bool Equals(object obj) => (obj is IHandle h && handle == h.DangerousGetHandle()) || (obj is IntPtr p && handle == p);
///
public override int GetHashCode() => handle.GetHashCode();
///
public IntPtr DangerousGetHandle() => handle;
}
/// Provides a handle to an AMSI session.
[StructLayout(LayoutKind.Sequential)]
public struct HAMSISESSION : IHandle
{
private readonly IntPtr handle;
/// Initializes a new instance of the struct.
/// An object that represents the pre-existing handle to use.
public HAMSISESSION(IntPtr preexistingHandle) => handle = preexistingHandle;
/// Returns an invalid handle by instantiating a object with .
public static HAMSISESSION NULL { get; } = default;
/// Gets a value indicating whether this instance is a null handle.
public bool IsNull => handle == IntPtr.Zero;
/// Performs an explicit conversion from to .
/// The handle.
/// The result of the conversion.
public static explicit operator IntPtr(HAMSISESSION h) => h.handle;
/// Performs an implicit conversion from to .
/// The pointer to a handle.
/// The result of the conversion.
public static implicit operator HAMSISESSION(IntPtr h) => new(h);
/// Implements the operator !=.
/// The first handle.
/// The second handle.
/// The result of the operator.
public static bool operator !=(HAMSISESSION h1, HAMSISESSION h2) => h1.handle != h2.handle;
/// Implements the operator ==.
/// The first handle.
/// The second handle.
/// The result of the operator.
public static bool operator ==(HAMSISESSION h1, HAMSISESSION h2) => h1.handle == h2.handle;
///
public override bool Equals(object obj) => (obj is IHandle h && handle == h.DangerousGetHandle()) || (obj is IntPtr p && handle == p);
///
public override int GetHashCode() => handle.GetHashCode();
///
public IntPtr DangerousGetHandle() => handle;
}
/// Provides a for that is disposed using .
public class SafeHAMSICONTEXT : SafeHANDLE
{
/// Initializes a new instance of the class and assigns an existing handle.
/// An object that represents the pre-existing handle to use.
///
/// to reliably release the handle during the finalization phase; otherwise, (not recommended).
///
public SafeHAMSICONTEXT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
/// Initializes a new instance of the class.
private SafeHAMSICONTEXT() : base() { }
/// Performs an implicit conversion from to .
/// The safe handle instance.
/// The result of the conversion.
public static implicit operator HAMSICONTEXT(SafeHAMSICONTEXT h) => h.handle;
///
protected override bool InternalReleaseHandle() { AmsiUninitialize(handle); return true; }
}
/// Provides a for that is disposed using .
public class SafeHAMSISESSION : SafeHANDLE
{
private SafeHAMSICONTEXT ctx;
/// Initializes a new instance of the class and assigns an existing handle.
/// An object that represents the pre-existing handle to use.
///
/// to reliably release the handle during the finalization phase; otherwise, (not recommended).
///
public SafeHAMSISESSION(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
/// Initializes a new instance of the class.
/// The context.
public SafeHAMSISESSION(HAMSICONTEXT context) : base() => Open(Context = context);
/// Initializes a new instance of the class.
/// The name, version, or GUID string of the app calling the AMSI API.
public SafeHAMSISESSION(string appName) : base()
{
AmsiInitialize(appName, out SafeHAMSICONTEXT hc).ThrowIfFailed();
Open(ctx = hc);
}
/// Initializes a new instance of the class.
private SafeHAMSISESSION() : base() { }
/// Gets or sets the handle of type HAMSICONTEXT that was initially received from AmsiInitialize.
/// The context handle.
public HAMSICONTEXT Context { get => ctx; set => ctx = new SafeHAMSICONTEXT((IntPtr)value, false); }
/// Performs an implicit conversion from to .
/// The safe handle instance.
/// The result of the conversion.
public static implicit operator HAMSISESSION(SafeHAMSISESSION h) => h.handle;
///
protected override bool InternalReleaseHandle() { AmsiCloseSession(Context, handle); ctx?.Dispose(); return true; }
private void Open(HAMSICONTEXT context)
{
AmsiOpenSessionInternal(context, out HAMSISESSION h).ThrowIfFailed();
SetHandle((IntPtr)h);
}
}
}
}