mirror of https://github.com/x64dbg/GleeBug
singleshoot hardware/software breakpoints working + delete hardware/software breakpoints + nice callback set function for hardware breakpoints
This commit is contained in:
parent
611c5864ca
commit
439fd82767
|
|
@ -19,7 +19,7 @@ namespace GleeBug
|
||||||
auto foundInfo = _process->breakpoints.find({ BreakpointType::Software, ptr(exceptionRecord.ExceptionAddress) });
|
auto foundInfo = _process->breakpoints.find({ BreakpointType::Software, ptr(exceptionRecord.ExceptionAddress) });
|
||||||
if (foundInfo == _process->breakpoints.end())
|
if (foundInfo == _process->breakpoints.end())
|
||||||
return;
|
return;
|
||||||
const auto & info = foundInfo->second;
|
const auto info = foundInfo->second;
|
||||||
|
|
||||||
//set continue status
|
//set continue status
|
||||||
_continueStatus = DBG_CONTINUE;
|
_continueStatus = DBG_CONTINUE;
|
||||||
|
|
@ -31,6 +31,8 @@ namespace GleeBug
|
||||||
_process->MemWrite(info.address, info.internal.software.oldbytes, info.internal.software.size);
|
_process->MemWrite(info.address, info.internal.software.oldbytes, info.internal.software.size);
|
||||||
_thread->StepInternal(std::bind([this, info]()
|
_thread->StepInternal(std::bind([this, info]()
|
||||||
{
|
{
|
||||||
|
//only restore the bytes if the breakpoint still exists
|
||||||
|
if (_process->breakpoints.find({ BreakpointType::Software, info.address }) != _process->breakpoints.end())
|
||||||
_process->MemWrite(info.address, info.internal.software.newbytes, info.internal.software.size);
|
_process->MemWrite(info.address, info.internal.software.newbytes, info.internal.software.size);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -41,6 +43,10 @@ namespace GleeBug
|
||||||
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Software, info.address });
|
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Software, info.address });
|
||||||
if (foundCallback != _process->breakpointCallbacks.end())
|
if (foundCallback != _process->breakpointCallbacks.end())
|
||||||
foundCallback->second(info);
|
foundCallback->second(info);
|
||||||
|
|
||||||
|
//delete the breakpoint if it is singleshoot
|
||||||
|
if (info.singleshoot)
|
||||||
|
_process->DeleteGenericBreakpoint(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,17 +115,19 @@ namespace GleeBug
|
||||||
auto foundInfo = _process->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
auto foundInfo = _process->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
||||||
if (foundInfo == _process->breakpoints.end())
|
if (foundInfo == _process->breakpoints.end())
|
||||||
return; //not a valid hardware breakpoint
|
return; //not a valid hardware breakpoint
|
||||||
const auto & info = foundInfo->second;
|
const auto info = foundInfo->second;
|
||||||
if (info.internal.hardware.slot != breakpointSlot)
|
if (info.internal.hardware.slot != breakpointSlot)
|
||||||
return; //not a valid hardware breakpoint
|
return; //not a valid hardware breakpoint
|
||||||
|
|
||||||
//set continue status
|
//set continue status
|
||||||
_continueStatus = DBG_CONTINUE;
|
_continueStatus = DBG_CONTINUE;
|
||||||
|
|
||||||
//delete the hardware breakpoint and do an internal step (TODO: maybe delete from all threads?)
|
//delete the hardware breakpoint from the thread (not the breakpoint buffer) and do an internal step (TODO: maybe delete from all threads?)
|
||||||
_thread->DeleteHardwareBreakpoint(breakpointSlot);
|
_thread->DeleteHardwareBreakpoint(breakpointSlot);
|
||||||
_thread->StepInternal(std::bind([this, info]()
|
_thread->StepInternal(std::bind([this, info]()
|
||||||
{
|
{
|
||||||
|
//only restore if the breakpoint still exists
|
||||||
|
if (_process->breakpoints.find({ BreakpointType::Hardware, info.address }) != _process->breakpoints.end())
|
||||||
_thread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
_thread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -130,6 +138,10 @@ namespace GleeBug
|
||||||
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
||||||
if (foundCallback != _process->breakpointCallbacks.end())
|
if (foundCallback != _process->breakpointCallbacks.end())
|
||||||
foundCallback->second(info);
|
foundCallback->second(info);
|
||||||
|
|
||||||
|
//delete the breakpoint if it is singleshoot
|
||||||
|
if (info.singleshoot)
|
||||||
|
_process->DeleteGenericBreakpoint(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//check the address
|
//check the address
|
||||||
if (!MemIsValidPtr(address) ||
|
if (!MemIsValidPtr(address) ||
|
||||||
breakpoints.find({BreakpointType::Software, address}) != breakpoints.end())
|
breakpoints.find({ BreakpointType::Software, address }) != breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//setup the breakpoint information struct
|
//setup the breakpoint information struct
|
||||||
|
|
@ -55,6 +55,28 @@ namespace GleeBug
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessInfo::DeleteBreakpoint(ptr address)
|
||||||
|
{
|
||||||
|
//find the breakpoint
|
||||||
|
auto found = breakpoints.find({ BreakpointType::Software, address });
|
||||||
|
if (found == breakpoints.end())
|
||||||
|
return false;
|
||||||
|
const auto & info = found->second;
|
||||||
|
|
||||||
|
//restore the breakpoint bytes if the breakpoint is enabled
|
||||||
|
if (info.enabled)
|
||||||
|
{
|
||||||
|
if (!MemWrite(address, info.internal.software.oldbytes, info.internal.software.size))
|
||||||
|
return false;
|
||||||
|
FlushInstructionCache(hProcess, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove the breakpoint from the maps
|
||||||
|
breakpoints.erase(found);
|
||||||
|
breakpointCallbacks.erase({ BreakpointType::Software, address });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProcessInfo::GetFreeHardwareBreakpointSlot(HardwareBreakpointSlot & slot) const
|
bool ProcessInfo::GetFreeHardwareBreakpointSlot(HardwareBreakpointSlot & slot) const
|
||||||
{
|
{
|
||||||
//find a free hardware breakpoint slot
|
//find a free hardware breakpoint slot
|
||||||
|
|
@ -69,7 +91,7 @@ namespace GleeBug
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size)
|
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size, bool singleshoot)
|
||||||
{
|
{
|
||||||
//check the address
|
//check the address
|
||||||
if (!MemIsValidPtr(address) ||
|
if (!MemIsValidPtr(address) ||
|
||||||
|
|
@ -99,7 +121,7 @@ namespace GleeBug
|
||||||
BreakpointInfo info = {};
|
BreakpointInfo info = {};
|
||||||
info.address = address;
|
info.address = address;
|
||||||
info.enabled = true;
|
info.enabled = true;
|
||||||
info.singleshoot = false;
|
info.singleshoot = singleshoot;
|
||||||
info.type = BreakpointType::Hardware;
|
info.type = BreakpointType::Hardware;
|
||||||
info.internal.hardware.slot = slot;
|
info.internal.hardware.slot = slot;
|
||||||
info.internal.hardware.type = type;
|
info.internal.hardware.type = type;
|
||||||
|
|
@ -114,16 +136,56 @@ namespace GleeBug
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type, HardwareBreakpointSize size)
|
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type, HardwareBreakpointSize size, bool singleshoot)
|
||||||
{
|
{
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
||||||
return false;
|
return false;
|
||||||
//set the hardware breakpoint
|
//set the hardware breakpoint
|
||||||
if (!SetHardwareBreakpoint(address, slot, type, size))
|
if (!SetHardwareBreakpoint(address, slot, type, size, singleshoot))
|
||||||
return false;
|
return false;
|
||||||
//insert the callback
|
//insert the callback
|
||||||
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
|
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProcessInfo::DeleteHardwareBreakpoint(ptr address)
|
||||||
|
{
|
||||||
|
//find the hardware breakpoint
|
||||||
|
auto found = breakpoints.find({ BreakpointType::Hardware, address });
|
||||||
|
if (found == breakpoints.end())
|
||||||
|
return false;
|
||||||
|
const auto & info = found->second;
|
||||||
|
|
||||||
|
//delete the hardware breakpoint from the internal buffer
|
||||||
|
hardwareBreakpoints[int(info.internal.hardware.slot)].enabled = false;
|
||||||
|
|
||||||
|
//delete the hardware breakpoint from the registers
|
||||||
|
bool success = true;
|
||||||
|
for (auto & thread : threads)
|
||||||
|
{
|
||||||
|
if (!thread.second.DeleteHardwareBreakpoint(info.internal.hardware.slot))
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete the breakpoint from the maps
|
||||||
|
breakpoints.erase(found);
|
||||||
|
breakpointCallbacks.erase({ BreakpointType::Hardware, address });
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessInfo::DeleteGenericBreakpoint(const BreakpointInfo & info)
|
||||||
|
{
|
||||||
|
switch (info.type)
|
||||||
|
{
|
||||||
|
case BreakpointType::Software:
|
||||||
|
return DeleteBreakpoint(info.address);
|
||||||
|
case BreakpointType::Hardware:
|
||||||
|
return DeleteHardwareBreakpoint(info.address);
|
||||||
|
case BreakpointType::Memory:
|
||||||
|
return false; //TODO implement this
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -96,6 +96,13 @@ namespace GleeBug
|
||||||
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 Deletes a software breakpoint.
|
||||||
|
\param address The address to delete the breakpoint from.
|
||||||
|
\return true if the breakpoint was deleted, false otherwise.
|
||||||
|
*/
|
||||||
|
bool DeleteBreakpoint(ptr address);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Attempts to find a free hardware breakpoint slot.
|
\brief Attempts to find a free hardware breakpoint slot.
|
||||||
\param [out] slot First free slot found, has no meaning when the function fails.
|
\param [out] slot First free slot found, has no meaning when the function fails.
|
||||||
|
|
@ -107,22 +114,57 @@ namespace GleeBug
|
||||||
\brief Sets a hardware breakpoint.
|
\brief Sets a hardware breakpoint.
|
||||||
\param address The address to set the hardware breakpoint on.
|
\param address The address to set the hardware breakpoint on.
|
||||||
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
||||||
\param type The hardware breakpoint type.
|
\param type (Optional) The hardware breakpoint type.
|
||||||
\param size The hardware breakpoint size.
|
\param size (Optional) The hardware breakpoint size.
|
||||||
|
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
|
||||||
\return true if the hardware breakpoint was set, false otherwise.
|
\return true if the hardware breakpoint was set, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte);
|
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte, bool singleshoot = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets a hardware breakpoint.
|
\brief Sets a hardware breakpoint.
|
||||||
\param address The address to set the hardware breakpoint on.
|
\param address The address to set the hardware breakpoint on.
|
||||||
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
||||||
\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 type The hardware breakpoint type.
|
\param type (Optional) The hardware breakpoint type.
|
||||||
\param size The hardware breakpoint size.
|
\param size (Optional) The hardware breakpoint size.
|
||||||
|
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
|
||||||
\return true if the hardware breakpoint was set, false otherwise.
|
\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);
|
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte, bool singleshoot = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Sets a hardware breakpoint.
|
||||||
|
\tparam T Generic type parameter. Must be a subclass of Debugger.
|
||||||
|
\param address The address to set the hardware breakpoint on.
|
||||||
|
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
|
||||||
|
\param debugger This pointer to a subclass of Debugger.
|
||||||
|
\param callback Pointer to the callback. Written like: &MyDebugger::cb
|
||||||
|
\param type (Optional) The hardware breakpoint type.
|
||||||
|
\param size (Optional) The hardware breakpoint size.
|
||||||
|
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
|
||||||
|
\return true if the hardware breakpoint was set, false otherwise.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, T* debugger, void(T::*callback)(const BreakpointInfo & info), HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte, bool singleshoot = false)
|
||||||
|
{
|
||||||
|
static_cast<void>(static_cast<Debugger*>(debugger));
|
||||||
|
return SetHardwareBreakpoint(address, slot, std::bind(callback, debugger, std::placeholders::_1), type, size, singleshoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Deletes a hardware breakpoint.
|
||||||
|
\param address The address the hardware breakpoint is set on.
|
||||||
|
\return true if the hardware breakpoint was deleted, false otherwise.
|
||||||
|
*/
|
||||||
|
bool DeleteHardwareBreakpoint(ptr address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Deletes a breakpoint.
|
||||||
|
\param info The breakpoint information.
|
||||||
|
\return true if the breakpoint was deleted, false otherwise.
|
||||||
|
*/
|
||||||
|
bool DeleteGenericBreakpoint(const BreakpointInfo & info);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ protected:
|
||||||
{
|
{
|
||||||
printf("Reached entry breakpoint! GIP: 0x%p\n",
|
printf("Reached entry breakpoint! GIP: 0x%p\n",
|
||||||
_registers->Gip());
|
_registers->Gip());
|
||||||
|
if (_process->DeleteBreakpoint(info.address))
|
||||||
|
printf("Entry breakpoint deleted!\n");
|
||||||
|
else
|
||||||
|
printf("Failed to delete entry breakpoint...\n");
|
||||||
_thread->StepInto(std::bind([this]()
|
_thread->StepInto(std::bind([this]()
|
||||||
{
|
{
|
||||||
printf("Step after entry breakpoint! GIP: 0x%p\n",
|
printf("Step after entry breakpoint! GIP: 0x%p\n",
|
||||||
|
|
@ -23,6 +27,10 @@ protected:
|
||||||
{
|
{
|
||||||
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
|
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
|
||||||
_registers->Gip());
|
_registers->Gip());
|
||||||
|
if (_process->DeleteHardwareBreakpoint(info.address))
|
||||||
|
printf("Entry hardware breakpoint deleted!\n");
|
||||||
|
else
|
||||||
|
printf("Failed to delete entry hardware breakpoint...\n");
|
||||||
_thread->StepInto(std::bind([this]()
|
_thread->StepInto(std::bind([this]()
|
||||||
{
|
{
|
||||||
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
|
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
|
||||||
|
|
@ -45,7 +53,7 @@ protected:
|
||||||
HardwareBreakpointSlot slot;
|
HardwareBreakpointSlot slot;
|
||||||
if (_process->GetFreeHardwareBreakpointSlot(slot))
|
if (_process->GetFreeHardwareBreakpointSlot(slot))
|
||||||
{
|
{
|
||||||
if (_process->SetHardwareBreakpoint(entry, slot, BIND1(this, MyDebugger::cbEntryHardwareBreakpoint), HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte))
|
if (_process->SetHardwareBreakpoint(entry, slot, this, &MyDebugger::cbEntryHardwareBreakpoint, HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte))
|
||||||
printf("Hardware breakpoint set at 0x%p!\n", entry);
|
printf("Hardware breakpoint set at 0x%p!\n", entry);
|
||||||
else
|
else
|
||||||
printf("Failed to set hardware breakpoint at 0x%p\n", entry);
|
printf("Failed to set hardware breakpoint at 0x%p\n", entry);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue