На высоком уровне AMSI хукает каждую команду или сценарий во время выполнения и передает их локальному антивирусному ПО для проверки. Причем поддерживаются практически любые антивирусы, это может быть не только стандартный Defender.
AMSI умеет работать:
- с PowerShell;
- Windows Script Host (
wscript
иcscript
); - JavaScript и VBScript;
- VBA-макросами.
Проблема такой реализации в том, что amsi.
(в которой реализована вся логика AMSI) находится в адресном пространстве текущего процесса. Как следствие, у атакующих появляется возможность манипулировать этой библиотекой так, как они захотят сами. Уже придумано множество способов обхода, это и amsiInitFailed, и хукинг, и патчинг. Сегодня мы обсудим еще один метод обхода — запуск процесса PowerShell в режиме отладки.
Становимся дебаггером
Недавно я обнаружил интересную API-функцию DebugActiveProcess(
, которая позволяет нашему процессу стать дебаггером для другого процесса. Прототип у нее очень простой, ей нужно передать лишь PID процесса, который требуется отлаживать.
BOOL DebugActiveProcess( [in] DWORD dwProcessId);
К сожалению, абы какой процесс отлаживать не получится. Успешный вызов этой функции получится, только если выполняется хотя бы одно из следующих условий:
- у токена нашего процесса есть
SeDebugPrivilege
; - мы можем запросить хендл на отлаживаемый процесс с маской
PROCESS_ALL_ACCESS
.
Казалось бы, требования более чем серьезные, но ничто не мешает нам запустить процесс powershell.
как дочерний, а на дочерний процесс наш родительский уж точно сможет запросить маску PROCESS_ALL_ACCESS
.
Что же нам даст статус дебаггера? Единственное преимущество — возможность обрабатывать Debug-события, среди которых LOAD_DLL_DEBUG_EVENT
. Событие генерируется сразу же, как только идет попытка загрузки DLL в адресное пространство отлаживаемого процесса. Причем будет заполнена структура LOAD_DLL_DEBUG_INFO
, содержащая базовый адрес подгружаемой библиотеки. А с базовым адресом уже можно наворотить немало дел...
Предлагаю перейти к практике. Во‑первых, мы не можем слепо взять и запустить процесс, а потом непонятно когда прицепиться к нему отладчиком — так есть шанс пропустить момент загрузки amsi.
в процесс. Поэтому процесс должен быть запущен с флагом CREATE_SUSPENDED
. Во‑вторых, из‑за того, что мы никак не обрабатываем Debug-события, приложение может упасть. Поэтому после того, как пропатчим AMSI, следует как можно скорее переставать быть дебаггером.
Для создания процесса я написал отдельную функцию StartProcessSuspended(
.
DWORD StartProcessSuspended(LPWSTR ProcName, HANDLE& hThread, HANDLE& hProc) { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWNORMAL; if (!CreateProcess(ProcName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { DWORD err = GetLastError(); std::cout << h("[-] Cant Create Suspended Process : ") << err << " " << GetWinapiErrorDescription(err) << std::endl; return -1; } hThread = pi.hThread; hProc = pi.hProcess;#ifdef DEBUG std::cout << h("[+] Process Created Successfully") << std::endl;#endif return pi.dwProcessId;}
Здесь дополнительно указан флаг CREATE_NEW_CONSOLE
. Он нужен, чтобы powershell.exe запускалась как новая консоль. Как будто мы ее запустили вручную, дважды кликнув на исполняемый файл. Функция возвращает PID созданного процесса, а также инициализирует хендлы, указывающие на главный поток процесса и на сам процесс.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»