I am attempting to use the AmsiScanBuffer
function of the Windows Anti-Malware Service Interface from managed code, specifically C#. When attempting to call the method the program hangs on the call anytime a non-zero buffer length is provided. If a buffer length of 0 zero is provided then the method returns immediately with the HResult E_INVALIDARG. The other methods exposed by AMSI work as expected so I expect the I believe my dllimport for this function to be close but probably not completely correct. Besides the array copy approach represented here I have tried pinning the array and the behavior is identical.
C prototype
HRESULT WINAPI AmsiScanBuffer(
_In_ HAMSICONTEXT amsiContext,
_In_ PVOID buffer,
_In_ ULONG length,
_In_ LPCWSTR contentName,
_In_opt_ HAMSISESSION session,
_Out_ AMSI_RESULT *result
);
Managed Code
[DllImport("Amsi.dll", EntryPoint = "AmsiScanBuffer", CallingConvention = CallingConvention.StdCall)]
public static extern int ScanBuffer(IntPtr amsiContext, IntPtr ptr, ulong length, string contentName, IntPtr session, out int result);
var virus = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
var bytes = Encoding.UTF8.GetBytes(virus);
int sizet = Marshal.SizeOf(typeof(byte)) * bytes.Length;
var ptr = Marshal.AllocHGlobal(sizet);
try
{
Marshal.Copy(bytes, 0, ptr, bytes.Length);
int hr = Amsi.ScanBuffer(context, ptr, (ulong)sizet, "Unknown Data", session, out result);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
The main problem is the
length
parameter toAmsiScanBuffer
. AULONG
in C/C++ on Windows is 32 bits, while aulong
in C# is 64 bits. So the parameter needs to be declared as auint
. I would have expected you'd get an "unbalanced stack" error when running under the debugger even if you passed a buffer length of zero. You can also declarebuffer
as abyte[]
and then just pass in thebytes
directly.For further simplification, you can omit the
CallingConvention
sinceStdCall
is the default. I also changed it to use the exact function name so it isn't necessary to specify it in theDllImport
. In general, when I'm working with C libraries directly from C# I like to keep the original function names, e.g.AmsiScanBuffer
instead of changing it toAmsi.ScanBuffer
. This makes it easier to look up docs when somebody is working on the code, although this is of course a matter of taste.Here's a working version as a console application.