суббота, 21 мая 2011 г.

Анти-обход перехвата APC dispatcher'a

Нашел у себя в закромах интересный способ обхода перехвата диспетчера APC, который придумал Clerk:

Запуск пользовательского потока в обход перехвата диспетчера APC(R3).
 o Восстанавливаем RtlpCalloutEntryList, для исключения глобальных VEH.
 o Создаём удалённый поток.
 o Формируем SEH-фрейм.
 o Взводим TF в контексте.
Поток стартует с взведённым TF. После исполнения первой инструкции диспетчера апк (KiUserApcDispatcher()) генерируется трассировочное исключение. Управление получает диспетчер исключений (KiUserExceptionDispatcher()). Векторные обработчики не вызываются (RtlCallVectoredExceptionHandlers()). Вызывается установленный SEH. Если диспетчер APC захвачен сплайсингом, останов генерируется после исполнения джампа. Если диспетчер APC перенаправлен на диспетчер исключений, посредством установки точки останова, прежде будет вызван SEH(если хэндлер установлен как VEH).

А я затем задумался, можно ли перехватить диспетчер APC в ring3, чтобы даже при установленном TF можно было сплайсить себе наздоровье?

Казалось бы - нет, нереально. Даже учитывая тот факт, что исключение будет сгенерировано лишь на второй инструкции, это ничего не дает.
Да, можно вместо первой записать short jump, но после прыжка опять таки окажемся в SEH.
Сбросить TF флаг наверное также не получится, т.к. lea edi, [esp+arg_C] это всего 4 байта. См. код диспатчера:

.text:7C90EAC0 _KiUserApcDispatcher@20 proc near
.text:7C90EAC0
.text:7C90EAC0 arg_C           = byte ptr  10h
.text:7C90EAC0
.text:7C90EAC0                 lea     edi, [esp+arg_C]
.text:7C90EAC4                 pop     eax
.text:7C90EAC5                 call    eax
.text:7C90EAC7                 push    1
.text:7C90EAC9                 push    edi
.text:7C90EACA                 call    _ZwContinue@8   ; ZwContinue(x,x)
.text:7C90EACF                 nop

Однако, мне пришел в голову один способ обхода, который требует изменения даже не байтов, а всего 1го бита.

Речь идет о фиче Single-Stepping on Branches, Exceptions, and Interrupts.

Устанавливаем BTF флаг (Single-step on branches) в регистре IA32_DEBUGCTL MSR.
Intel пишет, что исключение будет сгенерировано процессором только при branch, services an interrupt, or generates an exception, то есть мы отключаем по сути TF флаг до первого бранча. А это дает возможность спокойно перехватывать диспетчер APC сплайсингом, но через call myFunc, а не через джамп. А уже в myFunc можно делать все что угодно, включая сброс TF флага.

p.s. Кстати как дополнение, всплыл способ обнаружения( до этого мне не известный ) VmWare и VirtualBox - они не виртуализируют IA32_DEBUGCTL MSR, т.е. детект выглядит как запись в IA32_DEBUGCTL MSR любого значения и чтение его, прочитанное значение всегда будет нулем в виртуалках.

5 комментариев:

  1. Если не изменяет память, то Clerk отписывался про данному способу детекта VMware на virustech (была тема про способы детекта)

    ОтветитьУдалить
  2. А где (и зачем) подобные извращения применимы на практике?
    Не, я не утверждаю что не применимы, просто из контекста совершенно непонятно зачём всё это.

    ОтветитьУдалить
  3. Сr4sh
    Следует рассматривать это как интересную головоломку или разминку для мозга, не более того.

    ОтветитьУдалить
  4. а клерка совсем забанили ? прикольный штрих был, таких больше не делают

    ОтветитьУдалить
  5. На VirtualBox под lin можно патч накатить чтобы работало.
    На XEN работает без проблем.

    ОтветитьУдалить