hardware breakpoints working + fixed possible bug with breakpoints + added unknownEvent callback + added cbUnhandledException in MyDebugger

This commit is contained in:
Mr. eXoDia 2015-09-11 15:46:31 +02:00
parent 26c71cc6e4
commit 3bde590956
13 changed files with 528 additions and 17 deletions

View File

@ -17,6 +17,14 @@ namespace GleeBug
ShortInt3 ShortInt3
}; };
enum class HardwareBreakpointSlot
{
Dr0 = 0,
Dr1 = 1,
Dr2 = 2,
Dr3 = 3
};
enum class HardwareBreakpointType enum class HardwareBreakpointType
{ {
Access, Access,
@ -26,11 +34,11 @@ namespace GleeBug
enum class HardwareBreakpointSize enum class HardwareBreakpointSize
{ {
SizeByte, SizeByte = 1,
SizeWord, SizeWord = 2,
SizeDword, SizeDword = 4,
#ifdef _WIN64 #ifdef _WIN64
SizeQword SizeQword = 8
#endif //_WIN64 #endif //_WIN64
}; };
@ -54,6 +62,7 @@ namespace GleeBug
} software; } software;
struct struct
{ {
HardwareBreakpointSlot slot;
HardwareBreakpointType type; HardwareBreakpointType type;
HardwareBreakpointSize size; HardwareBreakpointSize size;
} hardware; } hardware;

View File

@ -70,11 +70,68 @@ namespace GleeBug
for (auto cbStep : cbStepCopy) for (auto cbStep : cbStepCopy)
cbStep(); 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) void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{ {
//let the debuggee handle exceptions per default //let the debuggee handle exceptions per default

View File

@ -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);
}
};

View File

@ -78,6 +78,9 @@ namespace GleeBug
case RIP_EVENT: case RIP_EVENT:
ripEvent(_debugEvent.u.RipInfo); ripEvent(_debugEvent.u.RipInfo);
break; break;
default:
unknownEvent(_debugEvent.dwDebugEventCode);
break;
} }
//write the register context //write the register context

View File

@ -44,12 +44,86 @@ namespace GleeBug
bool ProcessInfo::SetBreakpoint(ptr address, const BreakpointCallback & cbBreakpoint, bool singleshoot, SoftwareBreakpointType type) 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)) if (!SetBreakpoint(address, singleshoot, type))
return false; return false;
auto found = breakpointCallbacks.find({ BreakpointType::Software, address }); //insert the callback
if (found != breakpointCallbacks.end())
return false;
breakpointCallbacks.insert({ { BreakpointType::Software, address }, cbBreakpoint }); breakpointCallbacks.insert({ { BreakpointType::Software, address }, cbBreakpoint });
return true; 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;
}
}; };

View File

@ -9,5 +9,7 @@ namespace GleeBug
thread(nullptr), thread(nullptr),
systemBreakpoint(false) systemBreakpoint(false)
{ {
for (int i = 0; i < 4; i++)
hardwareBreakpoints[i].enabled = false;
} }
}; };

View File

