Способы обнаружения атомов

Дата публикации 25 фев 2017 | Редактировалось 10 янв 2018

Способы обнаружения атомов


Ранее описан способ блокировки исполнения атома — изоляция выборки данных (DF) через блокировку памяти. При обнаружении DF адресация изменяется, но так как в атоме DF не существует, он не может получить доступ к данным. Далее рассмотрены методы не блокировки, а обнаружения атомов.
Для обнаружения атома необходимо в начале получить событие DF. Далее можно выполнить валидацию DFG или иные манипуляции. Базовые способы получения DF:
  1. Раскодировка адресов для каждой инструкции, это получение линейного адреса через раскодировку MODRM инструкции. Для этого необходимо обработать поток инструкций — выполнить трассировку или эмуляцию.
  2. Установка ловушки. Срабатывание ловушки является событием DF. Ловушка ставится хардверно, через блокировку памяти или установку аппаратных точек останова (не универсально). В первом случае необходимо перенаправить DF на оригинальный адрес (IDP), что бы использовать ловушку повторно.
Помимо базовых способов можно найти системное решение. Так например обнаружить DF можно по расширению стека (доступ к сторожевым страницам). Кроме этого система реализует два монитора памяти: WW (write watch) и WSW (working set watch).
Первый (WW) работает со специальной памятью (MEM_WRITE_WATCH). Второй (WSW) механизм универсален. Это монитор рабочего набора. Лог добавленных страниц доступен из UM: ProcessWorkingSetWatch.
При первом обращении к странице памяти она добавляется в рабочий набор, это событие записывается в лог. Так как далее страничных нарушений не будет при обращении к данной странице, то DF не будет логгироваться. Для повторного мониторинга страницы весь рабочий набор должен быть сброшен: EmptyWorkingSet(). Но после такого сброса последует активная подгрузка страниц и соответственно сохранение этих событий в лог.
WSW это второй (с ProcessHandleTrace) механизм NT, который реализует раскрытие ядерных адресов. Пример лога для для NtQueryInformationProcess с буфером (0x360000), не присутствующем в рабочем наборе:
[​IMG]
WSW лог это массив записей:
Код (C):
  1. typedef struct _PROCESS_WS_WATCH_INFORMATION {
  2.           PVOID FaultingPc;
  3.           PVOID FaultingVa;
  4. } PROCESS_WS_WATCH_INFORMATION, *PPROCESS_WS_WATCH_INFORMATION;
Как видно первая запись в логе это событие DF в ядре при доступе к аргументу сервиса.
Следующие записи являются результатом работы отладчика (0x80615A85 0x53EA85 (смещение при загрузке ядра в OllyDbg, для загрузки необходимо изменить тип подсистемы Native Gui):
[​IMG]
Тот же вызов сервиса но при сброшенном рабочем наборе:
[​IMG]
Видна последовательность выполнения кода — вызов сервисного шлюза, возврат на него, DF из буфера и активность EMET. Следует заметить что DF из буфера происходит в ProbeForWrite() — это валидация аргументов сервиса. Под WOW в логе сохраняются UM адреса слоя виртуализации.
Этот (WSW) логгер хорошо подходит для обнаружения атомов. Он пригоден для следующих приложений:
  1. Непосредственно обнаружение атомов.
  2. Обнаружение отладочной активности.
  3. Обнаружение KM фильтров.
Упомянутый выше механизм трассировки описателей (Handle Trace) использовался для обнаружения ядерной фильтрации, что было реализовано в моторе SHDE (2012):
; Валидация ядерной SFC для определения наличия фильтров.
;
; Первый адрес на стеке ядра это kss60, инструкция следующая за процедурным ветвлением kssdoit, вызывающим NT-вектор. Второй адрес принадлежит телу NTAPI. Модель вызова сервисов (KiSystemService()/KiFastCallEntry()) не изменяется. Если вектор в SST направлен в фильтр, либо начало сервиса пропатчено (сплайсинг), то второй адрес будет принадлежать не NTAPI, а фильтру. Возможно что фильтров несколько, в этом случае SFC удлинится. Возможно фильтр не стоит на NTAPI, а находится глубже, например в менеджере объектов. В этом случае он не следит за вызов сервисов непосредственно (eg.: DrWeb ставит фильтр на OBTYPE.OpenProcedure). Однозначно определить NTAPI-фильтр можно только первый. Косвенная фильтрация не может служить для однозначной детекции.

Аналогично может быть использован и механизм WSW. Серию DF из области памяти нельзя отследить через WSW, но можно использовать цикл перезапусков целевого кода со сбросом рабочего набора, что даст все адреса, код по которым выполняет DF.
WSW позволяет исключить сервисы из валидации, так как отслеживает DF в них (сервисы являются атомами).
Перейдём к рассмотрению непосредственно детекта атомов. При обнаружении атомов трек DF является опциональным дополнением к DFG валидации через WSW:
  1. Если нет записи WSW и данные изменились, то исполнялся атом.
  2. Если есть запись WSW, то DF (WSW) должна быть из целевого кода или из сервиса. Такую проверку можно выполнить при трассировке целевого кода (таким образом выделив все адреса, по которым были DF). Может быть выполнена дополнительная проверка DF (раскодировка адресов) на соответствие WSW.
Например в AVVM сложные API являются заглушками для вызова атомов.
Если атом вызывается без обращений к аргументам до вызова его, то WSW будет пуста (1).
Если до вызова атома имеются DF, то он будет обнаружен через трассировку (2).
Если WSW эмулируется, то валидацию можно выполнить через трассировку (2).
© Indy, 2017

1 4.557
Indy_

Indy_
Well-Known Member

Регистрация:
29 апр 2011
Публикаций:
4