Злой отладчик. Изучаем новый способ обхода AMSI в Windows

Содержание статьи

  • Становимся дебаггером
  • Избегаем использования функции DebugActiveProcess
  • Заключение

Antimalware Scan Interface — сис­тема, которую в Microsoft соз­дали для защиты от вре­донос­ных сце­нари­ев на PowerShell. В этой статье я про­демонс­три­рую, как работа­ет один из методов обхо­да это­го механиз­ма. Мы будем запус­кать сце­нарий PowerShell как про­цесс под отладкой, что откро­ет некото­рые инте­рес­ные воз­можнос­ти.

На высоком уров­не AMSI хука­ет каж­дую коман­ду или сце­нарий во вре­мя выпол­нения и переда­ет их локаль­ному анти­вирус­ному ПО для про­вер­ки. При­чем под­держи­вают­ся прак­тичес­ки любые анти­виру­сы, это может быть не толь­ко стан­дар­тный Defender.

AMSI уме­ет работать:

  • с PowerShell;
  • Windows Script Host (wscript и cscript);
  • JavaScript и VBScript;
  • VBA-мак­росами.

Проб­лема такой реали­зации в том, что amsi.dll (в которой реали­зова­на вся логика AMSI) находит­ся в адресном прос­транс­тве текуще­го про­цес­са. Как следс­твие, у ата­кующих появ­ляет­ся воз­можность манипу­лиро­вать этой биб­лиоте­кой так, как они захотят сами. Уже при­дума­но мно­жес­тво спо­собов обхо­да, это и amsiInitFailed, и хукинг, и пат­чинг. Сегод­ня мы обсу­дим еще один метод обхо­да — запуск про­цес­са PowerShell в режиме отладки.

 

Становимся дебаггером

Не­дав­но я обна­ружил инте­рес­ную API-фун­кцию DebugActiveProcess(), которая поз­воля­ет нашему про­цес­су стать дебаг­гером для дру­гого про­цес­са. Про­тотип у нее очень прос­той, ей нуж­но передать лишь PID про­цес­са, который тре­бует­ся отла­живать.

BOOL DebugActiveProcess( [in] DWORD dwProcessId);

К сожале­нию, абы какой про­цесс отла­живать не получит­ся. Успешный вызов этой фун­кции получит­ся, толь­ко если выпол­няет­ся хотя бы одно из сле­дующих усло­вий:

  • у токена нашего про­цес­са есть SeDebugPrivilege;
  • мы можем зап­росить хендл на отла­жива­емый про­цесс с мас­кой PROCESS_ALL_ACCESS.

Ка­залось бы, тре­бова­ния более чем серь­езные, но нич­то не меша­ет нам запус­тить про­цесс powershell.exe как дочер­ний, а на дочер­ний про­цесс наш родитель­ский уж точ­но смо­жет зап­росить мас­ку PROCESS_ALL_ACCESS.

Что же нам даст ста­тус дебаг­гера? Единс­твен­ное пре­иму­щес­тво — воз­можность обра­баты­вать Debug-события, сре­ди которых LOAD_DLL_DEBUG_EVENT. Событие генери­рует­ся сра­зу же, как толь­ко идет попыт­ка заг­рузки DLL в адресное прос­транс­тво отла­жива­емо­го про­цес­са. При­чем будет запол­нена струк­тура LOAD_DLL_DEBUG_INFO, содер­жащая базовый адрес под­гру­жаемой биб­лиоте­ки. А с базовым адре­сом уже мож­но наворо­тить немало дел…

Пред­лагаю перей­ти к прак­тике. Во‑пер­вых, мы не можем сле­по взять и запус­тить про­цесс, а потом непонят­но ког­да при­цепить­ся к нему отладчи­ком — так есть шанс про­пус­тить момент заг­рузки amsi.dll в про­цесс. Поэто­му про­цесс дол­жен быть запущен с фла­гом 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 соз­данно­го про­цес­са, а так­же ини­циали­зиру­ет хен­длы, ука­зыва­ющие на глав­ный поток про­цес­са и на сам про­цесс.

Источник: xakep.ru

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *