Windows Defender防病毒软件从C#扫描[AccessViolation exception]

时间:2016-11-30 12:51:07

标签: c# windows dllimport antivirus windows-defender

我们正在编写一个代码,使用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**.

可能是什么问题?结构的格式是否正确?

  

P.S - msdn中没有关于MPRESOURCE_CLASS的信息。

我不确定这行代码是否正确。

 mpResourceInfo.Class = IntPtr.Zero;

更新

使用此代码快速扫描工作正常:

result = MpScanStart(phMpHandle, 1, 0, IntPtr.Zero, IntPtr.Zero, out phScanHandle);

Defender在事件查看器[应用程序和服务日志 - Microsoft-Windows-Windows Defender / Operational]中登录为

  

Windows Defender扫描已开始   扫描件ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
  扫描类型:AntiSpyware
  扫描参数:快速扫描

3 个答案:

答案 0 :(得分:11)

我无法在这里找出问题所在。所以我最终从Windows 10开始提供Antimalware Scan Interface(AMSI)。

我写了一个示例C#代码here 我发现的一件事是AMSI需要打开Windows defender /任何防病毒软件来验证传递给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, ulong 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);
}

答案 1 :(得分:3)

我一直在搜索问题,我把它读作可能的原因之一:

  

“您经常会看到调试和发布版本之间存在差异,因为   debug构建包含额外的元数据以帮助调试。“

此处:https://social.msdn.microsoft.com/Forums/vstudio/en-US/4f48c152-68cd-45ec-a11e-baa7de7f79c3/attempted-to-read-or-write-protected-memory?forum=csharpgeneral

此外,您应该检查this answer“是否可以在.NET中捕获访问冲突异常?”以及MSDN杂志中文章Handling Corrupted State Exceptions中解释的更多细节 ...

所以,根据那些答案和文章我会尝试:

首先仔细检查所有非托管代码的签名和COM互操作thunk,以验证它们是否正确。

2nd Set Visual Studio Debugger绕过此异常: 工具菜单 - >选项 - >调试 - >一般 - >取消选中此选项“抑制模块加载时的JIT优化”

3rd Try-Catch the exception

(注意:如果您在App.config中使用.Net 4,则在标记修改运行时中包含legacyCorruptedStateExceptionsPolicy enabled =“true”,如:

<runtime>
    <legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>

另外,here,我发现一些.net框架版本(最新评论指向答案评论之一中的4.6.1)有一个与此异常和解决方案相关的错误,在过去,一直在升级框架。 另外,在我读过的其中一个答案中:

  

您好有两个可能的原因。

     

1.我们有非托管代码,我们从托管代码调用它。这阻止了运行此代码。尝试运行这些命令和   重启你的电脑

     

cmd:netsh winsock reset

     

打开cmd.exe并运行命令“netsh winsock reset catalog”   2.Anti-virus正在考虑将非托管代码视为有害并且限制运行此代码禁用防病毒然后检查

我想知道其中一些方法是否可以帮助您解决问题。

我真的希望这会有所帮助。

KR,

答案 2 :(得分:2)

您可以使用Antimalware Scan Interface检查文件是否存在恶意软件。

  

反恶意软件扫描接口(AMSI)是一种通用接口标准,允许应用程序和服务与计算机上存在的任何反恶意软件产品集成。它为用户及其数据,应用程序和工作负载提供增强的恶意软件防护。

从Windows 10开始提供。