简体   繁体   English

Windows Defender Antivirus 扫描来自 C# [AccessViolation 异常]

[英]Windows Defender Antivirus scan from C# [AccessViolation exception]

We are writing a code to do on-demand scan of a file from C# using Windows Defender APIs.我们正在编写代码,使用 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)
            { }
        }

And the structure is defined here.结构定义在这里。

    [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;
    }

The code is written based on the documentation available at代码是根据可用的文档编写的

https://msdn.microsoft.com/en-us/library/vs/alm/dn920144(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/vs/alm/dn920144(v=vs.85).aspx

We are getting this exception我们得到这个例外

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.试图读取或写入受保护的 memory。这通常表明其他 memory 已损坏。

at

result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.

What could be the problem?可能是什么问题呢? Is the format of struct is correct? struct 的格式是否正确?

PS - No information about MPRESOURCE_CLASS is available in msdn. PS - msdn 中没有关于 MPRESOURCE_CLASS 的信息。

I'm not sure, whether this line of code is correct.我不确定这行代码是否正确。

 mpResourceInfo.Class = IntPtr.Zero;

Update:更新:

Quick scan is working fine with this code:快速扫描可以正常使用此代码:

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

Defender logs in the event viewer [ Applications and Services Logs-Microsoft-Windows-Windows Defender/Operational ] as Defender 登录事件查看器 [ Applications and Services Logs-Microsoft-Windows-Windows Defender/Operational ] 作为

Windows Defender scan has started. Windows Defender 扫描已启动。
Scan ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}扫描 ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Scan Type:AntiSpyware扫描类型:反间谍软件
Scan Parameters:Quick Scan扫描参数:快速扫描

I couldn't identify the problem here.我无法在这里确定问题。 So I ended up with Antimalware Scan Interface (AMSI) available starting from Windows 10.所以我最终得到了从 Windows 10 开始可用的反恶意软件扫描接口(AMSI)。

I have written a sample C# code here .在这里编写了一个示例 C# 代码。
One thing I found is AMSI requires Windows defender/any antivirus to be turned on to verify the file passed to API.我发现的一件事是 AMSI 需要打开 Windows Defender/任何防病毒软件来验证传递给 API 的文件。 But triggering a scan through MpClient.dll will trigger a defender scan even if defender is turned off.但是通过MpClient.dll触发扫描将触发防御者扫描,即使防御者已关闭。

Also ensure your project targets x64 platform.还要确保您的项目面向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);
}

I've been searching about problem and I've read this as one of the possible causes:我一直在寻找问题,并将其视为可能的原因之一:

"You often see differences between debug and release builds because debug builds contain extra metadata to assist in debugging." “您经常会看到调试版本和发布版本之间的差异,因为调试版本包含额外的元数据来帮助调试。”

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

Also you should check this answer to "Is it possible to catch an access violation exception in .NET?"您还应该查看“是否可以在 .NET 中捕获访问冲突异常?”的答案 and the further details that are explained in the article Handling Corrupted State Exceptions in MSDN magazine以及在 MSDN 杂志中处理损坏状态异常一文中解释的更多详细信息
... ...

So, according to that answers and articles I'd try:因此,根据这些答案和文章,我会尝试:

1st Double check signatures and COM interop thunks for all unmanaged code to verify that they're correct.第一次仔细检查所有非托管代码的签名和 COM 互操作 thunk,以验证它们是否正确。

2nd Set Visual Studio Debugger to bypass this exception: Tools menu ->Options -> Debugging -> General -> Uncheck this option "Suppress JIT optimization on module load" 2nd 设置 Visual Studio Debugger 以绕过此异常:工具菜单 -> 选项 -> 调试 -> 常规 -> 取消选中此选项“在模块加载时抑制 JIT 优化”

3rd Try-Catch the exception第三次尝试捕获异常

(note: if you are using .Net 4 then in App.config, within the tag modify runtime to include legacyCorruptedStateExceptionsPolicy enabled="true"like: (注意:如果您使用 .Net 4,则在 App.config 中,在标记中修改运行时以包含 legacyCorruptedStateExceptionsPolicy enabled="true" ,例如:

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

) )

In addition, here , I've found that some .net framework versions (latest comment point to 4.6.1 in one of the answer's comments) has a bug related with this exception and the solution, in the past, has been upgrading the framework.另外, 在这里,我发现一些 .net 框架版本(在一个答案的评论中最新评论指向 4.6.1)有一个与此异常相关的错误,并且过去的解决方案一直在升级框架. Also, in the one of that answers I've read:另外,在我读过的其中一个答案中:

Hi There are two possible reasons.您好 有两个可能的原因。

1.We have un-managed code and we are calling it from managed code. 1.我们有非托管代码,我们从托管代码中调用它。 that is preventing to run this code.这是阻止运行此代码。 try running these commands and restart your pc尝试运行这些命令并重新启动您的电脑

cmd: netsh winsock reset cmd:netsh winsock 重置

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打开 cmd.exe 并运行命令“netsh winsock reset catalog” 2.Anti-virus 将非托管代码视为有害并限制运行此代码禁用防病毒然后检查

I'd like to know if some of these approaches helps you to solve your issue.我想知道其中一些方法是否可以帮助您解决问题。

I really hope this helps.我真的希望这会有所帮助。

KR,韩国,

Juan胡安

You may use Antimalware Scan Interface to check file for malware.您可以使用反恶意软件扫描界面来检查文件中是否存在恶意软件。

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.反恶意软件扫描接口 (AMSI) 是一种通用接口标准,允许应用程序和服务与机器上存在的任何反恶意软件产品集成。 It provides enhanced malware protection for users and their data, applications, and workloads.它为用户及其数据、应用程序和工作负载提供增强的恶意软件保护。

It's available starting from Windows 10.它从 Windows 10 开始可用。

Windows Defender comes with CLI tool 'MpCmdRun' - it's not a full-sized antivirus app, but an API interface to the actual Windows Defender that's always (?) running in background. Windows Defender 附带 CLI 工具“MpCmdRun”——它不是一个全尺寸的防病毒应用程序,而是一个 API 接口,用于始终(?)在后台运行的实际 Windows Defender。

Saving to a temporary file via Path.GetTempFileName() and then running a scan like this通过Path.GetTempFileName()保存到临时文件,然后像这样运行扫描

MpCmdRun.exe -Scan -ScanType 3 -File "c:\path\to\temp\file" -DisableRemediation

works fine even in an ASP.NET (Core) app, that runs under app-pool identity即使在应用程序池身份下运行的 ASP.NET(核心)应用程序中也能正常工作

I've actually written a small (40 lines of code) C# helper that does everything for you (saves temp file, runs a scan, cleans up)我实际上写了一个小的(40 行代码)C# 帮助程序,它为您做所有事情(保存临时文件、运行扫描、清理)

https://github.com/jitbit/WinDefender/blob/main/WinDefender.cs https://github.com/jitbit/WinDefender/blob/main/WinDefender.cs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM