mirror of https://github.com/x64dbg/GleeBug
Add CS-aware WoW64 debugging support
This commit is contained in:
parent
6d37c95192
commit
dbb4aa83b9
|
|
@ -12,6 +12,14 @@
|
||||||
#define PAGE_SIZE 0x1000
|
#define PAGE_SIZE 0x1000
|
||||||
#endif // PAGE_SIZE
|
#endif // PAGE_SIZE
|
||||||
|
|
||||||
|
#ifndef STATUS_WX86_SINGLE_STEP
|
||||||
|
#define STATUS_WX86_SINGLE_STEP ((DWORD)0x4000001EL)
|
||||||
|
#endif // STATUS_WX86_SINGLE_STEP
|
||||||
|
|
||||||
|
#ifndef STATUS_WX86_BREAKPOINT
|
||||||
|
#define STATUS_WX86_BREAKPOINT ((DWORD)0x4000001FL)
|
||||||
|
#endif // STATUS_WX86_BREAKPOINT
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
//forward declarations
|
//forward declarations
|
||||||
|
|
|
||||||
|
|
@ -560,9 +560,11 @@ namespace GleeBug
|
||||||
switch(exceptionInfo.ExceptionRecord.ExceptionCode)
|
switch(exceptionInfo.ExceptionRecord.ExceptionCode)
|
||||||
{
|
{
|
||||||
case STATUS_BREAKPOINT:
|
case STATUS_BREAKPOINT:
|
||||||
|
case STATUS_WX86_BREAKPOINT:
|
||||||
exceptionBreakpoint(exceptionRecord, firstChance);
|
exceptionBreakpoint(exceptionRecord, firstChance);
|
||||||
break;
|
break;
|
||||||
case STATUS_SINGLE_STEP:
|
case STATUS_SINGLE_STEP:
|
||||||
|
case STATUS_WX86_SINGLE_STEP:
|
||||||
exceptionSingleStep(exceptionRecord, firstChance);
|
exceptionSingleStep(exceptionRecord, firstChance);
|
||||||
break;
|
break;
|
||||||
case STATUS_GUARD_PAGE_VIOLATION:
|
case STATUS_GUARD_PAGE_VIOLATION:
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,9 @@ 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)
|
{
|
||||||
|
auto exceptionCode = mDebugEvent.u.Exception.ExceptionRecord.ExceptionCode;
|
||||||
|
if(IsDbgReplyLaterSupported && (exceptionCode == STATUS_SINGLE_STEP || exceptionCode == STATUS_WX86_SINGLE_STEP))
|
||||||
{
|
{
|
||||||
// Resume the other threads since we are done processing the single step
|
// Resume the other threads since we are done processing the single step
|
||||||
for(auto & itr : SuspendedThreads)
|
for(auto & itr : SuspendedThreads)
|
||||||
|
|
@ -196,6 +198,7 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
exceptionEvent(mDebugEvent.u.Exception);
|
exceptionEvent(mDebugEvent.u.Exception);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case OUTPUT_DEBUG_STRING_EVENT:
|
case OUTPUT_DEBUG_STRING_EVENT:
|
||||||
debugStringEvent(mDebugEvent.u.DebugString);
|
debugStringEvent(mDebugEvent.u.DebugString);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -62,15 +62,26 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ZydisMachineMode GetMachineMode(const Registers & registers)
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
return registers.Is32BitMode() ? ZYDIS_MACHINE_MODE_LONG_COMPAT_32 : ZYDIS_MACHINE_MODE_LONG_64;
|
||||||
|
#else
|
||||||
|
return ZYDIS_MACHINE_MODE_LEGACY_32;
|
||||||
|
#endif // _WIN64
|
||||||
|
}
|
||||||
|
|
||||||
void Process::StepOver(const StepCallback & cbStep)
|
void Process::StepOver(const StepCallback & cbStep)
|
||||||
{
|
{
|
||||||
auto gip = Registers(thread->hThread, CONTEXT_CONTROL).Gip();
|
Registers registers(thread->hThread, CONTEXT_CONTROL);
|
||||||
|
auto gip = registers.Gip();
|
||||||
|
auto machineMode = GetMachineMode(registers);
|
||||||
unsigned char data[16];
|
unsigned char data[16];
|
||||||
if(MemReadSafe(gip, data, sizeof(data)))
|
if(MemReadSafe(gip, data, sizeof(data)))
|
||||||
{
|
{
|
||||||
ZydisDisassembledInstruction instruction;
|
ZydisDisassembledInstruction instruction;
|
||||||
if(ZYAN_SUCCESS(ZydisDisassembleIntel(
|
if(ZYAN_SUCCESS(ZydisDisassembleIntel(
|
||||||
GleeArchValue(ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_MACHINE_MODE_LONG_COMPAT_32),
|
machineMode,
|
||||||
gip,
|
gip,
|
||||||
data,
|
data,
|
||||||
sizeof(data),
|
sizeof(data),
|
||||||
|
|
@ -111,6 +122,7 @@ namespace GleeBug
|
||||||
|
|
||||||
// Check if we're currently stepping on a pushf instruction
|
// Check if we're currently stepping on a pushf instruction
|
||||||
auto isPushf = false;
|
auto isPushf = false;
|
||||||
|
auto pointerSize = registers.PointerSize();
|
||||||
{
|
{
|
||||||
auto gip = registers.Gip();
|
auto gip = registers.Gip();
|
||||||
unsigned char data[16];
|
unsigned char data[16];
|
||||||
|
|
@ -118,7 +130,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
ZydisDisassembledInstruction instruction;
|
ZydisDisassembledInstruction instruction;
|
||||||
if(ZYAN_SUCCESS(ZydisDisassembleIntel(
|
if(ZYAN_SUCCESS(ZydisDisassembleIntel(
|
||||||
GleeArchValue(ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_MACHINE_MODE_LONG_COMPAT_32),
|
GetMachineMode(registers),
|
||||||
gip,
|
gip,
|
||||||
data,
|
data,
|
||||||
sizeof(data),
|
sizeof(data),
|
||||||
|
|
@ -141,15 +153,16 @@ namespace GleeBug
|
||||||
|
|
||||||
if(isPushf)
|
if(isPushf)
|
||||||
{
|
{
|
||||||
thread->cbInternalStep = [this, cbStep]()
|
thread->cbInternalStep = [this, cbStep, pointerSize]()
|
||||||
{
|
{
|
||||||
// Remove the trap flag from the stack
|
// Remove the trap flag from the stack using the execution
|
||||||
|
// mode's pointer width (PUSHFD is four bytes under WoW64).
|
||||||
auto gsp = Registers(this->thread->hThread).Gsp();
|
auto gsp = Registers(this->thread->hThread).Gsp();
|
||||||
GleeBug::ptr data;
|
uint64 data = 0;
|
||||||
if(MemReadUnsafe(gsp, &data, sizeof(data)))
|
if(MemReadUnsafe(gsp, &data, pointerSize))
|
||||||
{
|
{
|
||||||
data &= ~(int)Registers::F::Trap;
|
data &= ~uint64(Registers::F::Trap);
|
||||||
MemWriteUnsafe(gsp, &data, sizeof(data));
|
MemWriteUnsafe(gsp, &data, pointerSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
cbStep();
|
cbStep();
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,12 @@ namespace GleeBug
|
||||||
TrapFlag(this),
|
TrapFlag(this),
|
||||||
ResumeFlag(this)
|
ResumeFlag(this)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
// Preserve hardware-breakpoint state across control-context updates,
|
||||||
|
// including transitions between WoW64 compatibility and native mode.
|
||||||
|
if((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
|
||||||
|
ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||||
|
#endif // _WIN64
|
||||||
memset(&mContext, 0, sizeof(CONTEXT));
|
memset(&mContext, 0, sizeof(CONTEXT));
|
||||||
mContext.ContextFlags = ContextFlags;
|
mContext.ContextFlags = ContextFlags;
|
||||||
if(!!GetThreadContext(hThread, &mContext))
|
if(!!GetThreadContext(hThread, &mContext))
|
||||||
|
|
@ -129,4 +135,18 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
return &mContext;
|
return &mContext;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
bool Registers::Is32BitMode() const
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
return mContext.SegCs == 0x23;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif // _WIN64
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Registers::PointerSize() const
|
||||||
|
{
|
||||||
|
return Is32BitMode() ? sizeof(uint32) : sizeof(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,16 @@ namespace GleeBug
|
||||||
*/
|
*/
|
||||||
PCONTEXT GetContext();
|
PCONTEXT GetContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Returns true when the thread is currently executing 32-bit code.
|
||||||
|
*/
|
||||||
|
bool Is32BitMode() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Gets the pointer size for the thread's current execution mode.
|
||||||
|
*/
|
||||||
|
size_t PointerSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
CONTEXT mContext;
|
CONTEXT mContext;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue