2

The AMSI has function AmsiScanBufferfor scanning byte array. But in that case the content of the whole must be read to memory which may be impossible for large files. The AmsiScanBuffer function has parameter amsiSession which is intended to be used for correlation of multiple scan requests. As far as I understand it should work to read one file by chunks and call AmsiScanBuffer for those chunks with the same session and context. But it does not:

public enum AMSI_RESULT
{
    AMSI_RESULT_CLEAN = 0,
    AMSI_RESULT_NOT_DETECTED = 1,
    AMSI_RESULT_DETECTED = 32768
}

public static class NativeMethods
{
    [DllImport("Amsi.dll", EntryPoint = "AmsiInitialize", CallingConvention = CallingConvention.StdCall)]
    public static extern int AmsiInitialize([MarshalAs(UnmanagedType.LPWStr)]string appName, out IntPtr amsiContext);

    [DllImport("Amsi.dll", EntryPoint = "AmsiUninitialize", CallingConvention = CallingConvention.StdCall)]
    public static extern void AmsiUninitialize(IntPtr amsiContext);

    [DllImport("Amsi.dll", EntryPoint = "AmsiOpenSession", CallingConvention = CallingConvention.StdCall)]
    public static extern int AmsiOpenSession(IntPtr amsiContext, out IntPtr session);

    [DllImport("Amsi.dll", EntryPoint = "AmsiCloseSession", CallingConvention = CallingConvention.StdCall)]
    public static extern void AmsiCloseSession(IntPtr amsiContext, IntPtr session);

    [DllImport("Amsi.dll", EntryPoint = "AmsiScanString", CallingConvention = CallingConvention.StdCall)]
    public static extern int AmsiScanString(IntPtr amsiContext, [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)]string @string, [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)]string contentName, IntPtr session, out AMSI_RESULT result);
    [DllImport("Amsi.dll", EntryPoint = "AmsiScanBuffer", CallingConvention = CallingConvention.StdCall)]
    public static extern int AmsiScanBuffer(IntPtr amsiContext, [In] [MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint length, [In()] [MarshalAs(UnmanagedType.LPWStr)] string contentName, IntPtr session, out AMSI_RESULT result);
}

class Program
{
    static void Main(string[] args)
    {
        IntPtr amsiContext;
        IntPtr session;
        AMSI_RESULT result = 0;
        int returnValue;

        returnValue = NativeMethods.AmsiInitialize("Win10AMSIScanner", out amsiContext);
        returnValue = NativeMethods.AmsiOpenSession(amsiContext, out session);

        Scan(amsiContext, session, ref result);

        Console.WriteLine(result);

        NativeMethods.AmsiCloseSession(amsiContext, session);
        NativeMethods.AmsiUninitialize(amsiContext);

        Console.ReadLine();
    }

    private static void Scan(IntPtr amsiContext, IntPtr session, ref AMSI_RESULT result)
    {
        const int bufferLength = 10;
        using (var fs = new MemoryStream(Encoding.UTF8.GetBytes(@"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*")))
        {
            long alreadyRead = 0;
            fs.Seek(0, SeekOrigin.Begin);

            long toReadCount = alreadyRead + bufferLength <= fs.Length ? bufferLength : fs.Length - alreadyRead;
            while (toReadCount > 0)
            {
                var content = new byte[toReadCount];
                fs.Read(content, 0, (int)toReadCount);

                NativeMethods.AmsiScanBuffer(amsiContext, content, (uint)toReadCount, "eicar-test-file", session, out result);

                alreadyRead += toReadCount;
                toReadCount = alreadyRead + bufferLength <= fs.Length ? bufferLength : fs.Length - alreadyRead;
            }
        }
    }
}

Do you have any ideas why it does not work or any suggestions on how to achieve the goal?

1 Answers1

4

Because you didn't specify what errors you get or what isn't working I can't help much.

What I can tell is that I have a working implementation of scanning files with AMSI in C++. So, yes, it is working. It even scans into ZIP files (depending on the virus scanner).

There is a lot of things that can fail. As example: You need to have the real-time protection enabled in Windows Defender Security Center (if you use Windows Defender). Otherwise, calling AmsiScanBuffer will return error code 0x80070015 with "The device is not ready." Other virus scanners may have this kind of option too.

Your code is missing checks of the return values. From the information present, AmsiInitialize could fail.

gyun
  • 71
  • 4
  • You save my day... real-time protection enabled in Windows Defender Security Center was Off!!! And i got HRESULT 80070015 – Zvi Redler Oct 02 '22 at 10:33