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) });
|
||||
if (foundInfo == _process->breakpoints.end())
|
||||
return;
|
||||
const auto & info = foundInfo->second;
|
||||
const auto info = foundInfo->second;
|
||||
|
||||
//set continue status
|
||||
_continueStatus = DBG_CONTINUE;
|
||||
|
|
@ -31,7 +31,9 @@ namespace GleeBug
|
|||
_process->MemWrite(info.address, info.internal.software.oldbytes, info.internal.software.size);
|
||||
_thread->StepInternal(std::bind([this, info]()
|
||||
{
|
||||
_process->MemWrite(info.address, info.internal.software.newbytes, info.internal.software.size);
|
||||
//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);
|
||||
}));
|
||||
|
||||
//call the generic callback
|
||||
|
|
@ -41,6 +43,10 @@ namespace GleeBug
|
|||
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Software, info.address });
|
||||
if (foundCallback != _process->breakpointCallbacks.end())
|
||||
foundCallback->second(info);
|
||||
|
||||
//delete the breakpoint if it is singleshoot
|
||||
if (info.singleshoot)
|
||||
_process->DeleteGenericBreakpoint(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,18 +115,20 @@ namespace GleeBug
|
|||
auto foundInfo = _process->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
||||
if (foundInfo == _process->breakpoints.end())
|
||||
return; //not a valid hardware breakpoint
|
||||
const auto & info = foundInfo->second;
|
||||
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?)
|
||||
//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->StepInternal(std::bind([this, info]()
|
||||
{
|
||||
_thread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
||||
//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);
|
||||
}));
|
||||
|
||||
//call the generic callback
|
||||
|
|
@ -130,6 +138,10 @@ namespace GleeBug
|
|||
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
||||
if (foundCallback != _process->breakpointCallbacks.end())
|
||||
foundCallback->second(info);
|
||||
|
||||
//delete the breakpoint if it is singleshoot
|
||||
if (info.singleshoot)
|
||||
_process->DeleteGenericBreakpoint(info);
|
||||
}
|
||||
|
||||
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace GleeBug
|
|||
{
|
||||
//check the address
|
||||
if (!MemIsValidPtr(address) ||
|
||||
breakpoints.find({BreakpointType::Software, address}) != breakpoints.end())
|
||||
breakpoints.find({ BreakpointType::Software, address }) != breakpoints.end())
|
||||
return false;
|
||||
|
||||
//setup the breakpoint information struct
|
||||
|
|
@ -15,7 +15,7 @@ namespace GleeBug
|
|||
info.enabled = true;
|
||||
info.singleshoot = singleshoot;
|
||||
info.type = BreakpointType::Software;
|
||||
|
||||
|
||||
//determine breakpoint byte and size from the type
|
||||
switch (type)
|
||||
{
|
||||
|
|
@ -55,6 +55,28 @@ namespace GleeBug
|
|||
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
|
||||
{
|
||||
//find a free hardware breakpoint slot
|
||||
|
|
@ -69,7 +91,7 @@ namespace GleeBug
|
|||
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
|
||||
if (!MemIsValidPtr(address) ||
|
||||
|
|
@ -99,7 +121,7 @@ namespace GleeBug
|
|||
BreakpointInfo info = {};
|
||||
info.address = address;
|
||||
info.enabled = true;
|
||||
info.singleshoot = false;
|
||||
info.singleshoot = singleshoot;
|
||||
info.type = BreakpointType::Hardware;
|
||||
info.internal.hardware.slot = slot;
|
||||
info.internal.hardware.type = type;
|
||||
|
|
@ -114,16 +136,56 @@ namespace GleeBug
|
|||
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
|
||||
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
||||
return false;
|
||||
//set the hardware breakpoint
|
||||
if (!SetHardwareBreakpoint(address, slot, type, size))
|
||||
if (!SetHardwareBreakpoint(address, slot, type, size, singleshoot))
|
||||
return false;
|
||||
//insert the callback
|
||||
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
\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.
|
||||
\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.
|
||||
\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.
|
||||
\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.
|
||||
*/
|
||||
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.
|
||||
\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.
|
||||
\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.
|
||||
*/
|
||||
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",
|
||||
_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]()
|
||||
{
|
||||
printf("Step after entry breakpoint! GIP: 0x%p\n",
|
||||
|
|
@ -23,6 +27,10 @@ protected:
|
|||
{
|
||||
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
|
||||
_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]()
|
||||
{
|
||||
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
|
||||
|
|
@ -45,7 +53,7 @@ protected:
|
|||
HardwareBreakpointSlot 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);
|
||||
else
|
||||
printf("Failed to set hardware breakpoint at 0x%p\n", entry);
|
||||
|
|
|
|||
Loading…
Reference in New Issue