mirror of https://github.com/x64dbg/GleeBug
Implement safe stepping with DBG_REPLY_LATER
This commit is contained in:
parent
660619edf3
commit
39934ea3ae
|
|
@ -1,6 +1,10 @@
|
||||||
#include "Debugger.h"
|
#include "Debugger.h"
|
||||||
#include "Debugger.Thread.Registers.h"
|
#include "Debugger.Thread.Registers.h"
|
||||||
|
|
||||||
|
#ifndef DBG_REPLY_LATER
|
||||||
|
#define DBG_REPLY_LATER ((NTSTATUS)0x40010001L)
|
||||||
|
#endif // DBG_REPLY_LATER
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::Start()
|
void Debugger::Start()
|
||||||
|
|
@ -24,6 +28,18 @@ namespace GleeBug
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD ThreadBeingProcessed = 0;
|
||||||
|
std::unordered_map<DWORD, HANDLE> SuspendedThreads;
|
||||||
|
bool IsDbgReplyLaterSupported = false;
|
||||||
|
|
||||||
|
// Check if DBG_REPLY_LATER is supported based on Windows version (Windows 10, version 1507 or above)
|
||||||
|
// https://www.gaijin.at/en/infos/windows-version-numbers
|
||||||
|
const uint32_t NtBuildNumber = *(uint32_t*)(0x7FFE0000 + 0x260);
|
||||||
|
if (NtBuildNumber != 0 && NtBuildNumber >= 10240)
|
||||||
|
{
|
||||||
|
IsDbgReplyLaterSupported = mSafeStep;
|
||||||
|
}
|
||||||
|
|
||||||
while(!mBreakDebugger)
|
while(!mBreakDebugger)
|
||||||
{
|
{
|
||||||
//wait for a debug event
|
//wait for a debug event
|
||||||
|
|
@ -53,6 +69,38 @@ namespace GleeBug
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle safe stepping
|
||||||
|
if (IsDbgReplyLaterSupported)
|
||||||
|
{
|
||||||
|
if (mDebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
|
||||||
|
{
|
||||||
|
// Check if there is a thread processing a single step
|
||||||
|
if (ThreadBeingProcessed != 0 && mDebugEvent.dwThreadId != ThreadBeingProcessed)
|
||||||
|
{
|
||||||
|
// Reply to the event later
|
||||||
|
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, DBG_REPLY_LATER))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Wait for the next event
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mDebugEvent.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
|
||||||
|
{
|
||||||
|
if (ThreadBeingProcessed != 0 && mDebugEvent.dwThreadId == ThreadBeingProcessed)
|
||||||
|
{
|
||||||
|
// Resume the other threads since the thread being processed is exiting
|
||||||
|
for (auto& itr : SuspendedThreads)
|
||||||
|
ResumeThread(itr.second);
|
||||||
|
|
||||||
|
SuspendedThreads.clear();
|
||||||
|
ThreadBeingProcessed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal we are currently paused
|
||||||
mIsRunning = false;
|
mIsRunning = false;
|
||||||
|
|
||||||
//set default continue status
|
//set default continue status
|
||||||
|
|
@ -108,6 +156,15 @@ namespace GleeBug
|
||||||
unloadDllEvent(mDebugEvent.u.UnloadDll);
|
unloadDllEvent(mDebugEvent.u.UnloadDll);
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_DEBUG_EVENT:
|
case EXCEPTION_DEBUG_EVENT:
|
||||||
|
if (IsDbgReplyLaterSupported && mDebugEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_SINGLE_STEP)
|
||||||
|
{
|
||||||
|
// Resume the other threads since we are done processing the single step
|
||||||
|
for (auto& itr : SuspendedThreads)
|
||||||
|
ResumeThread(itr.second);
|
||||||
|
|
||||||
|
SuspendedThreads.clear();
|
||||||
|
ThreadBeingProcessed = 0;
|
||||||
|
}
|
||||||
exceptionEvent(mDebugEvent.u.Exception);
|
exceptionEvent(mDebugEvent.u.Exception);
|
||||||
break;
|
break;
|
||||||
case OUTPUT_DEBUG_STRING_EVENT:
|
case OUTPUT_DEBUG_STRING_EVENT:
|
||||||
|
|
@ -139,6 +196,33 @@ namespace GleeBug
|
||||||
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
|
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle safe stepping
|
||||||
|
if (IsDbgReplyLaterSupported && mDebugEvent.dwDebugEventCode != EXIT_THREAD_DEBUG_EVENT)
|
||||||
|
{
|
||||||
|
// If TF is set (single step), then suspend all the other threads
|
||||||
|
if (mThread && mThread->isInternalStepping)
|
||||||
|
{
|
||||||
|
ThreadBeingProcessed = mDebugEvent.dwThreadId;
|
||||||
|
|
||||||
|
for (auto& Thread : mProcess->threads)
|
||||||
|
{
|
||||||
|
auto dwThreadId = Thread.first;
|
||||||
|
auto hThread = Thread.second->hThread;
|
||||||
|
|
||||||
|
// Do not suspend the current thread
|
||||||
|
if (ThreadBeingProcessed == dwThreadId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the thread is already suspended
|
||||||
|
if (SuspendedThreads.count(dwThreadId) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SuspendThread(hThread) != -1)
|
||||||
|
SuspendedThreads.emplace(dwThreadId, hThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//continue the debug event
|
//continue the debug event
|
||||||
if(!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
|
if(!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,7 @@ namespace GleeBug
|
||||||
bool mDetach = false;
|
bool mDetach = false;
|
||||||
bool mDetachAndBreak = false;
|
bool mDetachAndBreak = false;
|
||||||
bool mAttachedToProcess = false;
|
bool mAttachedToProcess = false;
|
||||||
|
bool mSafeStep = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief The current process (can be null in some cases).
|
\brief The current process (can be null in some cases).
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,9 @@ public:
|
||||||
case UE_ENGINE_SAFE_ATTACH:
|
case UE_ENGINE_SAFE_ATTACH:
|
||||||
mSafeAttach = VariableSet;
|
mSafeAttach = VariableSet;
|
||||||
break;
|
break;
|
||||||
|
case UE_ENGINE_SAFE_STEP:
|
||||||
|
mSafeStep = VariableSet;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,9 @@
|
||||||
#define UE_ENGINE_CALL_PLUGIN_DEBUG_CALLBACK 8
|
#define UE_ENGINE_CALL_PLUGIN_DEBUG_CALLBACK 8
|
||||||
#define UE_ENGINE_SET_DEBUG_PRIVILEGE 9
|
#define UE_ENGINE_SET_DEBUG_PRIVILEGE 9
|
||||||
#define UE_ENGINE_SAFE_ATTACH 10
|
#define UE_ENGINE_SAFE_ATTACH 10
|
||||||
|
#define UE_ENGINE_MEMBP_ALT 11
|
||||||
|
#define UE_ENGINE_DISABLE_ASLR 12
|
||||||
|
#define UE_ENGINE_SAFE_STEP 13
|
||||||
|
|
||||||
#define UE_OPTION_REMOVEALL 1
|
#define UE_OPTION_REMOVEALL 1
|
||||||
#define UE_OPTION_DISABLEALL 2
|
#define UE_OPTION_DISABLEALL 2
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue