diff --git a/GleeBug/Debugger.Loop.Exception.cpp b/GleeBug/Debugger.Loop.Exception.cpp index b9db2ed..0a2be5d 100644 --- a/GleeBug/Debugger.Loop.Exception.cpp +++ b/GleeBug/Debugger.Loop.Exception.cpp @@ -40,6 +40,9 @@ namespace GleeBug return; const auto info = foundInfo->second; + if (!info.enabled) + return; //not a valid software breakpoint + //set continue status mContinueStatus = DBG_CONTINUE; @@ -135,7 +138,7 @@ namespace GleeBug if (foundInfo == mProcess->breakpoints.end()) return; //not a valid hardware breakpoint const auto info = foundInfo->second; - if (info.internal.hardware.slot != breakpointSlot) + if (info.internal.hardware.slot != breakpointSlot || !info.enabled) return; //not a valid hardware breakpoint //set continue status @@ -163,6 +166,47 @@ namespace GleeBug mProcess->DeleteGenericBreakpoint(info); } + void Debugger::exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) + { + char error[128] = ""; + auto exceptionAddress = ptr(exceptionRecord.ExceptionAddress); + + auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress)); + if (foundRange == mProcess->memoryBreakpointRanges.end()) + { + auto foundPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1)); + if (foundPage != mProcess->memoryBreakpointPages.end()) + { + const auto & page = foundPage->second; + //TODO: single step and page protection changes + if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.NewProtect)) + { + sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first); + cbInternalError(error); + } + } + return; + } + + auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Memory, foundRange->first }); + if (foundInfo == mProcess->breakpoints.end()) + { + sprintf_s(error, "inconsistent memory breakpoint at 0x%p", exceptionAddress); + cbInternalError(error); + return; + } + + const auto info = foundInfo->second; + if (!info.enabled) + return; + + //exceptionRecord. + } + + void Debugger::exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) + { + } + void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) { //let the debuggee handle exceptions per default @@ -183,6 +227,12 @@ namespace GleeBug case STATUS_SINGLE_STEP: exceptionSingleStep(exceptionRecord, firstChance); break; + case STATUS_GUARD_PAGE_VIOLATION: + exceptionGuardPage(exceptionRecord, firstChance); + break; + case STATUS_ACCESS_VIOLATION: + exceptionAccessViolation(exceptionRecord, firstChance); + break; } //call the unhandled exception callback diff --git a/GleeBug/Debugger.Process.Breakpoint.cpp b/GleeBug/Debugger.Process.Breakpoint.cpp index ce9285f..f9a9eb5 100644 --- a/GleeBug/Debugger.Process.Breakpoint.cpp +++ b/GleeBug/Debugger.Process.Breakpoint.cpp @@ -261,10 +261,7 @@ namespace GleeBug data.NewProtect = permanentDep ? RemoveExecuteAccess(RemoveWriteAccess(data.OldProtect)) : data.OldProtect | PAGE_GUARD; } - DWORD oldProtect; - auto vps = !!VirtualProtectEx(hProcess, LPVOID(page), PAGE_SIZE, data.NewProtect, &oldProtect); - printf("VirtualProtect(0x%p, 0x%X, %08X, %08X) = %d\n", page, PAGE_SIZE, data.NewProtect, oldProtect, vps); - return vps; + return MemProtect(page, PAGE_SIZE, data.NewProtect); } bool Process::SetMemoryBreakpoint(ptr address, ptr size, MemoryType type, bool singleshoot) @@ -320,11 +317,7 @@ namespace GleeBug if (!success) { for (const auto & page : breakpointData) - { - DWORD oldProtect; - auto vps = !!VirtualProtectEx(hProcess, LPVOID(page.addr), PAGE_SIZE, page.OldProtect, &oldProtect); - printf("VirtualProtect(0x%p, 0x%X, %08X, %08X) = %d\n", page, PAGE_SIZE, page.OldProtect, oldProtect, vps); - } + MemProtect(page.addr, PAGE_SIZE, page.OldProtect); return false; } @@ -389,10 +382,7 @@ namespace GleeBug } else Protect = data.OldProtect; - DWORD oldProtect; - auto vps = !!VirtualProtectEx(hProcess, LPVOID(page), PAGE_SIZE, Protect, &oldProtect); - printf("VirtualProtect(0x%p, 0x%X, %08X, %08X) = %d\n", page, PAGE_SIZE, Protect, oldProtect, vps); - if (!vps) + if (!MemProtect(page, PAGE_SIZE, Protect)) success = false; if (!data.Refcount) memoryBreakpointPages.erase(foundData); diff --git a/GleeBug/Debugger.Process.Memory.cpp b/GleeBug/Debugger.Process.Memory.cpp index 365e738..823dc37 100644 --- a/GleeBug/Debugger.Process.Memory.cpp +++ b/GleeBug/Debugger.Process.Memory.cpp @@ -74,6 +74,18 @@ namespace GleeBug return MemReadUnsafe(address, &byte, sizeof(byte)); } + bool Process::MemProtect(ptr address, ptr size, DWORD newProtect, DWORD* oldProtect) + { + DWORD dwOldProtect; + auto vps = VirtualProtectEx(hProcess, LPVOID(address), size, newProtect, &dwOldProtect); + printf("MemProtect(0x%p, 0x%X, %08X, %08X) = %d\n", address, size, newProtect, dwOldProtect, vps); + if (!vps) + return false; + if (oldProtect) + *oldProtect = dwOldProtect; + return true; + } + ptr Process::MemFindPattern(ptr data, size_t datasize, const Pattern::WildcardPattern & pattern, bool safe) const { std::vector buffer(datasize); diff --git a/GleeBug/Debugger.Process.h b/GleeBug/Debugger.Process.h index 20733f8..fe60c9b 100644 --- a/GleeBug/Debugger.Process.h +++ b/GleeBug/Debugger.Process.h @@ -122,6 +122,16 @@ namespace GleeBug */ bool MemIsValidPtr(ptr address) const; + /** + \brief Memory protect (execute VirtualProtect in the context of the process). + \param address The address to change protection for. + \param size The size to change protection for. + \param newProtect The new protection. + \param [out] oldProtect The old protection. + \return true if it succeeds, false if it fails. + */ + bool MemProtect(ptr address, ptr size, DWORD newProtect, DWORD* oldProtect = nullptr); + /** \brief Finds the first occurrence of a pattern in process memory. \param data The address to start searching from. diff --git a/GleeBug/Debugger.h b/GleeBug/Debugger.h index 3f6480f..57cc5e2 100644 --- a/GleeBug/Debugger.h +++ b/GleeBug/Debugger.h @@ -259,6 +259,10 @@ namespace GleeBug */ virtual void exceptionHardwareBreakpoint(ptr exceptionAddress); + virtual void exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance); + + virtual void exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance); + protected: //variables PROCESS_INFORMATION mMainProcess; uint32 mContinueStatus = DBG_EXCEPTION_NOT_HANDLED;