Антивирусное сканирование Защитника Windows из C# [исключение AccessViolation]

Мы пишем код для проверки файла C# по требованию с помощью API Защитника Windows.

        [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**.

В чем может быть проблема? Правильный ли формат структуры?

PS - Информация о MPRESOURCE_CLASS недоступна в msdn.

Я не уверен, правильна ли эта строка кода.

 mpResourceInfo.Class = IntPtr.Zero;

Обновить:

Быстрое сканирование работает нормально с этим кодом:

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

Защитник регистрирует в средстве просмотра событий [Журналы приложений и служб-Microsoft-Windows-Windows Защитник / Операционный] как

Сканирование Защитника Windows началось.
Идентификатор сканирования:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Тип сканирования:AntiSpyware
Параметры сканирования: Быстрое сканирование

4 ответа

Решение

Я не мог определить проблему здесь. Таким образом, я получил доступ к интерфейсу сканирования на наличие вредоносных программ (AMSI), начиная с Windows 10.

Я написал пример кода C# здесь.
Я обнаружил, что 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, 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);
}

Я искал проблему, и я прочитал это как одну из возможных причин:

"Вы часто видите различия между сборками отладки и выпуска, потому что сборки отладки содержат дополнительные метаданные для помощи в отладке".

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

Также вы должны проверить этот ответ на "Возможно ли перехватить исключение нарушения прав доступа в.NET?" и дальнейшие подробности, которые объясняются в статье Обработка исключений из поврежденного состояния в журнале MSDN
...

Итак, согласно этим ответам и статьям я бы попробовал:

1-ая Двойная проверка подписей и связок взаимодействия для всего неуправляемого кода, чтобы проверить, что они правильны.

2-й Установите в Visual Studio Debugger, чтобы обойти это исключение: меню Сервис -> Параметры -> Отладка -> Общие -> Снимите этот флажок "Подавить оптимизацию JIT при загрузке модуля"

3-й Try-Catch исключение

(примечание: если вы используете.Net 4, то в App.config внутри тега измените среду выполнения, включив legacyCorruptedStateExceptionsPolicy enabled="true", например:

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

)

Кроме того, здесь я обнаружил, что в некоторых версиях.net Framework (последний комментарий к 4.6.1 в одном из комментариев к ответу) есть ошибка, связанная с этим исключением, и в прошлом решением было обновление инфраструктуры., Кроме того, в одном из ответов я прочитал:

Привет Есть две возможные причины.

1. У нас есть неуправляемый код, и мы вызываем его из управляемого кода. что мешает запустить этот код. попробуйте выполнить эти команды и перезагрузите компьютер

cmd: netsh winsock reset

Откройте cmd.exe и выполните команду "netsh winsock reset catalog" 2. Антивирус считает неуправляемый код вредным и ограничивает запуск этого кода, отключает антивирус и затем проверяет

Я хотел бы знать, поможет ли какой-либо из этих подходов решить вашу проблему.

Я действительно надеюсь, что это поможет.

KR,

Juan

Вы можете использовать интерфейс сканирования антивирусных программ для проверки файлов на наличие вредоносных программ.

Интерфейс сканирования на наличие вредоносного ПО (AMSI) - это общий стандарт интерфейса, который позволяет приложениям и службам интегрироваться с любым программным обеспечением для защиты от вредоносных программ, имеющимся на компьютере. Он обеспечивает улучшенную защиту от вредоносных программ для пользователей и их данных, приложений и рабочих нагрузок.

Это доступно начиная с Windows 10.

Защитник Windows поставляется с инструментом командной строки «MpCmdRun» — это не полноразмерное антивирусное приложение, а интерфейс API для реального Защитника Windows, который всегда (?) Работает в фоновом режиме.

Сохранение во временный файл черезPath.GetTempFileName()а затем запустить сканирование, как это

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

отлично работает даже в приложении ASP.NET (Core), которое работает под идентификатором пула приложений.

На самом деле я написал небольшой (40 строк кода) помощник C#, который делает все за вас (сохраняет временный файл, запускает сканирование, очищает)

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

Другие вопросы по тегам