Win32 API → NTAPI → Syscall: детектирование через EDR и ELK/Kibana
1. Архитектура вызовов
Прежде чем детектировать — необходимо понимать, что именно происходит в цепочке вызовов. Каждый уровень стека является потенциальной точкой как для атаки, так и для детектирования.
Приложение (user-space)
│
│ CreateFile(), VirtualAlloc(), OpenProcess()...
▼
kernel32.dll / kernelbase.dll ← [1] EDR User-space Hook (DLL Injection)
│
│ Высокоуровневые обёртки → вызов NTAPI
▼
ntdll.dll ← [2] ETW / API Monitoring
│ [3] Direct Syscall Detection
│ NtCreateFile()
│ NtAllocateVirtualMemory()
│ NtWriteVirtualMemory()
│ NtCreateThreadEx()
│
│ syscall stub:
│ mov r10, rcx
│ mov eax, <SSN> ← Syscall Service Number
│ syscall ← переход в ring 0
▼
ntoskrnl.exe (kernel) ← [4] SSDT (Service Descriptor Table)
│ [5] Kernel Callbacks
│ SSDT[SSN] → NtCreateFile
│ → IopCreateFile
│ → IoCreateFile...
▼
Драйвер / ФС / Устройство ← [6] Minifilter Driver
Что такое SSN (Syscall Service Number)
SSN — числовой индекс в таблице SSDT, соответствующий конкретной ядерной функции.
Значения зависят от версии и сборки Windows и не являются стабильными между релизами:
Функция Win10 21H2 Win11 22H2 Win11 23H2 NtAllocateVirtualMemory 0x18 0x18 0x18 NtWriteVirtualMemory 0x3A 0x3A 0x3A NtCreateThreadEx 0xC1 0xC2 0xC3 NtOpenProcess 0x26 0x26 0x26
Важно для аналитика: техники Hell's Gate / Halo's Gate / Tartarus' Gate динамически определяют SSN во время выполнения — именно потому что эти числа нестабильны.
2. SSDT
Что такое SSDT
System Service Descriptor Table — структура ядра Windows, содержащая массив указателей на функции-обработчики системных вызовов. Расположена в ntoskrnl.exe.
// Упрощённое определение
typedef struct _SYSTEM_SERVICE_TABLE {
PULONG_PTR ServiceTableBase; // массив адресов функций
PULONG ServiceCounterTableBase;
ULONG NumberOfServices; // ~450 функций в современных Windows
PUCHAR ParamTableBase;
} SYSTEM_SERVICE_TABLE;
SYSTEM_SERVICE_TABLE KeServiceDescriptorTable[2]; // 0=ядро, 1=Win32k (GUI)
Почему SSDT нельзя мониторить напрямую из user-space
- SSDT живёт в kernel-памяти — прямой доступ из ring 3 невозможен
- KPP (Kernel Patch Protection / PatchGuard) — начиная с x64 Windows, модификация SSDT детектируется и вызывает BSOD с кодом
0x109 CRITICAL_STRUCTURE_CORRUPTION - Антируткит-инструменты (GMER, Kernel Detective) могут читать SSDT через driver — но это не масштабируемое EDR-решение
Что реально делают EDR
Вместо прямого мониторинга SSDT, Enterprise EDR-решения (CrowdStrike Falcon, SentinelOne, Microsoft Defender for Endpoint) используют ETW Threat Intelligence и Kernel Callbacks — легальные Microsoft-approved механизмы, которые дают телеметрию на уровне, максимально близком к SSDT.
3. Точки перехвата
┌─────────────────────────────────────────────────────────────────┐ │ Уровень │ Механизм │ EDR/Tool │ ├─────────────────────────────────────────────────────────────────┤ │ User-space │ IAT/EAT Hooking │ EDR DLL inject │ │ (ring 3) │ (kernel32/ntdll) │ (legacy подход) │ ├─────────────────────────────────────────────────────────────────┤ │ Syscall boundary │ ETW Threat Intel │ ETWTI provider │ │ (ring 3→0) │ Direct Syscall det. │ SilkETW │ ├─────────────────────────────────────────────────────────────────┤ │ Kernel │ Kernel Callbacks │ EDR driver │ │ (ring 0) │ Minifilter Driver │ CrowdStrike / S1 │ │ │ ObRegisterCallbacks │ │ └─────────────────────────────────────────────────────────────────┘
4. ETW — основной механизм телеметрии
Event Tracing for Windows (ETW) — ключевой легальный механизм получения syscall-телеметрии без патчинга SSDT.
Ключевые провайдеры
Provider GUID Покрытие Microsoft-Windows-Kernel-Process 22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716 CreateProcess, CreateThread, LoadImage Microsoft-Windows-Kernel-File EDD08927-9CC4-4E65-B970-C2560FB5C289 NtCreateFile, NtWriteFile, NtReadFile Microsoft-Windows-Kernel-Registry 70EB4F03-C1DE-4F73-A051-33D13D5413BD Все Registry-операции Microsoft-Windows-Kernel-Network 7DD42A49-5329-4832-8DFD-43D979153A88 TCP/UDP события Microsoft-Windows-Threat-Intelligence F4E1897C-BB5D-5668-F1D8-040F4D8DD344 ETWTI — критически важен
ETWTI (ETW Threat Intelligence) — приоритет №1
ETWTI работает на уровне ядра и значительно сложнее обойти, чем user-space хуки:
Покрываемые API: NtAllocateVirtualMemory → детект shellcode allocation NtProtectVirtualMemory → детект RW→RX смены прав NtWriteVirtualMemory → детект process injection NtCreateThreadEx → детект remote thread NtMapViewOfSection → детект mapping injection NtQueueApcThread → детект APC injection LdrLoadDll → детект рефлективной загрузки DLL
Как малварь пытается обойти ETW
// Патч EtwEventWrite в ntdll.dll (user-space ETW патч)
// Малварь ищет функцию и пишет ret в начало:
FARPROC pEtwEventWrite = GetProcAddress(GetModuleHandle("ntdll.dll"), "EtwEventWrite");
BYTE patch[] = { 0xC3 }; // ret
WriteProcessMemory(GetCurrentProcess(), pEtwEventWrite, patch, 1, NULL);
Детект: само по себе изменение байт EtwEventWrite в ntdll — детект-сигнал.
ETWTI работает из ядра → патч user-space ntdll его не отключает.
5. Kernel Callbacks
EDR-драйвер регистрирует callbacks через официальный kernel API:
// ── Process Monitoring ────────────────────────────────────────
PsSetCreateProcessNotifyRoutineEx(
CallbackRoutine,
FALSE // регистрация
);
// → срабатывает при каждом CreateProcess / ExitProcess
// → даёт: PEPROCESS, parent PID, image path, commandline
// ── Thread Monitoring ─────────────────────────────────────────
PsSetCreateThreadNotifyRoutine(CallbackRoutine);
// → каждый CreateThread / CreateRemoteThread
// → КРИТИЧНО: remote thread в чужой процесс → IOC
// ── Image Load Monitoring ─────────────────────────────────────
PsSetLoadImageNotifyRoutine(CallbackRoutine);
// → каждая загрузка DLL/драйвера
// → детект: reflective injection, unsigned DLL, загрузка из temp
// ── Registry Monitoring ───────────────────────────────────────
CmRegisterCallback(CallbackRoutine, NULL, &Cookie);
// → все операции с реестром: Run ключи, Services, IFEO...
// ── Handle Operations ─────────────────────────────────────────
ObRegisterCallbacks(&CallbackRegistration, &RegistrationHandle);
// → OpenProcess / OpenThread с конкретными правами доступа
// → КЛЮЧЕВОЙ детект: OpenProcess(LSASS, PROCESS_VM_READ) → Mimikatz
GrantedAccess маски для OpenProcess — что искать
0x1010 → PROCESS_VM_READ | PROCESS_QUERY_LIMITED_INFORMATION (чтение памяти) 0x1410 → + PROCESS_VM_OPERATION (запись) 0x143A → почти все права (дамп) 0x1FFFFF → PROCESS_ALL_ACCESS (полный доступ) 0x0410 → стандартный Mimikatz-набор прав
6. Direct Syscall и Syscall Spoofing
Это наиболее актуальная техника обхода в 2024–2025. Понимание этого механизма критично для SOC-аналитика.
Почему малварь переходит на Direct Syscall
EDR-хуки в ntdll работают по принципу: EDR инжектирует свою DLL в каждый процесс и перехватывает вызовы в ntdll. Если малварь вызывает syscall, минуя ntdll — хук не срабатывает.
; ── Нормальный путь через ntdll ──────────────────────────────────
; ntdll!NtAllocateVirtualMemory:
mov r10, rcx ; сохранение rcx для syscall
mov eax, 0x18 ; SSN
syscall ; переход в ring 0
ret
; ── Direct Syscall (малварь в своём .text) ───────────────────────
; malware.exe+0x5678:
mov r10, rcx ; те же инструкции
mov eax, 0x18 ; тот же SSN
syscall ; НО: выполняется из адреса малвари!
ret
Syscall Spoofing / Stomping
Более продвинутая техника: SSN берётся из ntdll, но ret address подменяется:
Техника "Egg Hunting" / "Synthetic Frames": 1. Малварь находит syscall stub в ntdll (легитимный адрес) 2. Подменяет return address на стеке → stack walk показывает ntdll 3. Фактически: syscall выполняется из кода малвари, но стек "чистый"
Как детектировать Direct Syscall
Метод 1 — Аномальный call stack
── НОРМАЛЬНЫЙ СТЕК ─────────────────────────────────────────────
ntdll!NtAllocateVirtualMemory + 0x14
kernelbase!VirtualAllocEx + 0x5F
malware.exe + 0x1A3C
── ПОДОЗРИТЕЛЬНЫЙ (Direct Syscall) ────────────────────────────
ntdll!NtAllocateVirtualMemory + 0x14
malware.exe + 0x5678 ← нет kernelbase! в стеке
← или: syscall из non-ntdll региона
Метод 2 — Адрес инструкции syscall вне диапазона ntdll
# Псевдологика детекта (реализуется в EDR-драйвере):
ntdll_base = get_module_base("ntdll.dll")
ntdll_end = ntdll_base + get_module_size("ntdll.dll")
if syscall_instruction_address < ntdll_base or \
syscall_instruction_address > ntdll_end:
ALERT("Direct Syscall detected outside ntdll!")
log(process_name, pid, syscall_address, ssn)
Метод 3 — Memory region без backing file
Если syscall выполняется из региона памяти, у которого: - Type: MEM_PRIVATE (не MEM_IMAGE) - State: MEM_COMMIT - Protect: PAGE_EXECUTE_READ или PAGE_EXECUTE_READWRITE - MappedFile: None (нет backing PE-файла) → Это shellcode или reflective DLL → HIGH CONFIDENCE IOB
7. ELK / Kibana — конкретные запросы и правила
Источники данных
Sysmon v14+ → Winlogbeat → Elasticsearch → Kibana SIEM ETW (SilkETW) → Filebeat → Logstash → Kibana EDR Telemetry → Logstash → ES → Kibana Windows EventLog → Winlogbeat → ES → Kibana
Sysmon — критические Event ID
EID Событие Применение 1 Process Create commandline, hashes, parent 7 Image Loaded DLL из temp/appdata, unsigned 8 CreateRemoteThread remote thread injection 10 ProcessAccess OpenProcess + GrantedAccess 17/18 Pipe Created/Connected lateral movement, C2 25 Process Tampering hollowing, herpaderping
KQL — запросы для Kibana SIEM
🔴 LSASS Access (Credential Dumping)
event.code: "10"
AND winlog.event_data.TargetImage: "*\\lsass.exe"
AND winlog.event_data.GrantedAccess: (
"0x1010" OR "0x1410" OR "0x143a" OR
"0x1fffff" OR "0x0410" OR "0x1438"
)
AND NOT winlog.event_data.SourceImage: (
"C:\\Windows\\System32\\svchost.exe" OR
"C:\\Windows\\System32\\werfault.exe" OR
"C:\\Windows\\System32\\taskmgr.exe" OR
"C:\\Program Files\\*\\MsMpEng.exe"
)
Детектирует: Mimikatz, ProcDump, Nanodump, lsassy
🔴 Process Injection — Remote Thread
event.code: "8"
AND winlog.event_data.TargetImage: (
"*\\explorer.exe" OR "*\\svchost.exe" OR
"*\\lsass.exe" OR "*\\winlogon.exe" OR
"*\\spoolsv.exe"
)
AND NOT winlog.event_data.SourceImage: (
"C:\\Windows\\System32\\*" OR
"C:\\Windows\\SysWOW64\\*" OR
"C:\\Program Files\\*"
)
🔴 Подозрительная загрузка DLL (Unsigned / Temp)
event.code: "7"
AND winlog.event_data.Signed: "false"
AND winlog.event_data.ImageLoaded: (
"*\\AppData\\*" OR
"*\\Temp\\*" OR
"*\\ProgramData\\*" OR
"*\\Users\\Public\\*"
)
AND NOT winlog.event_data.Image: (
"C:\\Windows\\System32\\*" OR
"C:\\Windows\\SysWOW64\\*"
)
🔴 RW→RX смена прав памяти (Shellcode Pattern)
event.provider: "Microsoft-Windows-Threat-Intelligence"
AND winlog.event_data.NewAccessProtection: (
"PAGE_EXECUTE_READWRITE" OR
"PAGE_EXECUTE_WRITECOPY" OR
"0x40" OR "0x80"
)
AND winlog.event_data.OldAccessProtection: (
"PAGE_READWRITE" OR "0x04"
)
Детектирует: классический shellcode loader (malloc RW → copy → VirtualProtect RX → exec)
🟠 Direct Syscall — отсутствие ntdll в стеке
event.provider: "Microsoft-Windows-Threat-Intelligence"
AND winlog.event_data.CallingProcessId: *
AND NOT winlog.event_data.CallStack: "*ntdll*"
AND winlog.event_data.Type: (
"ALLOCVM_REMOTE" OR "PROTECTVM_REMOTE" OR
"WRITEVM_REMOTE" OR "CREATETHREAD_REMOTE"
)
🟠 ETW Patch Detection (EtwEventWrite stomping)
event.code: "7" AND winlog.event_data.ImageLoaded: "*\\ntdll.dll" AND winlog.event_data.ProcessId: *
event.provider: "Microsoft-Windows-Threat-Intelligence" AND winlog.event_data.ThreatName: "EtwEventWritePatch"
🟠 Heaven's Gate (WoW64 32→64 переход)
event.provider: "Microsoft-Windows-Threat-Intelligence" AND winlog.event_data.CallerProcessIsWow64: "true" AND winlog.event_data.TargetProcessIsWow64: "false" AND winlog.event_data.Type: "CREATETHREAD_REMOTE"
🟡 Scheduled Task Persistence (SSDT-смежный)
event.code: "1"
AND winlog.event_data.Image: "*\\schtasks.exe"
AND winlog.event_data.CommandLine: (
"*/create*" AND
("*/sc onlogon*" OR "*/sc onstart*" OR "*/sc minute*")
)
AND NOT winlog.event_data.User: "NT AUTHORITY\\SYSTEM"
Elastic Detection Rules (готовые к импорту)
В официальном репозитории elastic/detection-rules доступны правила, напрямую покрывающие SSDT-смежные техники:
windows/defense_evasion_direct_syscall_ntdll.toml windows/credential_access_lsass_memory_access.toml windows/defense_evasion_process_injection_via_createremotethread.toml windows/defense_evasion_suspicious_process_creation_calltrace.toml windows/defense_evasion_etw_provider_patched.toml
Импорт в Kibana SIEM:
Stack Management → Rules → Import rule
8. Практический стек детектирования
┌─────────────────────────────────────────────────────────────────────┐ │ PRODUCTION DETECTION STACK │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ [Kernel Layer] │ │ ETW Threat Intelligence Provider (F4E1897C...) │ │ + PsSetCreateProcessNotifyRoutineEx │ │ + ObRegisterCallbacks (OpenProcess/OpenThread) │ │ + Minifilter (filesystem events) │ │ │ │ │ [Collection Layer] ▼ │ │ SilkETW / SealighterTI → JSON (ETW → структурированные события) │ │ Sysmon v14+ → XML (process/file/network/registry) │ │ │ │ │ [Transport Layer] ▼ │ │ Winlogbeat / Filebeat → Logstash (enrich, normalize, GeoIP) │ │ │ │ │ [Storage Layer] ▼ │ │ Elasticsearch (горячий: 30 дней, тёплый: 90 дней) │ │ │ │ │ [Detection Layer] ▼ │ │ Kibana SIEM Rules → статические правила (KQL/EQL) │ │ ML Anomaly Jobs → поведенческие аномалии (CPU, inject rate)│ │ │ │ │ [Response Layer] ▼ │ │ Alert → SOAR (TheHive / Cortex) → автоматическая изоляция │ └─────────────────────────────────────────────────────────────────────┘
SilkETW — быстрый старт
# Мониторинг ETW Threat Intelligence провайдера
SilkETW.exe -t user `
-pn Microsoft-Windows-Threat-Intelligence `
-ot file `
-p C:\Logs\etwti.json
# Затем Filebeat читает C:\Logs\etwti.json → Elasticsearch
EQL (Event Query Language) — Kibana sequence detection
EQL позволяет детектировать цепочки событий, что критично для обнаружения многоэтапных техник:
-- Детект: alloc → write → protect → exec (классический shellcode loader)
sequence by process.entity_id with maxspan=30s
[process where event.type == "start"]
[api where process.Etwti.type == "ALLOCVM_REMOTE"]
[api where process.Etwti.type == "WRITEVM_REMOTE"]
[api where process.Etwti.type == "PROTECTVM_REMOTE"
and process.Etwti.NewProtection == "PAGE_EXECUTE_READ"]
[api where process.Etwti.type == "CREATETHREAD_REMOTE"]
9. Матрица угроз и обходов
Техника атаки Что обходит Детект-механизм Сигнал Direct Syscall ntdll user-space хуки ETWTI call stack analysis syscall не из ntdll диапазона Hell's Gate hardcoded SSN Sysmon EID 11 (чтение ntdll с диска) чтение PE-заголовка ntdll Halo's Gate патченные стабы memory scan ntdll integrity изменённые байты в ntdll Tartarus' Gate оба выше ETWTI комбо сигналов Syscall Spoofing call stack analysis ETWTI synthetic frame det. несоответствие ret address Heaven's Gate WoW64 хуки ETWTI WoW64 monitoring 32→64 thread creation ETW Patch ETW телеметрию kernel ETW integrity check патч EtwEventWrite SSDT Hook (руткит) всё PatchGuard / расхождение адресов BSOD или driver alert Process Hollowing process name whitelist Sysmon EID 25 section replace Process Doppelgänging file-based детект ETWTI + section mapping транзакционный файл
10. Заключение
Главный вывод
SSDT нельзя мониторить напрямую из user-space. Но это и не нужно — правильный стек детектирования строится на:
- ETWTI — ближайший к SSDT легальный источник телеметрии, работает из ядра
- Kernel Callbacks — покрывают process/thread/image/registry/handle события
- Sysmon — структурированная телеметрия для ELK без написания драйвера
- Поведенческие цепочки (EQL) — важнее отдельных сигнатур
Красные флаги для немедленного расследования
CRITICAL: • syscall-инструкция выполняется вне диапазона ntdll.dll • OpenProcess(lsass.exe) с GrantedAccess 0x1010/0x143a • CreateRemoteThread в системный процесс из non-system source • EtwEventWrite patch в ntdll любого процесса HIGH: • RW→RX смена прав в приватном (не MEM_IMAGE) регионе • Unsigned DLL загружена из %TEMP% / %APPDATA% • Отсутствие ntdll в call stack при системном вызове • Heaven's Gate: CreateThread WoW64→x64 cross-arch
Инструменты для лаборатории
Инструмент Назначение SilkETW ETW collection → JSON SealighterTI ETWTI специфично, usermode WinApiOverride user-space API мониторинг API Monitor перехват вызовов с параметрами WinDbg + tt time-travel debugging syscall chain Process Monitor быстрый file/registry/network мониторинг pe-sieve + hollows_hunter детект hollowing/doppelgänging в памяти