diff --git a/GleeBug/Debugger.Loop.Exception.cpp b/GleeBug/Debugger.Loop.Exception.cpp index 77d747f..a3adfc8 100644 --- a/GleeBug/Debugger.Loop.Exception.cpp +++ b/GleeBug/Debugger.Loop.Exception.cpp @@ -172,56 +172,6 @@ namespace GleeBug void Debugger::exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) { - /* old code ~Duncan~ - char error[128] = ""; - auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]); - //check if the exception address is directly in the range of a memory breakpoint - auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress)); - if (foundRange == mProcess->memoryBreakpointRanges.end()) - { - //if not in range, check if a memory breakpoint is in the accessed page - auto foundPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1)); - if (foundPage != mProcess->memoryBreakpointPages.end()) - { - //if the page contains a memory breakpoint we have to restore the old protection to correctly resume the debuggee - 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; - } - //find the breakpoint associated with the hit breakpoint range - 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; - } - //check if the memory breakpoint is disabled (meaning we shouldn't intercept the exception) - //TODO: think about what happens with multiple breakpoints in one page where only one is disabled - const auto info = foundInfo->second; - if (!info.enabled) - return; - printf("memory breakpoint: 0x%p (size: %d)\n", info.address, info.internal.memory.size); - //TODO: check if the right type is accessed (ExceptionInformation[0]) - //TODO: execute the user callback (if present) - //TODO: single step and restore page protection - */ - //New code ~Marques~ - /* 0xcc breakpoing - mThread->StepInternal(std::bind([this, info]() - { - //only restore the bytes if the breakpoint still exists - if (mProcess->breakpoints.find({ BreakpointType::Software, info.address }) != mProcess->breakpoints.end()) - mProcess->MemWriteUnsafe(info.address, info.internal.software.newbytes, info.internal.software.size); - })); - */ - char error[128] = ""; auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]); @@ -233,18 +183,21 @@ namespace GleeBug auto foundPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1)); if (foundPage != mProcess->memoryBreakpointPages.end()) { + mContinueStatus = DBG_CONTINUE; //if the page contains a memory breakpoint we have to restore the old protection to correctly resume the debuggee const auto & page = foundPage->second; + const auto pBaseAddr = foundPage->first; //TODO: single step and page protection changes - //FIXED (marques): - //restored *OLD* page protection settings + //FIXED if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect)) { sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first); cbInternalError(error); } - mThread->StepInternal(std::bind([this]() + //step + restore new protection to keep bp + mThread->StepInternal(std::bind([this, page, pBaseAddr]() { + mProcess->MemProtect(pBaseAddr, PAGE_SIZE, page.NewProtect); return; })); } @@ -285,24 +238,13 @@ namespace GleeBug Execute = 8 */ //Read but our bpx page is not bp on Read - if ((exceptionRecord.ExceptionInformation[0]) && (!(bpxPage->second.Type & 0x2))) + //We shouldn't care about other stuff such as Write or Execute since these breakpoints are implemented with Access Violation. + if ((exceptionRecord.ExceptionInformation[0]==0) && (!(bpxPage->second.Type & 0x2))) { //perhaps the program generated such exception return; } - //Exception on write but page bp information does not have bp on write - if ((exceptionRecord.ExceptionInformation[0] == 1) && (!(bpxPage->second.Type & 0x4))) - { - return; - } - - //caused by data execution prevention but page bp information does not have bp on exec - if ((exceptionRecord.ExceptionInformation[0] == 8) && (!(bpxPage->second.Type & 0x8))) - { - return; - } - //generic breakpoint callback function. cbBreakpoint(info); @@ -347,7 +289,125 @@ namespace GleeBug void Debugger::exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) { - //TODO: memory breakpoint code + //Same shit as before + + char error[128] = ""; + auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]); + + //check if the exception address is directly in the range of a memory breakpoint + auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress)); + if (foundRange == mProcess->memoryBreakpointRanges.end()) + { + //if not in range, check if a memory breakpoint is in the accessed page + auto foundPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1)); + if (foundPage != mProcess->memoryBreakpointPages.end()) + { + mContinueStatus = DBG_CONTINUE; + //if the page contains a memory breakpoint we have to restore the old protection to correctly resume the debuggee + const auto & page = foundPage->second; + const auto pBaseAddr = foundPage->first; + //TODO: single step and page protection changes + //FIXED + if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect)) + { + sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first); + cbInternalError(error); + } + //step + restore new protection to keep bp + mThread->StepInternal(std::bind([this, page, pBaseAddr]() + { + mProcess->MemProtect(pBaseAddr, PAGE_SIZE, page.NewProtect); + return; + })); + } + return; + } + + //find the breakpoint associated with the hit breakpoint range + 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; + } + + //check if the memory breakpoint is disabled (meaning we shouldn't intercept the exception) + //TODO: think about what happens with multiple breakpoints in one page where only one is disabled + //There is really no problem about this because enabled is a property of a range and ranges do not overlap. + const auto info = foundInfo->second; + if (!info.enabled) + return; + + printf("memory breakpoint: 0x%p (size: %d)\n", info.address, info.internal.memory.size); + + //TODO: check if the right type is accessed (ExceptionInformation[0]) + //FIXED: Marques + auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1)); + if (bpxPage == mProcess->memoryBreakpointPages.end()) + { + sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", exceptionAddress & ~(PAGE_SIZE - 1)); + cbInternalError(error); + return; + } + /* + Access = 1, + Read = 2, + Write = 4, + Execute = 8 + */ + //Write but the bpx was not on write + //We shouldn't care about other stuff such as read or access because those were implemented with page guards. + if ((exceptionRecord.ExceptionInformation[0] == 1) && (!(bpxPage->second.Type & 0x4))) + { + //perhaps the program generated such exception + return; + } + + //Exec but bpx was not on exec. + if ((exceptionRecord.ExceptionInformation[0] == 8) && (!(bpxPage->second.Type & 0x8))) + { + //perhaps the program generated such exception + return; + } + //generic breakpoint callback function. + cbBreakpoint(info); + + //TODO: execute the user callback (if present) + //FIXED: Marques + auto bpxCb = mProcess->breakpointCallbacks.find({ BreakpointType::Memory, info.address }); + if (bpxCb != mProcess->breakpointCallbacks.end()) + { + bpxCb->second(info); + } + + + mContinueStatus = DBG_CONTINUE; + //TODO: single step and restore page protection + //FIXED: + if (!mProcess->MemProtect(bpxPage->first, PAGE_SIZE, bpxPage->second.OldProtect)) + { + sprintf_s(error, "MemProtect failed on 0x%p", bpxPage->first); + cbInternalError(error); + } + //Pass info as well + auto pageAddr = bpxPage->first; + auto pageProperties = bpxPage->second; + mThread->StepInternal(std::bind([this, info, pageAddr, pageProperties]() + { + //Check if the bpx still exists + auto found_range = mProcess->memoryBreakpointRanges.find(Range(info.address, info.address)); + if (found_range != mProcess->memoryBreakpointRanges.end()) + { + mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.NewProtect); + } + return; + })); + + if (foundInfo->second.singleshoot) + { + mProcess->DeleteMemoryBreakpoint(exceptionAddress); + } } void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) diff --git a/GleeBug/Debugger.Process.Breakpoint.cpp b/GleeBug/Debugger.Process.Breakpoint.cpp index e4f8623..7f10ec8 100644 --- a/GleeBug/Debugger.Process.Breakpoint.cpp +++ b/GleeBug/Debugger.Process.Breakpoint.cpp @@ -199,6 +199,7 @@ namespace GleeBug static DWORD RemoveExecuteAccess(DWORD dwAccess) { + //These settings can trigger access violation. DWORD dwBase = dwAccess & 0xFF; DWORD dwHigh = dwAccess & 0xFFFFFF00; switch (dwBase) @@ -208,7 +209,7 @@ namespace GleeBug case PAGE_EXECUTE_READ: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: - return dwHigh | (dwBase >> 4); + return dwHigh | (dwBase >> 4); //This removes execute in deed; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx - 0x1337 tricks default: return dwAccess; } @@ -252,12 +253,16 @@ namespace GleeBug else { auto & oldData = found->second; - data.Type = oldData.Type | uint32(type); - data.OldProtect = oldData.OldProtect; - data.Refcount = oldData.Refcount + 1; - if (data.Type & uint32(MemoryType::Access) || data.Type & uint32(MemoryType::Read)) //Access/Read always becomes PAGE_GUARD - data.NewProtect = data.OldProtect | PAGE_GUARD; - else if (data.Type & (uint32(MemoryType::Write) | uint32(MemoryType::Execute))) //Write + Execute becomes either PAGE_GUARD or both write and execute flags removed + data.Type = oldData.Type | uint32(type); //combines new protection + data.OldProtect = oldData.OldProtect; // old protection remains the same + data.Refcount = oldData.Refcount + 1; //increment reference count + if (oldData.Type == uint32(type)) // Edge case for when you need to set a mem bpx on a same page with the same type, you just leave newProtect = OldProtect. + { + data.NewProtect = data.OldProtect; + } + else if (data.Type & uint32(MemoryType::Access) || data.Type & uint32(MemoryType::Read)) // Access/Read always becomes PAGE_GUARD ; This page cannot access or Read? + data.NewProtect = data.OldProtect | PAGE_GUARD; //as before + else if (data.Type & (uint32(MemoryType::Write) | uint32(MemoryType::Execute))) // Write + Execute becomes either PAGE_GUARD or both write and execute flags removed data.NewProtect = permanentDep ? RemoveExecuteAccess(RemoveWriteAccess(data.OldProtect)) : data.OldProtect | PAGE_GUARD; } diff --git a/MyDebugger/MyDebugger.h b/MyDebugger/MyDebugger.h index c3be501..53994a3 100644 --- a/MyDebugger/MyDebugger.h +++ b/MyDebugger/MyDebugger.h @@ -10,8 +10,16 @@ class MyDebugger : public Debugger protected: void cbMemoryBreakpoint(const BreakpointInfo & info) { + unsigned char dataToExec[4]; printf("Reached memory breakpoint! GIP: 0x%p\n", mRegisters->Gip()); + + mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4); + printf("\n You Bpxed Correctly: "); + for (int i = 0; i < 4; i++) + { + printf("%02X ", dataToExec[i]); + } } void cbEntryBreakpoint(const BreakpointInfo & info) @@ -24,7 +32,7 @@ protected: auto addr = mRegisters->Esi(); #endif //_WIN64 printf("Addr: 0x%p\n", addr); - if (mProcess->SetMemoryBreakpoint(addr, 0x1000, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Access)) + if (mProcess->SetMemoryBreakpoint(addr, 0x1000, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Execute)) puts("Memory breakpoint set!"); else puts("Failed to set memory breakpoint...");