2016-11-30 13 views
15

Мы пишем код для сканирования по требованию файла с C# с использованием API-интерфейсов Windows Defender.Windows Defender Антивирусная проверка с C# [AccessViolation exception]

 [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 - Информация о MPRESOURCE_CLASS отсутствует в msdn.

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

mpResourceInfo.Class = IntPtr.Zero; 

Update:

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

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

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

Началось сканирование защитника Windows.
Scan ID: {CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Тип сканирования: АнтиШпион
Параметры сканирования: Быстрое сканирование

+3

Священные закодированные пути, Бэтмен! Пожалуйста, не делайте этого. Что делать, если мой загрузочный диск не является дисководом C? А что, если Защитник Windows не установлен в Program Files? –

+0

@CodyGray - Это POC. Но спасибо за указание. – mlg

+0

Первая ошибка, которую я вижу, это объявление члена MPSCAN_RESOURCES.pResourceList. Это указатель на массив, а не UnmanagedType.ByValArray. Вы должны объявить его как IntPtr и маршалировать массив самостоятельно. Использование Pack = 1 также очень неверно. Там может быть больше ошибок, это не просто api. Вы будете впереди, используя C++/CLI, чтобы сделать это, по крайней мере, вы можете положиться на заголовочный файл mpclient.h. –

ответ

2

Я не мог определить проблему здесь. Таким образом, я получил Antimalware Scan Interface (AMSI), начиная с Windows 10.

Я написал образец кода 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, 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); 
} 
+0

Зачем голосовать на этом посту. Послушайте, почему это проголосовало? Я хотел рассказать здесь, AMSI - успешный альтернативный способ общения с защитником. – mlg

+0

@ EricHirst - Это наоборот. Я опубликовал это как комментарий http://stackoverflow.com/questions/40888849/windows-defender-antivirus-scan-from-c-sharp-accessviolation-exception/41361625?noredirect=1#comment69762063_40888849 к самому вопросу. Иван скопировал это и отправил как ответ :) – mlg

+1

@mlg Я не скопировал вам ответ, потому что на самом деле я этого не заметил. Кажется, мы параллельно исследовали ту же проблему и нашли то же самое решение. В любом случае, я отведу ваш ответ и награду за вас. Возможно, имеет смысл добавить доказательство концептуального кода для использования AMSI, которое вы уже писали в ответ. –

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?» и дальнейшие детали, которые поясняются в статье Handling Corrupted State Exceptions в журнале MSDN
...

Таким образом, в соответствии с этим ответами и статей, которые я хотел бы попробовать:

1st Double подписей проверочных и COM Interop санки для всех неуправляемого кода, чтобы убедиться, что они правы.

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

третьего Try-Catch исключение

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

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

)

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

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

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

CMD: Netsh Winsock сбросить

открытым cmd.exe и запустить команду «Netsh Winsock каталог сброса» 2.Anti-вирус рассматривает не-управляемый код, как вредный и ограничение для запуска этого кода отключить антивирус, а затем проверить

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

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

KR,

Juan

+0

Спасибо. Я это увижу. – mlg

1

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

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

Он доступен, начиная с ОС Windows 10.

+0

Добавлено как комментарий к вопросу. http://stackoverflow.com/questions/40888849/windows-defender-antivirus-scan-from-c-sharp-accessviolation-exception/41361625?noredirect=1#comment69762063_40888849 – mlg