Статья Direct Syscalls vs EDR: Как заставить Windows выполнять ваши команды в обход хуков защитного ПО

Admin

Администратор

Direct Syscalls vs EDR: Как заставить Windows выполнять ваши команды в обход хуков защитного ПО​


Если вы когда-нибудь писали малварь на C++ или Go, вы наверняка использовали функции вроде NtCreateSection или NtWriteVirtualMemory. Но знаете ли вы, что в 99% случаев за вами в этот момент «подсматривает» антивирус?

Сегодня мы разберем, как работают Direct Syscalls (прямые системные вызовы) — техника, которая позволяет общаться с ядром Windows напрямую, игнорируя «посредников» в лице систем защиты.


1. Проблема: Что такое EDR-хуки?​

Современные антивирусы и EDR (Endpoint Detection and Response) работают не только по сигнатурам файлов. Они следят за поведением программ в реальном времени.

Когда ваша программа хочет выделить память в чужом процессе, она вызывает функцию из ntdll.dll. EDR заранее «патчит» эту библиотеку в памяти вашего процесса, вставляя туда инструкцию JMP (прыжок).
  • Как это выглядит: Программа вызывает NtMapViewOfSection -> управление прыгает в движок антивируса -> антивирус проверяет параметры -> если всё ок, возвращает управление системе.

Это называется User-mode Hooking. Ваша программа буквально живет под колпаком.


2. Решение: Прямой путь к ядру (Direct Syscalls)​


Зачем нам идти в ntdll.dll, где нас ждет засада, если мы можем выполнить системный вызов сами?

Системный вызов (Syscall) — это ассемблерная инструкция (syscall на x64), которая переключает процессор из режима пользователя в режим ядра. Чтобы вызвать её, нам нужно знать две вещи:

  1. SSN (System Service Number): Индекс функции (например, у NtWriteVirtualMemory в Windows 10 это может быть 0x3A).
  2. Инструкцию syscall.


Идея: Мы сами кладем номер функции в регистр RAX и выполняем syscall, полностью игнорируя код в ntdll.dll, который «заражен» хуками антивируса.



3. Главная сложность: Динамические SSN​

Проблема в том, что номера функций (SSN) меняются от версии к версии Windows. У Windows 10 1903 один номер, у Windows 11 — другой. Хардкодить их — плохая идея (код сломается после обновления системы).

На помощь приходят продвинутые техники:


А) Hell's Gate (Врата Ада)​

Техника, которая ищет SSN прямо в памяти ntdll.dll. Она ищет характерные опкоды (машинный код) функций и «выкусывает» из них номер системного вызова.

  • Минус: Если EDR захукал саму процедуру поиска, Hell's Gate может ничего не найти.

Б) Halo's Gate (Врата Ореола)​

Улучшенная версия. Если нужная функция захукана (код изменен антивирусом), техника ищет соседние функции (выше и ниже по адресу). Поскольку номера функций в Windows обычно идут по порядку, мы можем вычислить SSN нашей функции на основе соседей.

4. Реализация на практике (ASM + C)​

Чтобы это работало, нам нужен файл на ассемблере (.asm), который подготовит регистры:


Код:
; Пример для NtTerminateProcess
module_ntterminate:
mov r10, rcx
mov eax, [ssn_number] ; Сюда мы динамически подставим SSN
syscall
ret




И основной код на C++, который с помощью Hell's Gate найдет этот самый ssn_number в памяти системы.

5. Почему это всё еще работает?​


EDR не могут заблокировать инструкцию syscall как таковую, потому что на ней работает вся операционная система. Однако современные защитники научились новому фокусу — Call Stack Monitoring. Они смотрят: «А откуда был совершен системный вызов?». Если он пришел не из ntdll.dll, а из непонятного куска памяти (вашего кода) — это мгновенный детект.


Как это обходят?

Используют технику Indirect Syscalls. Мы готовим регистры в своем коде, но прыгаем на инструкцию syscall внутри легитимной ntdll.dll. Для системы это выглядит так, будто вызов совершила сама библиотека.


Итог​

Direct Syscalls — это база для любого серьезного Red Team инструмента. Это превращает игру в «кошки-мышки»: антивирусы ставят ловушки, а мы учимся ходить сквозь стены.