• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Новые методы антидебага

danyrusdem

RAID-массив
Пользователь
Регистрация
24.06.2019
Сообщения
56
Реакции
61
2020 год закончился и я решил выпустить новые антидебаг методы которые вы не видели.Что-бы начать глянем на два новых метода,оба связаны с приостановкой потока. Они не самые революционные или полезные, но лучшее я оставляю напоследок.

Обход заморозки процесса

Это милый небольшой флаг создания потока, который Microsoft добавила в 19H1. Вы когда-нибудь задумывались, почему есть дыра во флагах создания потоков? Что ж, дыра заполнена флагом, который я назову THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE (я понятия не имею, как он на самом деле называется), значение которого, естественно, равно 0x40.

Дабы продемонстрировать что оно делает,Я покажу как работает PsSuspendProcess.

C:
NTSTATUS PsSuspendProcess(_EPROCESS* Process)
{
  const auto currentThread = KeGetCurrentThread();
  KeEnterCriticalRegionThread(currentThread);

  NTSTATUS status = STATUS_SUCCESS;
  if ( ExAcquireRundownProtection(&Process->RundownProtect) )
  {
    auto targetThread = PsGetNextProcessThread(Process, nullptr);
    while ( targetThread )
    {
      // Our flag in action
      if ( !targetThread->Tcb.MiscFlags.BypassProcessFreeze )
        PsSuspendThread(targetThread, nullptr);

      targetThread = PsGetNextProcessThread(Process, targetThread);
    }
    ExReleaseRundownProtection(&Process->RundownProtect);
  }
  else
    status = STATUS_PROCESS_IS_TERMINATING;

  if ( Process->Flags3.EnableThreadSuspendResumeLogging )
    EtwTiLogSuspendResumeProcess(status, Process, Process, 0);

  KeLeaveCriticalRegionThread(currentThread);
  return status;
}

Как видите, NtSuspendProcess, вызывающий PsSuspendProcess, просто проигнорирует поток с этим флагом. Еще один бонус в том, что поток также не приостанавливается NtDebugActiveProcess! Насколько мне известно, невозможно запросить или отключить флаг после того, как поток был создан с ним, поэтому вы ничего не можете с ним поделать.

Что касается его полезности, я бы сказал, что это просто приятная небольшая добавка против сброса и вызывает путаницу, когда вы нажимаете кнопку приостановить в Processhacker, и процесс продолжает работать, как будто ничего не произошло.

Пример:

Например, вот несколько угарный код, который будет продолжать печатать, что я запускаю. Я уверен, что, увидев это во время движения задним ходом, вы бы сильно запутались в том, какого черта можно приостановить свой собственный процесс.

C:
#define THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE 0x40

NTSTATUS printer(void*) {
    while(true) {
        std::puts("I am running\n");
        Sleep(1000);
    }
    return STATUS_SUCCESS;
}

HANDLE handle;
NtCreateThreadEx(&handle, MAXIMUM_ALLOWED, nullptr, NtCurrentProcess(),
                 &printer, nullptr, THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE,
                 0, 0, 0, nullptr);

NtSuspendProcess(NtCurrentProcess());

Продолжая тенденцию к плохому поведению NtSuspendProcess, мы снова будем злоупотреблять его работой, чтобы определить, был ли наш процесс приостановлен.
Уловка заключается в том, что счетчик приостановки представляет собой 8-битное значение со знаком. Как и в предыдущем случае, вот код, который поможет вам понять внутреннюю работу:

C:
ULONG KeSuspendThread(_ETHREAD *Thread)
{
  auto irql = KeRaiseIrql(DISPATCH_LEVEL);
  KiAcquireKobjectLockSafe(&Thread->Tcb.SuspendEvent);

  auto oldSuspendCount = Thread->Tcb.SuspendCount;
  if ( oldSuspendCount == MAXIMUM_SUSPEND_COUNT ) // 127
  {
    _InterlockedAnd(&Thread->Tcb.SuspendEvent.Header.Lock, 0xFFFFFF7F);
    KeLowerIrql(irql);
    ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
  }

  auto prcb = KeGetCurrentPrcb();
  if ( KiSuspendThread(Thread, prcb) )
    ++Thread->Tcb.SuspendCount;

  _InterlockedAnd(&Thread->Tcb.SuspendEvent.Header.Lock, 0xFFFFFF7F);
  KiExitDispatcher(prcb, 0, 1, 0, irql);
  return oldSuspendCount;
}