@ -21,11 +21,11 @@ namespace GleeBug
ThreadInfo* thread; ThreadInfo* thread;
bool systemBreakpoint; bool systemBreakpoint;
ThreadMap threads; ThreadMap threads; //DO NOT COPY THESE OBJECTS!
DllMap dlls; DllMap dlls;
BreakpointMap breakpoints; BreakpointMap breakpoints;
BreakpointCallbackMap breakpointCallbacks; BreakpointCallbackMap breakpointCallbacks;
BreakpointInfo restoreSoftwareBreakpoint; BreakpointInfo hardwareBreakpoints[4];
/** /**
\brief Constructor. \brief Constructor.
@ -62,7 +62,7 @@ namespace GleeBug
/** /**
\brief Sets a software breakpoint. \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 singleshoot (Optional) True to remove the breakpoint after the first hit.
\param type (Optional) The software breakpoint type. \param type (Optional) The software breakpoint type.
\return true if the breakpoint was set, false otherwise. \return true if the breakpoint was set, false otherwise.
@ -71,7 +71,7 @@ namespace GleeBug
/** /**
\brief Sets a software breakpoint. \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 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 singleshoot (Optional) True to remove the breakpoint after the first hit.
\param type (Optional) The software breakpoint type. \param type (Optional) The software breakpoint type.
@ -82,7 +82,7 @@ namespace GleeBug
/** /**
\brief Sets a software breakpoint. \brief Sets a software breakpoint.
\tparam T Generic type parameter. Must be a subclass of Debugger. \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 debugger This pointer to a subclass of Debugger.
\param callback Pointer to the callback. Written like: &MyDebugger::cb \param callback Pointer to the callback. Written like: &MyDebugger::cb
\param singleshoot (Optional) True to remove the breakpoint after the first hit. \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)); static_cast<void>(static_cast<Debugger*>(debugger));
return SetBreakpoint(address, std::bind(callback, debugger, std::placeholders::_1), singleshoot, type); 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);
}; };
}; };

View File

@ -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;
}
};

View File

@ -3,6 +3,7 @@
#include "Debugger.Global.h" #include "Debugger.Global.h"
#include "Debugger.Thread.Registers.h" #include "Debugger.Thread.Registers.h"
#include "Debugger.Breakpoint.h"
namespace GleeBug namespace GleeBug
{ {
@ -99,6 +100,23 @@ namespace GleeBug
StepInternal(std::bind(callback, debugger)); 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: private:
CONTEXT _oldContext; CONTEXT _oldContext;
}; };

View File

@ -106,6 +106,12 @@ namespace GleeBug
*/ */
virtual void cbRipEvent(const RIP_INFO & rip) {}; 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 protected: //other callbacks
/** /**
\brief Internal error callback. Provide an implementation to use this callback. \brief Internal error callback. Provide an implementation to use this callback.
@ -191,6 +197,12 @@ namespace GleeBug
*/ */
virtual void ripEvent(const RIP_INFO & rip); 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 protected: //core exception handlers
/** /**
\brief Breakpoint exception handler. Do not override this unless you know what you are doing! \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); 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 protected: //variables
PROCESS_INFORMATION _mainProcess; PROCESS_INFORMATION _mainProcess;
uint32 _continueStatus; uint32 _continueStatus;

View File

@ -155,10 +155,12 @@
<ClCompile Include="Debugger.Loop.Process.cpp" /> <ClCompile Include="Debugger.Loop.Process.cpp" />
<ClCompile Include="Debugger.Loop.Rip.cpp" /> <ClCompile Include="Debugger.Loop.Rip.cpp" />
<ClCompile Include="Debugger.Loop.Thread.cpp" /> <ClCompile Include="Debugger.Loop.Thread.cpp" />
<ClCompile Include="Debugger.Loop.Unknown.cpp" />
<ClCompile Include="Debugger.Process.Breakpoint.cpp" /> <ClCompile Include="Debugger.Process.Breakpoint.cpp" />
<ClCompile Include="Debugger.Process.cpp" /> <ClCompile Include="Debugger.Process.cpp" />
<ClCompile Include="Debugger.Process.Memory.cpp" /> <ClCompile Include="Debugger.Process.Memory.cpp" />
<ClCompile Include="Debugger.Thread.cpp" /> <ClCompile Include="Debugger.Thread.cpp" />
<ClCompile Include="Debugger.Thread.HardwareBreakpoint.cpp" />
<ClCompile Include="Debugger.Thread.Registers.cpp" /> <ClCompile Include="Debugger.Thread.Registers.cpp" />
<ClCompile Include="Debugger.Thread.Registers.GetSet.cpp" /> <ClCompile Include="Debugger.Thread.Registers.GetSet.cpp" />
</ItemGroup> </ItemGroup>

View File

@ -56,6 +56,12 @@
<ClCompile Include="Debugger.Process.Breakpoint.cpp"> <ClCompile Include="Debugger.Process.Breakpoint.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </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>
<ItemGroup> <ItemGroup>
<ClInclude Include="Debugger.h"> <ClInclude Include="Debugger.h">

View File

@ -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 void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) override
{ {
ptr entry = ptr(createProcess.lpStartAddress); ptr entry = ptr(createProcess.lpStartAddress);
printf("Process %d created with entry 0x%p\n", printf("Process %d created with entry 0x%p\n",
_debugEvent.dwProcessId, _debugEvent.dwProcessId,
entry); 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); printf("Breakpoint set at 0x%p!\n", entry);
else 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 void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override
@ -96,7 +118,7 @@ protected:
void cbSystemBreakpoint() override void cbSystemBreakpoint() override
{ {
printf("System breakpoint reached, GIP: 0x%p\n", printf("System breakpoint reached, GIP: 0x%p\n",
_registers->Gip.Get()); _registers->Gip());
_thread->StepInto(this, &MyDebugger::cbStepSystem); _thread->StepInto(this, &MyDebugger::cbStepSystem);
} }
@ -111,6 +133,15 @@ protected:
printf("Breakpoint on 0x%p!\n", printf("Breakpoint on 0x%p!\n",
info.address); 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 #endif //_MYDEBUGGER_H