Исходник BadDBGException

✊Rot Front✊
Пользователь
Статус
Оффлайн
Регистрация
2 Июл 2020
Сообщения
131
Реакции[?]
256
Поинты[?]
84K
Поскольку мне было скучно,я начал изучать работу UM дебаггера.
Встал вопрос:"Как работает ThreadHideFromDebugger?" - и я сделал мемный PoC.
Зачем устанавливать флаг в ETHREAD-> CrossThreadFlags ->HideFromDebugger,
если можно просто пропатчить код в ядре,чтобы всегда дебаггеру не передавалось исключение.
Пожалуйста, авторизуйтесь для просмотра ссылки.

Проблема: мы патчим код в ntoskrnl.exe и через некоторое время вы получите BSOD с ошибкой CRITICAL_STRUCTURE_CORRUPTION.

Объяснение:
Здесь мы рассмотрим работу NtSetInformationThread с ThreadHideFromDebugger.
Большинство описаний данной техники звучат как-то так:
Если этот флаг установлен для потока, то этот поток перестает отправлять уведомления о событиях отладки.
Эти события включают точки останова и уведомления о завершении программы.

Если мы посмотрим NtSetInformationThread,то мы увидим следующую картину:

C++:
case ThreadHideFromDebugger :
    if ( ThreadInformationLength )
      return STATUS_INFO_LENGTH_MISMATCH;
    nt_status = ObReferenceObjectByHandleWithTag(
               v6,
               THREAD_SET_INFORMATION,
               (POBJECT_TYPE)PsThreadType,
               v9,
               'yQsP',
               &ethread,
               NULL);
    if ( nt_status < 0 )
      return nt_status;
    /*_
    InterlockedOr((volatile signed __int32 *)ethread + 324, 4u);
    пиздабол т.к
    mov     rax, [rsp+278h+var_238]
    lock or dword ptr [rax+510h], 4  ;CrossThreadFlags  на моей системе
    jmp     short loc_140802B96
    */
    _InterlockedOr(ethread->CrossThreadFlags, 4u);

В структуре _ETHREAD есть CrossThreadFlags,где хранятся некоторые флаги потока.
Хранится там значения и хранится,но как это работает?! Да и почему мой 1337 дебаггер перестаёт работать?!!!
Слегка погуглив я нашёл
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
Ответ:DbgkForwardException
Я решил взять код из WRK для наглядности + ida несколько раз обманула и вам не всё будет понятно,если покажу этот "кусок кода".
C++:
/*
https://github.com/HighSchoolSoftwareClub/Windows-Research-Kernel-WRK-/blob/26b524b2d0f18de703018e16ec5377889afcf4ab/WRK-v1.2/base/ntos/dbgk/dbgkport.c#L211
*/

BOOLEAN
DbgkForwardException(
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN BOOLEAN DebugException,
    IN BOOLEAN SecondChance
    )

/*++
Routine Description:
    This function is called forward an exception to the calling process's
    debug or subsystem exception port.
Arguments:
    ExceptionRecord - Supplies a pointer to an exception record.
    DebugException - Supplies a boolean variable that specifies whether
        this exception is to be forwarded to the process's
        DebugPort(TRUE), or to its ExceptionPort(FALSE).
Return Value:
    TRUE - The process has a DebugPort or an ExceptionPort, and the reply
        received from the port indicated that the exception was handled.
    FALSE - The process either does not have a DebugPort or
        ExceptionPort, or the process has a port, but the reply received
        from the port indicated that the exception was not handled.
--*/

{
    PEPROCESS Process;
    PVOID Port;
    DBGKM_APIMSG m;
    PDBGKM_EXCEPTION args;
    NTSTATUS st;
    BOOLEAN LpcPort;

    PAGED_CODE();

    args = &m.u.Exception;

    //
    // Initialize the debug LPC message with default information.
    //

    DBGKM_FORMAT_API_MSG(m,DbgKmExceptionApi,sizeof(*args));

    //
    // Get the address of the destination LPC port.
    //

    Process = PsGetCurrentProcess();
    if (DebugException) {
        if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) {
            Port = NULL;
        } else {
            Port = Process->DebugPort;
        }
        LpcPort = FALSE;
    } else {
        Port = Process->ExceptionPort;
        m.h.u2.ZeroInit = LPC_EXCEPTION;
        LpcPort = TRUE;
    }

    //
    // If the destination LPC port address is NULL, then return FALSE.
    //

    if (Port == NULL) {
        return FALSE;
    }

    //
    // Fill in the remainder of the debug LPC message.
    //

    args->ExceptionRecord = *ExceptionRecord;
    args->FirstChance = !SecondChance;

    //
    // Send the debug message to the destination LPC port.
    //

    if (LpcPort) {
        st = DbgkpSendApiMessageLpc(&m,Port,DebugException);
    } else {
        st = DbgkpSendApiMessage(&m,DebugException);
    }


    //
    // If the send was not successful, then return a FALSE indicating that
    // the port did not handle the exception. Otherwise, if the debug port
    // is specified, then look at the return status in the message.
    //

    if (!NT_SUCCESS(st) ||
        ((DebugException) &&
        (m.ReturnedStatus == DBG_EXCEPTION_NOT_HANDLED || !NT_SUCCESS(m.ReturnedStatus)))) {
        return FALSE;

    } else {
        return TRUE;
    }
}
Ответ:если флаг установлен, то исключение не передаётся на порт отладчика(DbgkpSendApiMessage),Port будет равен 0 и функция возвращает FALSE.
Вот и всё :D
 
Последнее редактирование:
Сверху Снизу