
Чистые косвенные системные вызовы с подменой системных вызовов.
SyscallRevenant — это новый метод выполнения чистых косвенных системных вызовов.
Основной компонент динамически разрешает номера системных сервисов (SSN) и адреса инструкции syscall.
Это делается путём включения флага трассировки во время выполнения.
Вторичный компонент — это подмена через замену параметров перед syscall.
Эта комбинация предназначена для обхода хуков в пользовательском пространстве при последующем вызове системного вызова с одновременной подменой изначально переданных параметров.
Отказ от ответственности: Цель этого — только для образовательных целей и тестирования. Не используйте это на машинах, на использование которых у вас нет разрешения. Не используйте это для воздействия на машины и связи с машинами, на использование которых у вас нет авторизации.
Косвенные системные вызовы — это метод выполнения инструкций syscall в доверенном пользовательском пространстве.
Если пользователь находит инструкцию syscall, он может перейти к ней косвенно.
Событие, включённое во время сеанса трассировки, может раскрыть адрес возврата сразу после инструкции.
Это не учитывает хуки Endpoint Detection & Response (EDR) в пользовательском пространстве.
EDR может вставлять хуки в ntdll.dll, тем самым обесценивая процесс поиска SSN и инструкций syscall.
Вход в хук принесёт пользу владеющему потоку, не повышая оценку вредоносности.
Наблюдение за входом в функцию и наблюдение за результирующей операцией — это разные вещи.
RevenantSyscalls исследует этот разрыв.
Следующие разделы описывают два основных компонента проекта.
Первый компонент разрешает адреса функций из ntdll.dll, загруженной процессом.
Затем может быть выполнена трассировка с флагом трассировки, если требуется информация о системном вызове.
Второй компонент выполняет косвенный переход к сохранённой информации о функции.
Чтение из сегментного регистра позволяет получить Process Environment Block (PEB).
LoaderData — это поле в PEB, содержащее данные, загружаемые с каждым процессом.
LoaderData содержит информацию о модулях, загруженных вместе с каждым процессом.
Имена модулей и базовые адреса существуют в записях модулей.
Информация об экспорте динамически подключаемой библиотеки (DLL) описывает экспортируемые ею символы. Метаданные экспорта поддерживают поиск экспортируемых символов. Индекс функции применяется только к именам и порядковым номерам имён. Хеширование имени функции — лучшее решение для сред с малым объёмом памяти.
Векторный обработчик исключений — это механизм обработки исключений, который перехватывает исключения из любого места внутри процесса.
Включение флага трассировки вызывает исключение EXCEPTION_SINGLE_STEP на следующей выполняемой инструкции.
Пользовательский векторный обработчик исключений может проверить RIP и обнаружить syscall.
Путём многократного сброса флага трассировки адрес syscall будет обнаружен, а SSN сохранён.
Поиск системного вызова
|
Выполнение системного вызова
|
Каждый системный вызов начинается с первоначального поиска информации о системном вызове; Хуки будут задействованы для получения информации о системном вызове. Далее будет выполнен косвенный переход к системному вызову. Будет связанная подмена RIP (из исходной точки входа). При повторном входе исходные параметры были подменены.
С точки зрения Event Tracing for Windows (ETW), возможные испускаемые события: SysEnter, SysExit и StackWalk для любого из них.
Если EDR строит аналогичные, сопоставимые события, они будут выглядеть почти идентично.
Единственные различия будут заключаться в кардинально различающихся временных метках Query Performance Counter (QPC).
src/AsmRevenant.asm REAL_RTN: DQ 0
FAKE_RTN: DQ 0
; If a syscall information lookup is in progress, the
; initial entry return address needs to be preserved.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [FAKE_RTN], RAX
; Once the re-entry is made, the real return is saved,
; and the current is spoofed with initial return.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [REAL_RTN], RAX
MOV RAX, QWORD PTR [FAKE_RTN]
MOV QWORD PTR [RSP], RAX
src/Revenant.cLONG VectoredExceptionHandler(EXCEPTION_POINTERS *BreakPoint) {
...
// If a syscall information lookup is being made, the
// syscall instruction address is saved, the SSN is
// saved, and the return is rerouted.
if (LookupInProgress && *(USHORT*)BreakPoint->Address == 0x050F) {
SyscallInstruction = BreakPoint->Address;
SyscallSSN = BreakPoint->Context->Rax;
BreakPoint->Context->Rip = SyscallExit;
}
// When re-entered, if the previous instruction was
// a syscall, reset return address, and exit.
if (!LookupInProgress && *(USHORT*)(BreakPoint->Address - 2) == 0x050F) {
*(VOID**)BreakPoint->Context->Rsp = REAL_RTN;
BreakPoint->Context->Rip = SyscallExit;
}
...
}