diff --git a/GleeBug/Debugger.Global.h b/GleeBug/Debugger.Global.h index 7cb5b05..355005c 100644 --- a/GleeBug/Debugger.Global.h +++ b/GleeBug/Debugger.Global.h @@ -32,6 +32,7 @@ namespace GleeBug typedef std::map ThreadMap; typedef std::map BreakpointMap; typedef std::map BreakpointCallbackMap; + typedef std::unordered_map SoftwareBreakpointMap; //vector typedefs typedef std::vector StepCallbackVector; diff --git a/GleeBug/Debugger.Process.Breakpoint.cpp b/GleeBug/Debugger.Process.Breakpoint.cpp index c345f43..96542c5 100644 --- a/GleeBug/Debugger.Process.Breakpoint.cpp +++ b/GleeBug/Debugger.Process.Breakpoint.cpp @@ -37,7 +37,8 @@ namespace GleeBug FlushInstructionCache(hProcess, nullptr, 0); //insert in the breakpoint map - breakpoints.insert({ { info.type, info.address }, info }); + auto itr = breakpoints.insert({ { info.type, info.address }, info }); + softwareBreakpointReferences[info.address] = itr.first; return true; } @@ -72,6 +73,7 @@ namespace GleeBug } //remove the breakpoint from the maps + softwareBreakpointReferences.erase(info.address); breakpoints.erase(found); breakpointCallbacks.erase({ BreakpointType::Software, address }); return true; @@ -156,7 +158,7 @@ namespace GleeBug 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; diff --git a/GleeBug/Debugger.Process.Memory.cpp b/GleeBug/Debugger.Process.Memory.cpp index 62a0d5d..3360f17 100644 --- a/GleeBug/Debugger.Process.Memory.cpp +++ b/GleeBug/Debugger.Process.Memory.cpp @@ -7,11 +7,60 @@ namespace GleeBug return !!ReadProcessMemory(this->hProcess, reinterpret_cast(address), buffer, size, nullptr); } + bool ProcessInfo::MemReadSafe(ptr address, void* buffer, ptr size) const + { + if (!MemRead(address, buffer, size)) + return false; + + //choose the filter method that has the lowest cost + auto start = address; + auto end = start + size; + if (size > breakpoints.size()) + { + for (const auto & breakpoint : breakpoints) + { + if (breakpoint.first.first != BreakpointType::Software) + continue; + const auto & info = breakpoint.second; + auto curAddress = info.address; + for (ptr j = 0; j < info.internal.software.size; j++) + { + if (curAddress + j >= start && curAddress + j < end) + ((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j]; + } + } + } + else + { + for (ptr i = start; i < end; i++) + { + auto found = softwareBreakpointReferences.find(i); + if (found == softwareBreakpointReferences.end()) + continue; + const auto & info = found->second->second; + auto curAddress = info.address; + for (ptr j = 0; j < info.internal.software.size && i < end; j++, i++) + { + if (curAddress + j >= start && curAddress + j < end) + ((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j]; + } + i += info.internal.software.size - 1; + } + } + + return true; + } + bool ProcessInfo::MemWrite(ptr address, const void* buffer, ptr size) { return !!WriteProcessMemory(this->hProcess, reinterpret_cast(address), buffer, size, nullptr); } + bool ProcessInfo::MemWriteSafe(ptr address, const void* buffer, ptr size) + { + return false; + } + bool ProcessInfo::MemIsValidPtr(ptr address) const { uint8 byte; diff --git a/GleeBug/Debugger.Process.h b/GleeBug/Debugger.Process.h index eaf6281..2d33ab8 100644 --- a/GleeBug/Debugger.Process.h +++ b/GleeBug/Debugger.Process.h @@ -24,6 +24,7 @@ namespace GleeBug ThreadMap threads; //DO NOT COPY THESE OBJECTS! DllMap dlls; BreakpointMap breakpoints; + SoftwareBreakpointMap softwareBreakpointReferences; BreakpointCallbackMap breakpointCallbacks; BreakpointInfo hardwareBreakpoints[4]; @@ -44,6 +45,15 @@ namespace GleeBug */ bool MemRead(ptr address, void* buffer, ptr size) const; + /** + \brief Safely read memory from the process, filtering out breakpoint bytes. + \param address The virtual address to read from. + \param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure. + \param size The size to read. + \return true if it succeeds, false if it fails. + */ + bool MemReadSafe(ptr address, void* buffer, ptr size) const; + /** \brief Write memory to the process. \param address The virtual address to write to. @@ -53,6 +63,15 @@ namespace GleeBug */ bool MemWrite(ptr address, const void* buffer, ptr size); + /** + \brief Safely write memory to the process, preserving breakpoint bytes. + \param address The virtual address to write to. + \param [in] buffer Source buffer. Cannot be null. + \param size The size to write. + \return true if it succeeds, false if it fails. + */ + bool MemWriteSafe(ptr address, const void* buffer, ptr size); + /** \brief Check if an address is a valid read pointer. \param address The address to check. diff --git a/MyDebugger/MyDebugger.h b/MyDebugger/MyDebugger.h index eb38ca2..6c1304d 100644 --- a/MyDebugger/MyDebugger.h +++ b/MyDebugger/MyDebugger.h @@ -50,7 +50,7 @@ protected: printf("Process %d created with entry 0x%p\n", _debugEvent.dwProcessId, entry); - HardwareBreakpointSlot slot; + /*HardwareBreakpointSlot slot; if (_process->GetFreeHardwareBreakpointSlot(slot)) { if (_process->SetHardwareBreakpoint(entry, slot, this, &MyDebugger::cbEntryHardwareBreakpoint, HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte)) @@ -59,12 +59,24 @@ protected: printf("Failed to set hardware breakpoint at 0x%p\n", entry); } else - printf("No free hardware breakpoint slot...\n"); + printf("No free hardware breakpoint slot...\n");*/ - /*if(_process->SetBreakpoint(entry, this, &MyDebugger::cbEntryBreakpoint)) + 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); + uint8 test[5]; + ptr start = entry - 2; + printf("unsafe: "); + _process->MemRead(start, test, sizeof(test)); + for (int i = 0; i < sizeof(test); i++) + printf("%02X ", test[i]); + puts(""); + _process->MemReadSafe(start, test, sizeof(test)); + printf(" safe: "); + for (int i = 0; i < sizeof(test); i++) + printf("%02X ", test[i]); + puts(""); } void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override