进程挂起从托管代码调用 AmsiScanBuffer
Process hangs pinvoking AmsiScanBuffer from managed Code
我正在尝试从托管代码(特别是 C#)使用 Windows 反恶意软件服务接口的 AmsiScanBuffer
功能。尝试调用该方法时,只要提供非零缓冲区长度,程序就会挂起调用。如果提供的缓冲区长度为 0 零,则方法 returns 会立即与 HResult E_INVALIDARG 一起使用。 AMSI 公开的其他方法按预期工作,所以我希望我相信我的 dllimport 此功能接近但可能不完全正确。除了此处表示的数组复制方法外,我还尝试固定数组并且行为相同。
C原型
HRESULT WINAPI AmsiScanBuffer(
_In_ HAMSICONTEXT amsiContext,
_In_ PVOID buffer,
_In_ ULONG length,
_In_ LPCWSTR contentName,
_In_opt_ HAMSISESSION session,
_Out_ AMSI_RESULT *result
);
托管代码
[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);
}
主要问题是 AmsiScanBuffer
的 length
参数。 C/C++ on Windows 中的 ULONG
是 32 位,而 C# 中的 ulong
是 64 位。所以参数需要声明为uint
。我原以为在调试器下 运行 时会出现 "unbalanced stack" 错误,即使您传递的缓冲区长度为零也是如此。您也可以将 buffer
声明为 byte[]
,然后直接传入 bytes
。
为了进一步简化,您可以省略 CallingConvention
,因为 StdCall
是默认值。我还将它更改为使用确切的函数名称,因此不必在 DllImport
中指定它。一般来说,当我直接从 C# 使用 C 库时,我喜欢保留原始函数名称,例如AmsiScanBuffer
而不是将其更改为 Amsi.ScanBuffer
。这使得当有人在处理代码时更容易查找文档,尽管这当然是一个品味问题。
这是一个作为控制台应用程序的工作版本。
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace AmsiTest {
class Program {
static void Main( string[] args ) {
var virus = Encoding.UTF8.GetBytes(
"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
);
IntPtr context;
var hrInit = AmsiInitialize( "AmsiTest", out context );
if( hrInit != 0 ) {
Console.WriteLine( $"AmsiInitialize failed, HRESULT {hrInit:X8}" );
return;
}
AMSI_RESULT result;
var hrScan = AmsiScanBuffer(
context, virus, (uint)virus.Length,
"EICAR Test File", IntPtr.Zero, out result
);
AmsiUninitialize( context );
if( hrScan != 0 ) {
Console.WriteLine( $"AmsiScanBuffer failed, HRESULT {hrScan:X8}" );
} else if( result == AMSI_RESULT.AMSI_RESULT_DETECTED ) {
Console.WriteLine( "Detected EICAR test" );
} else {
Console.WriteLine( $"Failed to detect EICAR test, result {result:X8}" );
}
}
public enum AMSI_RESULT {
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_BLOCKED_BY_ADMIN_START = 16384,
AMSI_RESULT_BLOCKED_BY_ADMIN_END = 20479,
AMSI_RESULT_DETECTED = 32768
}
[DllImport( "Amsi.dll" )]
public static extern uint AmsiInitialize(
string appName,
out IntPtr amsiContext
);
[DllImport( "Amsi.dll" )]
public static extern uint AmsiScanBuffer(
IntPtr amsiContext,
byte[] buffer,
uint length,
string contentName,
IntPtr session,
out AMSI_RESULT result
);
[DllImport( "Amsi.dll" )]
public static extern void AmsiUninitialize(
IntPtr amsiContext
);
}
}
我正在尝试从托管代码(特别是 C#)使用 Windows 反恶意软件服务接口的 AmsiScanBuffer
功能。尝试调用该方法时,只要提供非零缓冲区长度,程序就会挂起调用。如果提供的缓冲区长度为 0 零,则方法 returns 会立即与 HResult E_INVALIDARG 一起使用。 AMSI 公开的其他方法按预期工作,所以我希望我相信我的 dllimport 此功能接近但可能不完全正确。除了此处表示的数组复制方法外,我还尝试固定数组并且行为相同。
C原型
HRESULT WINAPI AmsiScanBuffer(
_In_ HAMSICONTEXT amsiContext,
_In_ PVOID buffer,
_In_ ULONG length,
_In_ LPCWSTR contentName,
_In_opt_ HAMSISESSION session,
_Out_ AMSI_RESULT *result
);
托管代码
[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);
}
主要问题是 AmsiScanBuffer
的 length
参数。 C/C++ on Windows 中的 ULONG
是 32 位,而 C# 中的 ulong
是 64 位。所以参数需要声明为uint
。我原以为在调试器下 运行 时会出现 "unbalanced stack" 错误,即使您传递的缓冲区长度为零也是如此。您也可以将 buffer
声明为 byte[]
,然后直接传入 bytes
。
为了进一步简化,您可以省略 CallingConvention
,因为 StdCall
是默认值。我还将它更改为使用确切的函数名称,因此不必在 DllImport
中指定它。一般来说,当我直接从 C# 使用 C 库时,我喜欢保留原始函数名称,例如AmsiScanBuffer
而不是将其更改为 Amsi.ScanBuffer
。这使得当有人在处理代码时更容易查找文档,尽管这当然是一个品味问题。
这是一个作为控制台应用程序的工作版本。
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace AmsiTest {
class Program {
static void Main( string[] args ) {
var virus = Encoding.UTF8.GetBytes(
"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
);
IntPtr context;
var hrInit = AmsiInitialize( "AmsiTest", out context );
if( hrInit != 0 ) {
Console.WriteLine( $"AmsiInitialize failed, HRESULT {hrInit:X8}" );
return;
}
AMSI_RESULT result;
var hrScan = AmsiScanBuffer(
context, virus, (uint)virus.Length,
"EICAR Test File", IntPtr.Zero, out result
);
AmsiUninitialize( context );
if( hrScan != 0 ) {
Console.WriteLine( $"AmsiScanBuffer failed, HRESULT {hrScan:X8}" );
} else if( result == AMSI_RESULT.AMSI_RESULT_DETECTED ) {
Console.WriteLine( "Detected EICAR test" );
} else {
Console.WriteLine( $"Failed to detect EICAR test, result {result:X8}" );
}
}
public enum AMSI_RESULT {
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_BLOCKED_BY_ADMIN_START = 16384,
AMSI_RESULT_BLOCKED_BY_ADMIN_END = 20479,
AMSI_RESULT_DETECTED = 32768
}
[DllImport( "Amsi.dll" )]
public static extern uint AmsiInitialize(
string appName,
out IntPtr amsiContext
);
[DllImport( "Amsi.dll" )]
public static extern uint AmsiScanBuffer(
IntPtr amsiContext,
byte[] buffer,
uint length,
string contentName,
IntPtr session,
out AMSI_RESULT result
);
[DllImport( "Amsi.dll" )]
public static extern void AmsiUninitialize(
IntPtr amsiContext
);
}
}