Windows 来自 C# 的 Defender 防病毒扫描 [AccessViolation 异常]
Windows Defender Antivirus scan from C# [AccessViolation exception]
我们正在编写代码,使用 Windows Defender API 从 C# 中按需扫描文件。
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int WDStatus(out bool pfEnabled);
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpManagerOpen(uint dwReserved, out IntPtr phMpHandle);
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpScanStart(IntPtr hMpHandle, uint ScanType, uint dwScanOptions, IntPtr pScanResources, IntPtr pCallbackInfo, out IntPtr phScanHandle);
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpHandleClose(IntPtr hMpHandle);
private void DoDefenderScan_Click(object sender, EventArgs e)
{
try
{
bool pfEnabled;
int result = WDStatus(out pfEnabled); //Returns the defender status - It's working properly.
ErrorHandler.ThrowOnFailure(result, VSConstants.S_OK);
IntPtr phMpHandle;
uint dwReserved = 0;
IntPtr phScanHandle;
MpManagerOpen(dwReserved, out phMpHandle); //Opens Defender and returns the handle in phMpHandle.
tagMPRESOURCE_INFO mpResourceInfo = new tagMPRESOURCE_INFO();
mpResourceInfo.Path = "eicar.com";
mpResourceInfo.Scheme = "file";
mpResourceInfo.Class = IntPtr.Zero;
tagMPRESOURCE_INFO[] pResourceList = new tagMPRESOURCE_INFO[1];
pResourceList.SetValue(mpResourceInfo, 0);
tagMPSCAN_RESOURCES scanResource = new tagMPSCAN_RESOURCES();
scanResource.dwResourceCount = 1;
scanResource.pResourceList = pResourceList;
IntPtr resourcePointer = StructToPtr(scanResource);
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
MpHandleClose(phMpHandle);
MpHandleClose(phScanHandle);
Marshal.FreeHGlobal(resourcePointer);
}
catch (Exception)
{ }
}
这里定义了结构。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPSCAN_RESOURCES
{
public uint dwResourceCount;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
public tagMPRESOURCE_INFO[] pResourceList;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPRESOURCE_INFO
{
[MarshalAs(UnmanagedType.LPWStr)]
public String Scheme;
[MarshalAs(UnmanagedType.LPWStr)]
public String Path;
public IntPtr Class;
}
public class MPRESOURCE_CLASS
{
public uint Value;
}
private static IntPtr StructToPtr(object obj)
{
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
代码是根据
上提供的文档编写的
https://msdn.microsoft.com/en-us/library/vs/alm/dn920144(v=vs.85).aspx
我们遇到了这个异常
试图读取或写入受保护的内存。这通常表示其他内存已损坏。
在
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
可能是什么问题? struct格式是否正确?
P.S - No information about MPRESOURCE_CLASS is available in msdn.
我不确定这行代码是否正确。
mpResourceInfo.Class = IntPtr.Zero;
更新:
快速扫描可以正常使用此代码:
result = MpScanStart(phMpHandle, 1, 0, IntPtr.Zero, IntPtr.Zero, out phScanHandle);
Defender 在事件查看器中登录[应用程序和服务日志-Microsoft-Windows-Windows Defender/Operational] 为
Windows Defender scan has started.
Scan ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Scan Type:AntiSpyware
Scan Parameters:Quick Scan
我一直在寻找问题,我认为这是可能的原因之一:
"You often see differences between debug and release builds because
debug builds contain extra metadata to assist in debugging."
你还应该查看 MSDN 杂志this answer to "Is it possible to catch an access violation exception in .NET?" and the further details that are explained in the article Handling Corrupted State Exceptions
...
因此,根据我尝试的答案和文章:
第 1 次仔细检查所有非托管代码的签名和 COM interop thunk,以验证它们是否正确。
2nd 设置 Visual Studio 调试器绕过此异常:
工具菜单 -> 选项 -> 调试 -> 常规 -> 取消选中此选项 "Suppress JIT optimization on module load"
第三次 Try-Catch 异常
(注意:如果您使用的是 .Net 4,则在 App.config 中,在标签修改运行时以包含 legacyCorruptedStateExceptionsPolicy enabled="true"like:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
)
此外,here,我发现一些.net framework 版本(在其中一个答案的评论中最新评论指向 4.6.1)有一个与此异常和解决方案相关的错误,过去,一直在升级框架。
另外,在我读过的其中一个答案中:
Hi There are two possible reasons.
1.We have un-managed code and we are calling it from managed code. that is preventing to run this code. try running these commands and
restart your pc
cmd: netsh winsock reset
open cmd.exe and run command "netsh winsock reset catalog"
2.Anti-virus is considering un-managed code as harmful and restricting to run this code disable anti-virus and then check
我想知道其中一些方法是否可以帮助您解决问题。
我真的希望这对您有所帮助。
韩国,
胡安
您可以使用 Antimalware Scan Interface 检查文件是否存在恶意软件。
The Antimalware Scan Interface (AMSI) is a generic interface standard that allows applications and services to integrate with any antimalware product present on a machine. It provides enhanced malware protection for users and their data, applications, and workloads.
从 Windows 10 开始可用。
我无法确定这里的问题。所以我最终得到了 Antimalware Scan Interface (AMSI) 从 Windows 10.
开始可用
我已经编写了示例 C# 代码 here。
我发现的一件事是 AMSI 要求打开 Windows defender/any 防病毒软件以验证传递给 API 的文件。但是通过 MpClient.dll
触发扫描将触发防御者扫描,即使关闭了防御者。
还要确保您的项目面向 x64
平台。
public enum AMSI_RESULT
{
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_DETECTED = 32768
}
[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);
//This method apparently exists on MSDN but not in AMSI.dll (version 4.9.10586.0)
[DllImport("Amsi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern bool AmsiResultIsMalware(AMSI_RESULT result);
private void CallAntimalwareScanInterface()
{
IntPtr amsiContext;
IntPtr session;
AMSI_RESULT result = 0;
int returnValue;
returnValue = AmsiInitialize("VirusScanAPI", out amsiContext); //appName is the name of the application consuming the Amsi.dll. Here my project name is VirusScanAPI.
returnValue = AmsiOpenSession(amsiContext, out session);
returnValue = AmsiScanString(amsiContext, @"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*", "EICAR", session, out result); //I've used EICAR test string.
AmsiCloseSession(amsiContext, session);
AmsiUninitialize(amsiContext);
}
我们正在编写代码,使用 Windows Defender API 从 C# 中按需扫描文件。
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int WDStatus(out bool pfEnabled);
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpManagerOpen(uint dwReserved, out IntPtr phMpHandle);
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpScanStart(IntPtr hMpHandle, uint ScanType, uint dwScanOptions, IntPtr pScanResources, IntPtr pCallbackInfo, out IntPtr phScanHandle);
[DllImport(@"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpHandleClose(IntPtr hMpHandle);
private void DoDefenderScan_Click(object sender, EventArgs e)
{
try
{
bool pfEnabled;
int result = WDStatus(out pfEnabled); //Returns the defender status - It's working properly.
ErrorHandler.ThrowOnFailure(result, VSConstants.S_OK);
IntPtr phMpHandle;
uint dwReserved = 0;
IntPtr phScanHandle;
MpManagerOpen(dwReserved, out phMpHandle); //Opens Defender and returns the handle in phMpHandle.
tagMPRESOURCE_INFO mpResourceInfo = new tagMPRESOURCE_INFO();
mpResourceInfo.Path = "eicar.com";
mpResourceInfo.Scheme = "file";
mpResourceInfo.Class = IntPtr.Zero;
tagMPRESOURCE_INFO[] pResourceList = new tagMPRESOURCE_INFO[1];
pResourceList.SetValue(mpResourceInfo, 0);
tagMPSCAN_RESOURCES scanResource = new tagMPSCAN_RESOURCES();
scanResource.dwResourceCount = 1;
scanResource.pResourceList = pResourceList;
IntPtr resourcePointer = StructToPtr(scanResource);
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
MpHandleClose(phMpHandle);
MpHandleClose(phScanHandle);
Marshal.FreeHGlobal(resourcePointer);
}
catch (Exception)
{ }
}
这里定义了结构。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPSCAN_RESOURCES
{
public uint dwResourceCount;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
public tagMPRESOURCE_INFO[] pResourceList;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPRESOURCE_INFO
{
[MarshalAs(UnmanagedType.LPWStr)]
public String Scheme;
[MarshalAs(UnmanagedType.LPWStr)]
public String Path;
public IntPtr Class;
}
public class MPRESOURCE_CLASS
{
public uint Value;
}
private static IntPtr StructToPtr(object obj)
{
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
代码是根据
上提供的文档编写的https://msdn.microsoft.com/en-us/library/vs/alm/dn920144(v=vs.85).aspx
我们遇到了这个异常
试图读取或写入受保护的内存。这通常表示其他内存已损坏。
在
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
可能是什么问题? struct格式是否正确?
P.S - No information about MPRESOURCE_CLASS is available in msdn.
我不确定这行代码是否正确。
mpResourceInfo.Class = IntPtr.Zero;
更新:
快速扫描可以正常使用此代码:
result = MpScanStart(phMpHandle, 1, 0, IntPtr.Zero, IntPtr.Zero, out phScanHandle);
Defender 在事件查看器中登录[应用程序和服务日志-Microsoft-Windows-Windows Defender/Operational] 为
Windows Defender scan has started.
Scan ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Scan Type:AntiSpyware
Scan Parameters:Quick Scan
我一直在寻找问题,我认为这是可能的原因之一:
"You often see differences between debug and release builds because debug builds contain extra metadata to assist in debugging."
你还应该查看 MSDN 杂志this answer to "Is it possible to catch an access violation exception in .NET?" and the further details that are explained in the article Handling Corrupted State Exceptions
...
因此,根据我尝试的答案和文章:
第 1 次仔细检查所有非托管代码的签名和 COM interop thunk,以验证它们是否正确。
2nd 设置 Visual Studio 调试器绕过此异常: 工具菜单 -> 选项 -> 调试 -> 常规 -> 取消选中此选项 "Suppress JIT optimization on module load"
第三次 Try-Catch 异常
(注意:如果您使用的是 .Net 4,则在 App.config 中,在标签修改运行时以包含 legacyCorruptedStateExceptionsPolicy enabled="true"like:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
)
此外,here,我发现一些.net framework 版本(在其中一个答案的评论中最新评论指向 4.6.1)有一个与此异常和解决方案相关的错误,过去,一直在升级框架。 另外,在我读过的其中一个答案中:
Hi There are two possible reasons.
1.We have un-managed code and we are calling it from managed code. that is preventing to run this code. try running these commands and restart your pc
cmd: netsh winsock reset
open cmd.exe and run command "netsh winsock reset catalog" 2.Anti-virus is considering un-managed code as harmful and restricting to run this code disable anti-virus and then check
我想知道其中一些方法是否可以帮助您解决问题。
我真的希望这对您有所帮助。
韩国,
胡安
您可以使用 Antimalware Scan Interface 检查文件是否存在恶意软件。
The Antimalware Scan Interface (AMSI) is a generic interface standard that allows applications and services to integrate with any antimalware product present on a machine. It provides enhanced malware protection for users and their data, applications, and workloads.
从 Windows 10 开始可用。
我无法确定这里的问题。所以我最终得到了 Antimalware Scan Interface (AMSI) 从 Windows 10.
开始可用我已经编写了示例 C# 代码 here。
我发现的一件事是 AMSI 要求打开 Windows defender/any 防病毒软件以验证传递给 API 的文件。但是通过 MpClient.dll
触发扫描将触发防御者扫描,即使关闭了防御者。
还要确保您的项目面向 x64
平台。
public enum AMSI_RESULT
{
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_DETECTED = 32768
}
[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);
//This method apparently exists on MSDN but not in AMSI.dll (version 4.9.10586.0)
[DllImport("Amsi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern bool AmsiResultIsMalware(AMSI_RESULT result);
private void CallAntimalwareScanInterface()
{
IntPtr amsiContext;
IntPtr session;
AMSI_RESULT result = 0;
int returnValue;
returnValue = AmsiInitialize("VirusScanAPI", out amsiContext); //appName is the name of the application consuming the Amsi.dll. Here my project name is VirusScanAPI.
returnValue = AmsiOpenSession(amsiContext, out session);
returnValue = AmsiScanString(amsiContext, @"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*", "EICAR", session, out result); //I've used EICAR test string.
AmsiCloseSession(amsiContext, session);
AmsiUninitialize(amsiContext);
}