Если вы посмотрите на первый пример кода с PsSuspendProcess, в нем нет проверки на ошибки, и вам все равно, если вы больше не можете приостановить поток. Так что же происходит, когда вы вызываете NtResumeProcess? Он уменьшает счетчик приостановки! Все, что нам нужно сделать, это довести его до максимума, и когда кто-то решит приостановить и возобновить нас, он фактически оставит счет в состоянии, в котором он не был ранее.

Пример

Приведенный ниже простой код довольно эффективен:
Visual Studio - предотвращает приостановку процесса после присоединения.
WinDbg - обнаруживается при подключении.

x64dbg - кнопка паузы становится схематичной с сообщениями об ошибках типа «Программа не запущена» до тех пор, пока вы вручную не переключитесь на основной поток.

ScyllaHide - более старые версии использовали NtSuspendProcess и вызывали его обнаружение, но это было исправлено, как только я сообщил об этом.

C:
for(size_t i = 0; i < 128; ++i)
  NtSuspendThread(thread, nullptr);

while(true) {
  if(NtSuspendThread(thread, nullptr) != STATUS_SUSPEND_COUNT_EXCEEDED)
    std::puts("I was suspended\n");
  Sleep(1000);
}

Заключение

Во всяком случае, я надеюсь, что это продемонстрировало, что лучше не полагаться на NtSuspendProcess в работе так хорошо, как вы ожидаете от инструментов, работающих с потенциально вредоносным или защищенным кодом. Надеюсь, вам понравился этот пост, и ожидаем, что в ближайшие недели появится больше контента.

Оригинал: https://secret.club/2021/01/04/thread-stuff.html
Перевод: danyrusdem
 
Пожалуйста, обратите внимание, что пользователь заблокирован
ну такое... уж совсем от детей защита.
Это тоже спорный вопрос. Когда-то совсем давно, я узнал про антидебаги и начал их вставлять во все свои сорцы ). Потом, нашел курс bad_guy, познакомился с Олли, и удивился, какая же все это ерунда, и как легко можно пропатчить (или автоматом обойти) все эти антидебаги. В большинстве случаев они ерунда, т.к. половину из них автоматом обходит отладчик (все эти проверки на флаги в РЕВ), а часть можно тупо занопить. Но , если это применять в комплексе с анти-дизасмом и трешгеном, то толк , имхо, есть. Вот был такой локер Мейз, там в комплексе было и то и это , сложно было его реверсить даже аверам. Так как что там именно срабатывает не видно изза анти-дизасма (в Ида каша из jz jnz), а отладчик вылетает.
 
реверсить даже аверам
Аверы зачастую такие же скрипткиддисы, как и остальные начинающие реверсеры.

в Ида каша из jz jnz
Скриптами эта каша снимается на раз-два.

отладчик вылетает
См выше

Единственный анти-хуянти, который сейчас реально помогает - это ВМ. Вот где уж разбирать всю кашу то ещё "удовольствие" (где-то тут должен ворваться инди со своим визором и поводить мне по щекам, да)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Скриптами эта каша снимается на раз-два.
Возможно, я не знаю питон / idc.

где-то тут должен ворваться инди со своим визором и поводить мне по щекам, да)

Ладно Инди, его визор никто не видел, а как насчет PIN и подобного? Тестил, они помогают против ВМ?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ещё есть такие способы:
1)Допустим где-то в программе есть интересный условный прыжок допустим je
и сразу за ним команда которая делает исключение,да такое которое невозможно обойти.
Решение:заNopить эту команду.
2)Что ещё встречал это когда опять интересный условный прыжок jnz(к примеру),меняешь его идёшь к return..и дальше исключение и крэш.
Тут два пути,или вместо return писать jmp адресс который должен быть дальше или скролить вверх искать там push ebp(или int* выше) или стандартное начало
подпрограммы и искать ссылки на неё.
И дальше уже пытаться заNopить всю эту подпрограмму.
Ну кто знает,тот знает.
Кстати мою порекомендовать мой перевод от lena151,там много интересных подходов и инфы =)
P.S Надеюсь это хоть кто-то поймёт,просто я это видел в коде-а описать словами трудно.
Если не понятно,извините.:(
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх