Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix race condition and remote hwbp removal (#44) #45

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 59 additions & 23 deletions TitanHide/hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,45 +602,81 @@ static NTSTATUS NTAPI HookNtGetContextThread(
return ret;
}

static NTSTATUS NTAPI HookNtSetContextThread(
static NTSTATUS NTAPI SetContextThreadWithoutDebugRegisters(
IN HANDLE ThreadHandle,
IN PCONTEXT Context)
{
ULONG pid = (ULONG)(ULONG_PTR)PsGetCurrentProcessId();
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
bool IsHidden = PreviousMode != KernelMode && Hider::IsHidden(pid, HideNtSetContextThread);
ULONG OriginalContextFlags = 0;
if(IsHidden)
CONTEXT contextCopy;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, but I now remember why I didn't implement this. It's undocumented, but the sizeof(CONTEXT) isn't actually the maximum size a user might pass to Get/SetThreadContext. See https://github.com/x64dbg/TitanEngine/blob/x64dbg/TitanEngine/TitanEngine.Debugger.Context.cpp#L987, but I'm unfortunately not sure how to deal with this...

Copy link
Author

@dauthleikr dauthleikr Mar 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I have two possible solutions in mind. I took a look at what InitializeContext does, and it calls a function called RtlGetExtendedContextLength2 to get the length for its ContextFlags.

Solution 1: Figure out the maximum size and go with that
Solution 2: The same functions also exists in the kernel, add it to the other undocumented functions and use it.

I can do one of those when I have some spare time, right now the bad fix works for me.

PCONTEXT contextPtr;
bool copyContextSuccess;

__try
{
//http://lifeinhex.com/dont-touch-this-writing-good-drivers-is-really-hard
//http://lifeinhex.com/when-software-is-good-enough
Log("[TITANHIDE] NtSetContextThread by %d\r\n", pid);
__try
{
ProbeForWrite(&Context->ContextFlags, sizeof(ULONG), 1);
OriginalContextFlags = Context->ContextFlags;
Context->ContextFlags = OriginalContextFlags & ~0x10; //CONTEXT_DEBUG_REGISTERS ^ CONTEXT_AMD64/CONTEXT_i386
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
IsHidden = false;
}
// Copy the context, then strip flags: https://github.com/mrexodia/TitanHide/issues/44
ProbeForRead(Context, sizeof(CONTEXT), 1);
contextCopy = *Context;
contextPtr = &contextCopy;

OriginalContextFlags = contextPtr->ContextFlags;
contextPtr->ContextFlags = OriginalContextFlags & ~0x10; //CONTEXT_DEBUG_REGISTERS ^ CONTEXT_AMD64/CONTEXT_i386
copyContextSuccess = true;
}
NTSTATUS ret = Undocumented::NtSetContextThread(ThreadHandle, Context);
if(IsHidden)
__except (EXCEPTION_EXECUTE_HANDLER)
{
contextPtr = Context;
copyContextSuccess = false;
}

NTSTATUS ret = Undocumented::NtSetContextThread(ThreadHandle, contextPtr);
if (copyContextSuccess)
{
// Copy the result context back
contextPtr->ContextFlags = OriginalContextFlags;
__try
{
ProbeForWrite(&Context->ContextFlags, sizeof(ULONG), 1);
Context->ContextFlags = OriginalContextFlags;
ProbeForWrite(Context, sizeof(CONTEXT), 1);
*Context = *contextPtr;
}
__except(EXCEPTION_EXECUTE_HANDLER)
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
return ret;
}

static NTSTATUS NTAPI HookNtSetContextThread(
IN HANDLE ThreadHandle,
IN PCONTEXT Context)
{
ULONG callerPid = (ULONG)(ULONG_PTR)PsGetCurrentProcessId();;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
bool StripDebugRegisterFlags;

if (PreviousMode == KernelMode)
{
StripDebugRegisterFlags = false;
}
else
{
ULONG targetPid = Misc::GetProcessIDFromThreadHandle(ThreadHandle);

// To prevent other processes from erasing breakpoints, they need to be "hidden" too
StripDebugRegisterFlags = Hider::IsHidden(targetPid, HideNtSetContextThread) &&
Hider::IsHidden(callerPid, HideNtSetContextThread);
}

if (StripDebugRegisterFlags)
{
//http://lifeinhex.com/dont-touch-this-writing-good-drivers-is-really-hard
//http://lifeinhex.com/when-software-is-good-enough
Log("[TITANHIDE] NtSetContextThread on %d\r\n", callerPid);
return SetContextThreadWithoutDebugRegisters(ThreadHandle, Context);
}

return Undocumented::NtSetContextThread(ThreadHandle, Context);
}

static NTSTATUS NTAPI HookNtSystemDebugControl(
IN SYSDBG_COMMAND Command,
IN PVOID InputBuffer,
Expand Down