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), которая переключает процессор из режима пользователя в режим ядра. Чтобы вызвать её, нам нужно знать две вещи:
- SSN (System Service Number): Индекс функции (например, у NtWriteVirtualMemory в Windows 10 это может быть 0x3A).
- Инструкцию 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. Для системы это выглядит так, будто вызов совершила сама библиотека.