✊Rot Front✊
-
Автор темы
- #1
Поскольку мне было скучно,я начал изучать работу UM дебаггера.
Встал вопрос:"Как работает ThreadHideFromDebugger?" - и я сделал мемный PoC.
Зачем устанавливать флаг в ETHREAD-> CrossThreadFlags ->HideFromDebugger,
если можно просто пропатчить код в ядре,чтобы всегда дебаггеру не передавалось исключение.
Проблема: мы патчим код в ntoskrnl.exe и через некоторое время вы получите BSOD с ошибкой CRITICAL_STRUCTURE_CORRUPTION.
Объяснение:
Встал вопрос:"Как работает ThreadHideFromDebugger?" - и я сделал мемный PoC.
Зачем устанавливать флаг в ETHREAD-> CrossThreadFlags ->HideFromDebugger,
если можно просто пропатчить код в ядре,чтобы всегда дебаггеру не передавалось исключение.
Пожалуйста, авторизуйтесь для просмотра ссылки.
Проблема: мы патчим код в ntoskrnl.exe и через некоторое время вы получите BSOD с ошибкой CRITICAL_STRUCTURE_CORRUPTION.
Объяснение:
Здесь мы рассмотрим работу NtSetInformationThread с ThreadHideFromDebugger.
Большинство описаний данной техники звучат как-то так:
Если этот флаг установлен для потока, то этот поток перестает отправлять уведомления о событиях отладки.
Эти события включают точки останова и уведомления о завершении программы.
Если мы посмотрим NtSetInformationThread,то мы увидим следующую картину:
В структуре _ETHREAD есть CrossThreadFlags,где хранятся некоторые флаги потока.
Хранится там значения и хранится,но как это работает?! Да и почему мой 1337 дебаггер перестаёт работать?!!!
Слегка погуглив я нашёл
Ответ:DbgkForwardException
Я решил взять код из WRK для наглядности + ida несколько раз обманула и вам не всё будет понятно,если покажу этот "кусок кода".
Ответ:если флаг установлен, то исключение не передаётся на порт отладчика(DbgkpSendApiMessage),Port будет равен 0 и функция возвращает FALSE.
Вот и всё :D
Большинство описаний данной техники звучат как-то так:
Если этот флаг установлен для потока, то этот поток перестает отправлять уведомления о событиях отладки.
Эти события включают точки останова и уведомления о завершении программы.
Если мы посмотрим NtSetInformationThread,то мы увидим следующую картину:
C++:
case ThreadHideFromDebugger :
if ( ThreadInformationLength )
return STATUS_INFO_LENGTH_MISMATCH;
nt_status = ObReferenceObjectByHandleWithTag(
v6,
THREAD_SET_INFORMATION,
(POBJECT_TYPE)PsThreadType,
v9,
'yQsP',
ðread,
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;
}
}
Вот и всё :D
Последнее редактирование: