mirror of https://github.com/x64dbg/GleeBug
hardware breakpoints working + fixed possible bug with breakpoints + added unknownEvent callback + added cbUnhandledException in MyDebugger
This commit is contained in:
parent
26c71cc6e4
commit
3bde590956
|
|
@ -17,6 +17,14 @@ namespace GleeBug
|
|||
ShortInt3
|
||||
};
|
||||
|
||||
enum class HardwareBreakpointSlot
|
||||
{
|
||||
Dr0 = 0,
|
||||
Dr1 = 1,
|
||||
Dr2 = 2,
|
||||
Dr3 = 3
|
||||
};
|
||||
|
||||
enum class HardwareBreakpointType
|
||||
{
|
||||
Access,
|
||||
|
|
@ -26,11 +34,11 @@ namespace GleeBug
|
|||
|
||||
enum class HardwareBreakpointSize
|
||||
{
|
||||
SizeByte,
|
||||
SizeWord,
|
||||
SizeDword,
|
||||
SizeByte = 1,
|
||||
SizeWord = 2,
|
||||
SizeDword = 4,
|
||||
#ifdef _WIN64
|
||||
SizeQword
|
||||
SizeQword = 8
|
||||
#endif //_WIN64
|
||||
};
|
||||
|
||||
|
|
@ -54,6 +62,7 @@ namespace GleeBug
|
|||
} software;
|
||||
struct
|
||||
{
|
||||
HardwareBreakpointSlot slot;
|
||||
HardwareBreakpointType type;
|
||||
HardwareBreakpointSize size;
|
||||
} hardware;
|
||||
|
|
|
|||
|
|
@ -70,11 +70,68 @@ namespace GleeBug
|
|||
for (auto cbStep : cbStepCopy)
|
||||
cbStep();
|
||||
}
|
||||
else //handle other single step exceptions
|
||||
else //handle hardware breakpoint single step exceptions
|
||||
{
|
||||
exceptionHardwareBreakpoint(ptr(exceptionRecord.ExceptionAddress));
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::exceptionHardwareBreakpoint(ptr exceptionAddress)
|
||||
{
|
||||
//determine the hardware breakpoint triggered
|
||||
ptr dr6 = _registers->Dr6();
|
||||
HardwareBreakpointSlot breakpointSlot;
|
||||
ptr breakpointAddress;
|
||||
if (exceptionAddress == _registers->Dr0() || dr6 & 0x1)
|
||||
{
|
||||
breakpointAddress = _registers->Dr0();
|
||||
breakpointSlot = HardwareBreakpointSlot::Dr0;
|
||||
}
|
||||
else if (exceptionAddress == _registers->Dr1() || dr6 & 0x2)
|
||||
{
|
||||
breakpointAddress = _registers->Dr1();
|
||||
breakpointSlot = HardwareBreakpointSlot::Dr1;
|
||||
}
|
||||
else if (exceptionAddress == _registers->Dr2() || dr6 & 0x4)
|
||||
{
|
||||
breakpointAddress = _registers->Dr2();
|
||||
breakpointSlot = HardwareBreakpointSlot::Dr2;
|
||||
}
|
||||
else if (exceptionAddress == _registers->Dr3() || dr6 & 0x8)
|
||||
{
|
||||
breakpointAddress = _registers->Dr3();
|
||||
breakpointSlot = HardwareBreakpointSlot::Dr3;
|
||||
}
|
||||
else
|
||||
return; //not a hardware breakpoint
|
||||
|
||||
//find the breakpoint in the internal structures
|
||||
auto foundInfo = _process->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
||||
if (foundInfo == _process->breakpoints.end())
|
||||
return; //not a valid hardware breakpoint
|
||||
const auto & info = foundInfo->second;
|
||||
if (info.internal.hardware.slot != breakpointSlot)
|
||||
return; //not a valid hardware breakpoint
|
||||
|
||||
//set continue status
|
||||
_continueStatus = DBG_CONTINUE;
|
||||
|
||||
//delete the hardware breakpoint and do an internal step (TODO: maybe delete from all threads?)
|
||||
_thread->DeleteHardwareBreakpoint(breakpointSlot);
|
||||
_thread->StepInternal(std::bind([this, info]()
|
||||
{
|
||||
_thread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
||||
}));
|
||||
|
||||
//call the generic callback
|
||||
cbBreakpoint(info);
|
||||
|
||||
//call the user callback
|
||||
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
||||
if (foundCallback != _process->breakpointCallbacks.end())
|
||||
foundCallback->second(info);
|
||||
}
|
||||
|
||||
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||
{
|
||||
//let the debuggee handle exceptions per default
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
#include "Debugger.h"
|
||||
|
||||
namespace GleeBug
|
||||
{
|
||||
void Debugger::unknownEvent(DWORD debugEventCode)
|
||||
{
|
||||
//prevent possible anti-debug trick
|
||||
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||||
|
||||
//call the debug event callback
|
||||
cbUnknownEvent(debugEventCode);
|
||||
}
|
||||
};
|
||||
|
|
@ -78,6 +78,9 @@ namespace GleeBug
|
|||
case RIP_EVENT:
|
||||
ripEvent(_debugEvent.u.RipInfo);
|
||||
break;
|
||||
default:
|
||||
unknownEvent(_debugEvent.dwDebugEventCode);
|
||||
break;
|
||||
}
|
||||
|
||||
//write the register context
|
||||
|
|
|
|||
|
|
@ -44,12 +44,86 @@ namespace GleeBug
|
|||
|
||||
bool ProcessInfo::SetBreakpoint(ptr address, const BreakpointCallback & cbBreakpoint, bool singleshoot, SoftwareBreakpointType type)
|
||||
{
|
||||
//check if a callback on this address was already found
|
||||
if (breakpointCallbacks.find({ BreakpointType::Software, address }) != breakpointCallbacks.end())
|
||||
return false;
|
||||
//set the breakpoint
|
||||
if (!SetBreakpoint(address, singleshoot, type))
|
||||
return false;
|
||||
auto found = breakpointCallbacks.find({ BreakpointType::Software, address });
|
||||
if (found != breakpointCallbacks.end())
|
||||
return false;
|
||||
//insert the callback
|
||||
breakpointCallbacks.insert({ { BreakpointType::Software, address }, cbBreakpoint });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessInfo::GetFreeHardwareBreakpointSlot(HardwareBreakpointSlot & slot)
|
||||
{
|
||||
//find a free hardware breakpoint slot
|
||||
for (int i = 0; i < 4;i++)
|
||||
{
|
||||
if (!hardwareBreakpoints[i].enabled)
|
||||
{
|
||||
slot = HardwareBreakpointSlot(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size)
|
||||
{
|
||||
//check the address
|
||||
if (!MemIsValidPtr(address) ||
|
||||
breakpoints.find({ BreakpointType::Hardware, address }) != breakpoints.end())
|
||||
return false;
|
||||
|
||||
//attempt to set the hardware breakpoint in every thread
|
||||
bool success = true;
|
||||
for (auto & thread : threads)
|
||||
{
|
||||
if (!thread.second.SetHardwareBreakpoint(address, slot, type, size))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if setting failed, unset all
|
||||
if (!success)
|
||||
{
|
||||
for (auto & thread : threads)
|
||||
thread.second.DeleteHardwareBreakpoint(slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
//setup the breakpoint information struct
|
||||
BreakpointInfo info = {};
|
||||
info.address = address;
|
||||
info.enabled = true;
|
||||
info.singleshoot = false;
|
||||
info.type = BreakpointType::Hardware;
|
||||
info.internal.hardware.slot = slot;
|
||||
info.internal.hardware.type = type;
|
||||
info.internal.hardware.size = size;
|
||||
|
||||
//insert in the breakpoint map
|
||||
breakpoints.insert({ { info.type, info.address }, info });
|
||||
|
||||
//insert in the hardware breakpoint cache
|
||||
hardwareBreakpoints[int(slot)] = info;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type, HardwareBreakpointSize size)
|
||||
{
|
||||
//check if a callback on this address was already found
|
||||
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
||||
return false;
|
||||
//set the hardware breakpoint
|
||||
if (!SetHardwareBreakpoint(address, slot, type, size))
|
||||
return false;
|
||||
//insert the callback
|
||||
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -9,5 +9,7 @@ namespace GleeBug
|
|||
thread(nullptr),
|
||||
systemBreakpoint(false)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
hardwareBreakpoints[i].enabled = false;
|
||||
}
|
||||
};
|
||||
|
|
@ -21,11 +21,11 @@ namespace GleeBug
|
|||
ThreadInfo* thread;
|
||||
bool systemBreakpoint;
|
||||
|
||||
ThreadMap threads;
|
||||
ThreadMap threads; //DO NOT COPY THESE OBJECTS!
|
||||
DllMap dlls;
|
||||
BreakpointMap breakpoints;
|
||||
BreakpointCallbackMap breakpointCallbacks;
|
||||
BreakpointInfo restoreSoftwareBreakpoint;
|
||||
BreakpointInfo hardwareBreakpoints[4];
|
||||
|
||||
/**
|
||||
\brief Constructor.
|
||||
|
|
@ -62,7 +62,7 @@ namespace GleeBug
|
|||
|
||||
/**
|
||||
\brief Sets a software breakpoint.
|
||||
\param address The address to put the breakpoint on.
|
||||
\param address The address to set the breakpoint on.
|
||||
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
|
||||
\param type (Optional) The software breakpoint type.
|
||||
\return true if the breakpoint was set, false otherwise.
|
||||
|
|
@ -71,7 +71,7 @@ namespace GleeBug
|
|||
|
||||
/**
|
||||
\brief Sets a software breakpoint.
|
||||
\param address The address to put the breakpoint on.
|
||||
\param address The address to set the breakpoint on.
|
||||
\param cbBreakpoint The breakpoint callback. Can be written using BIND1(this, MyDebugger::cb).
|
||||
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
|
||||
\param type (Optional) The software breakpoint type.
|
||||
|
|
@ -82,7 +82,7 @@ namespace GleeBug
|
|||
/**
|
||||
\brief Sets a software breakpoint.
|
||||
\tparam T Generic type parameter. Must be a subclass of Debugger.
|
||||
\param address The address to put the breakpoint on.
|
||||
\param address The address to set the breakpoint on.
|
||||
\param debugger This pointer to a subclass of Debugger.
|
||||
\param callback Pointer to the callback. Written like: &MyDebugger::cb
|
||||
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
|
||||
|
|
@ -95,6 +95,34 @@ namespace GleeBug
|
|||
static_cast<void>(static_cast<Debugger*>(debugger));
|
||||
return SetBreakpoint(address, std::bind(callback, debugger, std::placeholders::_1), singleshoot, type);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Attempts to find a free hardware breakpoint slot.
|
||||
\param [out] slot First free slot found, has no meaning when the function fails.
|
||||
\return true if a free slot was found, false otherwise.
|
||||
*/
|
||||
bool GetFreeHardwareBreakpointSlot(HardwareBreakpointSlot & slot);
|
||||
|
||||
/**
|
||||
\brief Sets a hardware breakpoint.
|
||||
\param address The address to set the hardware breakpoint on.
|
||||
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
||||
\param type The hardware breakpoint type.
|
||||
\param size The hardware breakpoint size.
|
||||
\return true if the hardware breakpoint was set, false otherwise.
|
||||
*/
|
||||
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte);
|
||||
|
||||
/**
|
||||
\brief Sets a hardware breakpoint.
|
||||
\param address The address to set the hardware breakpoint on.
|
||||
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
||||
\param cbBreakpoint The breakpoint callback. Can be written using BIND1(this, MyDebugger::cb).
|
||||
\param type The hardware breakpoint type.
|
||||
\param size The hardware breakpoint size.
|
||||
\return true if the hardware breakpoint was set, false otherwise.
|
||||
*/
|
||||
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,250 @@
|
|||
#include "Debugger.Thread.h"
|
||||
|
||||
#define BITSET(a,x) (a|=1<<x)
|
||||
#define BITCLEAR(a,x) (a&=~(1<<x))
|
||||
#define BITTOGGLE(a,x) (a^=1<<x)
|
||||
#define BITGET(a,x) (a&(1<<x))
|
||||
|
||||
namespace GleeBug
|
||||
{
|
||||
enum DR7_MODE
|
||||
{
|
||||
MODE_DISABLED = 0, //00
|
||||
MODE_LOCAL = 1, //01
|
||||
MODE_GLOBAL = 2 //10
|
||||
};
|
||||
|
||||
enum DR7_TYPE
|
||||
{
|
||||
TYPE_EXECUTE = 0, //00
|
||||
TYPE_WRITE = 1, //01
|
||||
TYPE_READWRITE = 3 //11
|
||||
};
|
||||
|
||||
enum DR7_SIZE
|
||||
{
|
||||
SIZE_1 = 0, //00
|
||||
SIZE_2 = 1, //01
|
||||
SIZE_8 = 2, //10
|
||||
SIZE_4 = 3 //11
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct DR7
|
||||
{
|
||||
BYTE DR7_MODE[4];
|
||||
BYTE DR7_TYPE[4];
|
||||
BYTE DR7_SIZE[4];
|
||||
};
|
||||
|
||||
static inline ptr dr7_ptr(const DR7 & dr7)
|
||||
{
|
||||
ptr result = 0;
|
||||
if (BITGET(dr7.DR7_MODE[0], 0))
|
||||
BITSET(result, 0);
|
||||
if (BITGET(dr7.DR7_MODE[0], 1))
|
||||
BITSET(result, 1);
|
||||
if (BITGET(dr7.DR7_MODE[1], 0))
|
||||
BITSET(result, 2);
|
||||
if (BITGET(dr7.DR7_MODE[1], 1))
|
||||
BITSET(result, 3);
|
||||
if (BITGET(dr7.DR7_MODE[2], 0))
|
||||
BITSET(result, 4);
|
||||
if (BITGET(dr7.DR7_MODE[2], 1))
|
||||
BITSET(result, 5);
|
||||
if (BITGET(dr7.DR7_MODE[3], 0))
|
||||
BITSET(result, 6);
|
||||
if (BITGET(dr7.DR7_MODE[3], 1))
|
||||
BITSET(result, 7);
|
||||
if (BITGET(dr7.DR7_TYPE[0], 0))
|
||||
BITSET(result, 16);
|
||||
if (BITGET(dr7.DR7_TYPE[0], 1))
|
||||
BITSET(result, 17);
|
||||
if (BITGET(dr7.DR7_SIZE[0], 0))
|
||||
BITSET(result, 18);
|
||||
if (BITGET(dr7.DR7_SIZE[0], 1))
|
||||
BITSET(result, 19);
|
||||
if (BITGET(dr7.DR7_TYPE[1], 0))
|
||||
BITSET(result, 20);
|
||||
if (BITGET(dr7.DR7_TYPE[1], 1))
|
||||
BITSET(result, 21);
|
||||
if (BITGET(dr7.DR7_SIZE[1], 0))
|
||||
BITSET(result, 22);
|
||||
if (BITGET(dr7.DR7_SIZE[1], 1))
|
||||
BITSET(result, 23);
|
||||
if (BITGET(dr7.DR7_TYPE[2], 0))
|
||||
BITSET(result, 24);
|
||||
if (BITGET(dr7.DR7_TYPE[2], 1))
|
||||
BITSET(result, 25);
|
||||
if (BITGET(dr7.DR7_SIZE[2], 0))
|
||||
BITSET(result, 26);
|
||||
if (BITGET(dr7.DR7_SIZE[2], 1))
|
||||
BITSET(result, 27);
|
||||
if (BITGET(dr7.DR7_TYPE[3], 0))
|
||||
BITSET(result, 28);
|
||||
if (BITGET(dr7.DR7_TYPE[3], 1))
|
||||
BITSET(result, 29);
|
||||
if (BITGET(dr7.DR7_SIZE[3], 0))
|
||||
BITSET(result, 30);
|
||||
if (BITGET(dr7.DR7_SIZE[3], 1))
|
||||
BITSET(result, 31);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline DR7 ptr_dr7(ptr dr7)
|
||||
{
|
||||
DR7 result;
|
||||
memset(&result, 0, sizeof(DR7));
|
||||
if (BITGET(dr7, 0))
|
||||
BITSET(result.DR7_MODE[0], 0);
|
||||
if (BITGET(dr7, 1))
|
||||
BITSET(result.DR7_MODE[0], 1);
|
||||
if (BITGET(dr7, 2))
|
||||
BITSET(result.DR7_MODE[1], 0);
|
||||
if (BITGET(dr7, 3))
|
||||
BITSET(result.DR7_MODE[1], 1);
|
||||
if (BITGET(dr7, 4))
|
||||
BITSET(result.DR7_MODE[2], 0);
|
||||
if (BITGET(dr7, 5))
|
||||
BITSET(result.DR7_MODE[2], 1);
|
||||
if (BITGET(dr7, 6))
|
||||
BITSET(result.DR7_MODE[3], 0);
|
||||
if (BITGET(dr7, 7))
|
||||
BITSET(result.DR7_MODE[3], 1);
|
||||
if (BITGET(dr7, 16))
|
||||
BITSET(result.DR7_TYPE[0], 0);
|
||||
if (BITGET(dr7, 17))
|
||||
BITSET(result.DR7_TYPE[0], 1);
|
||||
if (BITGET(dr7, 18))
|
||||
BITSET(result.DR7_SIZE[0], 0);
|
||||
if (BITGET(dr7, 19))
|
||||
BITSET(result.DR7_SIZE[0], 1);
|
||||
if (BITGET(dr7, 20))
|
||||
BITSET(result.DR7_TYPE[1], 0);
|
||||
if (BITGET(dr7, 21))
|
||||
BITSET(result.DR7_TYPE[1], 1);
|
||||
if (BITGET(dr7, 22))
|
||||
BITSET(result.DR7_SIZE[1], 0);
|
||||
if (BITGET(dr7, 23))
|
||||
BITSET(result.DR7_SIZE[1], 1);
|
||||
if (BITGET(dr7, 24))
|
||||
BITSET(result.DR7_TYPE[2], 0);
|
||||
if (BITGET(dr7, 25))
|
||||
BITSET(result.DR7_TYPE[2], 1);
|
||||
if (BITGET(dr7, 26))
|
||||
BITSET(result.DR7_SIZE[2], 0);
|
||||
if (BITGET(dr7, 27))
|
||||
BITSET(result.DR7_SIZE[2], 1);
|
||||
if (BITGET(dr7, 28))
|
||||
BITSET(result.DR7_TYPE[3], 0);
|
||||
if (BITGET(dr7, 29))
|
||||
BITSET(result.DR7_TYPE[3], 1);
|
||||
if (BITGET(dr7, 30))
|
||||
BITSET(result.DR7_SIZE[3], 0);
|
||||
if (BITGET(dr7, 31))
|
||||
BITSET(result.DR7_SIZE[3], 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline DR7_SIZE size_dr7(HardwareBreakpointSize size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case HardwareBreakpointSize::SizeByte:
|
||||
return SIZE_1;
|
||||
case HardwareBreakpointSize::SizeWord:
|
||||
return SIZE_2;
|
||||
case HardwareBreakpointSize::SizeDword:
|
||||
return SIZE_4;
|
||||
#ifdef _WIN64
|
||||
case HardwareBreakpointSize::SizeQword:
|
||||
return SIZE_8;
|
||||
#endif //_WIN64
|
||||
default:
|
||||
return SIZE_1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline DR7_TYPE type_dr7(HardwareBreakpointType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case HardwareBreakpointType::Access:
|
||||
return TYPE_READWRITE;
|
||||
case HardwareBreakpointType::Write:
|
||||
return TYPE_WRITE;
|
||||
case HardwareBreakpointType::Execute:
|
||||
return TYPE_EXECUTE;
|
||||
default:
|
||||
return TYPE_EXECUTE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size)
|
||||
{
|
||||
//check if the alignment is correct
|
||||
if ((address % int(size) != 0))
|
||||
return false;
|
||||
|
||||
//set the address register
|
||||
switch (slot)
|
||||
{
|
||||
case HardwareBreakpointSlot::Dr0:
|
||||
registers.Dr0 = address;
|
||||
break;
|
||||
case HardwareBreakpointSlot::Dr1:
|
||||
registers.Dr1 = address;
|
||||
break;
|
||||
case HardwareBreakpointSlot::Dr2:
|
||||
registers.Dr2 = address;
|
||||
break;
|
||||
case HardwareBreakpointSlot::Dr3:
|
||||
registers.Dr3 = address;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
//set the Dr7 register
|
||||
auto dr7 = ptr_dr7(registers.Dr7());
|
||||
auto index = int(slot);
|
||||
dr7.DR7_MODE[index] = MODE_LOCAL;
|
||||
dr7.DR7_SIZE[index] = size_dr7(size);
|
||||
dr7.DR7_TYPE[index] = type_dr7(type);
|
||||
registers.Dr7 = dr7_ptr(dr7);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadInfo::DeleteHardwareBreakpoint(HardwareBreakpointSlot slot)
|
||||
{
|
||||
//zero the address register
|
||||
switch (slot)
|
||||
{
|
||||
case HardwareBreakpointSlot::Dr0:
|
||||
registers.Dr0 = 0;
|
||||
break;
|
||||
case HardwareBreakpointSlot::Dr1:
|
||||
registers.Dr1 = 0;
|
||||
break;
|
||||
case HardwareBreakpointSlot::Dr2:
|
||||
registers.Dr2 = 0;
|
||||
break;
|
||||
case HardwareBreakpointSlot::Dr3:
|
||||
registers.Dr3 = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
//set the Dr7 register
|
||||
auto dr7 = ptr_dr7(registers.Dr7());
|
||||
auto index = int(slot);
|
||||
dr7.DR7_MODE[index] = MODE_DISABLED;
|
||||
dr7.DR7_SIZE[index] = SIZE_1;
|
||||
dr7.DR7_TYPE[index] = TYPE_EXECUTE;
|
||||
registers.Dr7 = dr7_ptr(dr7);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Debugger.Global.h"
|
||||
#include "Debugger.Thread.Registers.h"
|
||||
#include "Debugger.Breakpoint.h"
|
||||
|
||||
namespace GleeBug
|
||||
{
|
||||
|
|
@ -99,6 +100,23 @@ namespace GleeBug
|
|||
StepInternal(std::bind(callback, debugger));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets a hardware breakpoint.
|
||||
\param address The address to set the hardware breakpoint on.
|
||||
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
||||
\param type The hardware breakpoint type.
|
||||
\param size The hardware breakpoint size.
|
||||
\return true if the hardware breakpoint was set, false otherwise.
|
||||
*/
|
||||
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size);
|
||||
|
||||
/**
|
||||
\brief Deletes a hardware breakpoint.
|
||||
\param slot The slot to remove the hardware breakpoint from.
|
||||
\return true if the hardware breakpoint was deleted, false otherwise.
|
||||
*/
|
||||
bool DeleteHardwareBreakpoint(HardwareBreakpointSlot slot);
|
||||
|
||||
private:
|
||||
CONTEXT _oldContext;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -106,6 +106,12 @@ namespace GleeBug
|
|||
*/
|
||||
virtual void cbRipEvent(const RIP_INFO & rip) {};
|
||||
|
||||
/**
|
||||
\brief Unknown event callback. Called before the event is internally processed. Provide an implementation to use this callback.
|
||||
\param debugEventCode The debug event code.
|
||||
*/
|
||||
virtual void cbUnknownEvent(DWORD debugEventCode) {};
|
||||
|
||||
protected: //other callbacks
|
||||
/**
|
||||
\brief Internal error callback. Provide an implementation to use this callback.
|
||||
|
|
@ -191,6 +197,12 @@ namespace GleeBug
|
|||
*/
|
||||
virtual void ripEvent(const RIP_INFO & rip);
|
||||
|
||||
/**
|
||||
\brief Unknown event. Do not override this unless you know what you are doing!
|
||||
\param debugEventCode The debug event code.
|
||||
*/
|
||||
virtual void unknownEvent(DWORD debugEventCode);
|
||||
|
||||
protected: //core exception handlers
|
||||
/**
|
||||
\brief Breakpoint exception handler. Do not override this unless you know what you are doing!
|
||||
|
|
@ -206,6 +218,12 @@ namespace GleeBug
|
|||
*/
|
||||
virtual void exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, bool firstChance);
|
||||
|
||||
/**
|
||||
\brief Hardware breakpoint (single step) exception handler. Do not override this unless you know what you are doing!
|
||||
\param exceptionAddress The exception address.
|
||||
*/
|
||||
virtual void exceptionHardwareBreakpoint(ptr exceptionAddress);
|
||||
|
||||
protected: //variables
|
||||
PROCESS_INFORMATION _mainProcess;
|
||||
uint32 _continueStatus;
|
||||
|
|
|
|||
|
|
@ -155,10 +155,12 @@
|
|||
<ClCompile Include="Debugger.Loop.Process.cpp" />
|
||||
<ClCompile Include="Debugger.Loop.Rip.cpp" />
|
||||
<ClCompile Include="Debugger.Loop.Thread.cpp" />
|
||||
<ClCompile Include="Debugger.Loop.Unknown.cpp" />
|
||||
<ClCompile Include="Debugger.Process.Breakpoint.cpp" />
|
||||
<ClCompile Include="Debugger.Process.cpp" />
|
||||
<ClCompile Include="Debugger.Process.Memory.cpp" />
|
||||
<ClCompile Include="Debugger.Thread.cpp" />
|
||||
<ClCompile Include="Debugger.Thread.HardwareBreakpoint.cpp" />
|
||||
<ClCompile Include="Debugger.Thread.Registers.cpp" />
|
||||
<ClCompile Include="Debugger.Thread.Registers.GetSet.cpp" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<ClCompile Include="Debugger.Process.Breakpoint.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger.Loop.Unknown.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger.Thread.HardwareBreakpoint.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger.h">
|
||||
|
|
|
|||
|
|
@ -19,16 +19,38 @@ protected:
|
|||
}));
|
||||
}
|
||||
|
||||
void cbEntryHardwareBreakpoint(const BreakpointInfo & info)
|
||||
{
|
||||
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
|
||||
_registers->Gip());
|
||||
_thread->StepInto(std::bind([this]()
|
||||
{
|
||||
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
|
||||
_registers->Gip());
|
||||
}));
|
||||
}
|
||||
|
||||
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) override
|
||||
{
|
||||
ptr entry = ptr(createProcess.lpStartAddress);
|
||||
printf("Process %d created with entry 0x%p\n",
|
||||
_debugEvent.dwProcessId,
|
||||
entry);
|
||||
if(_process->SetBreakpoint(entry, this, &MyDebugger::cbEntryBreakpoint))
|
||||
HardwareBreakpointSlot slot;
|
||||
if (_process->GetFreeHardwareBreakpointSlot(slot))
|
||||
{
|
||||
if (_process->SetHardwareBreakpoint(entry, slot, BIND1(this, MyDebugger::cbEntryHardwareBreakpoint), HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte))
|
||||
printf("Hardware breakpoint set at 0x%p!\n", entry);
|
||||
else
|
||||
printf("Failed to set hardware breakpoint at 0x%p\n", entry);
|
||||
}
|
||||
else
|
||||
printf("No free hardware breakpoint slot...\n");
|
||||
|
||||
/*if(_process->SetBreakpoint(entry, this, &MyDebugger::cbEntryBreakpoint))
|
||||
printf("Breakpoint set at 0x%p!\n", entry);
|
||||
else
|
||||
printf("Failed to set breakpoint at 0x%p...\b", entry);
|
||||
printf("Failed to set breakpoint at 0x%p...\b", entry);*/
|
||||
}
|
||||
|
||||
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override
|
||||
|
|
@ -96,7 +118,7 @@ protected:
|
|||
void cbSystemBreakpoint() override
|
||||
{
|
||||
printf("System breakpoint reached, GIP: 0x%p\n",
|
||||
_registers->Gip.Get());
|
||||
_registers->Gip());
|
||||
_thread->StepInto(this, &MyDebugger::cbStepSystem);
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +133,15 @@ protected:
|
|||
printf("Breakpoint on 0x%p!\n",
|
||||
info.address);
|
||||
}
|
||||
|
||||
void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) override
|
||||
{
|
||||
printf("Unhandled exception (%s) 0x%08X on 0x%p, GIP: 0x%p\n",
|
||||
firstChance ? "first chance" : "second chance",
|
||||
exceptionRecord.ExceptionCode,
|
||||
exceptionRecord.ExceptionAddress,
|
||||
_registers->Gip());
|
||||
}
|
||||
};
|
||||
|
||||
#endif //_MYDEBUGGER_H
|
||||
Loading…
Reference in New Issue