【问题标题】:Windows Defender Antivirus scan from C# [AccessViolation exception]从 C# [AccessViolation 异常] 进行 Windows Defender 防病毒扫描
【发布时间】:2017-04-14 19:18:58
【问题描述】:

我们正在编写代码以使用 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 - 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}
扫描类型:反间谍软件
扫描参数:快速扫描

【问题讨论】:

  • 神圣的硬编码路径,蝙蝠侠!请不要这样做。如果我的引导驱动器不是驱动器 C 怎么办?如果 Program Files 中没有安装 Windows Defender 怎么办?
  • @CodyGray - 这是一个 POC。但感谢您指出。
  • 我看到的第一个错误是 MPSCAN_RESOURCES.pResourceList 成员声明。它是指向数组的指针,而不是 UnmanagedType.ByValArray。您必须将其声明为 IntPtr 并自己编组数组。使用 Pack=1 也是非常错误的。可能有更多的错误,这不是一个简单的api。使用 C++/CLI 来做这件事,你会领先一步,至少你可以依赖 mpclient.h 头文件。
  • @HansPassant 谢谢!我会调查的。
  • 最后我放弃了。我们计划使用反恶意软件扫描接口 (AMSI)。但是 AMSI 支持仅在 Windows 10 中可用。我编写了一个示例代码,以防有人需要。 midhunlalg.blogspot.in/2016/12/…

标签: c# windows dllimport antivirus windows-defender


【解决方案1】:

我无法确定这里的问题。所以我最终从 Windows 10 开始获得了 Antimalware Scan Interface (AMSI)。

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

【讨论】:

  • 为什么要对这篇文章投反对票。小心告诉,为什么它被否决了?我想在这里告诉大家,AMSI 是一种成功的与防守方沟通的替代方式。
  • @EricHirst - 情况正好相反。我将此作为评论 stackoverflow.com/questions/40888849/… 发布到我的问题本身。伊万复制了它并发布为答案:)
  • @mlg 我没有复制你的答案,因为我实际上没有注意到它。似乎我们正在并行调查相同的问题并找到相同的解决方案。无论如何,我会支持你的回应并奖励你。添加概念验证代码以使用您已经写到答案中的 AMSI 可能是有意义的。
  • @IvanZhakov 对此我很抱歉。我以为是另一种方式。我的错!。哦,我现在无法更新评论:(
  • 您没有在代码中使用 AmsiScanBuffer,但如果您这样做了,该声明将不起作用。 length 参数需要声明为uint,而不是ulong。在 Windows 上的 C 中,ULONG 是 4 个字节,但 C# ulong 是 8 个字节。这是working example of AmsiScanBuffer
【解决方案2】:

我一直在寻找问题,我认为这是可能的原因之一:

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

这里: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 优化”

第三次尝试捕获异常

(注意:如果您使用的是 .Net 4,那么在 App.config 中,在标签中修改运行时以包含 legacyCorruptedStateExceptionsPolicy enabled="true"like:

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

)

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

您好,有两个可能的原因。

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

cmd: netsh winsock 重置

打开 cmd.exe 并运行命令“netsh winsock 重置目录” 2.Anti-virus将非托管代码视为有害并限制运行此代码禁用杀毒然后检查

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

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

韩国,

胡安

【讨论】:

  • 谢谢。我会看到的。
【解决方案3】:

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

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

从 Windows 10 开始提供。

【讨论】:

猜你喜欢
  • 2017-09-20
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 2016-07-10
  • 1970-01-01
  • 2010-11-29
相关资源
最近更新 更多