The AMSI has function AmsiScanBuffer
for 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?