mirror of https://github.com/x64dbg/GleeBug
Membp (#45)
* Provided implementation for : Debugger::exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) * void Debugger::exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) >_> with spaces. * . Bugfix : If there is a page exception risen upon a page that is indeed being used by one of our breakpoints, then we simply restore the old page protections, singlestep and then apply the new page protection. . exceptionAccessViolation implementation - the code looks almost equal to exceptionGuardPage except for the verifications made to try to spot on cases where the program uses unusual page permissions (in this case the program should then be granted the right to handle the self generated exception). * . Minor bugfix on exceptionGuardPage. * staff * Final Fixes. Now I suppose everything works correctly. Test by yourself.
This commit is contained in:
parent
6c6e181ff5
commit
b76d500c42
|
|
@ -172,6 +172,10 @@ namespace GleeBug
|
||||||
|
|
||||||
void Debugger::exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance)
|
void Debugger::exceptionGuardPage(const EXCEPTION_RECORD & exceptionRecord, bool firstChance)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
ASSUME:
|
||||||
|
exceptionAddress may or may not have been generated by your breakpoints.
|
||||||
|
*/
|
||||||
char error[128] = "";
|
char error[128] = "";
|
||||||
auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]);
|
auto exceptionAddress = ptr(exceptionRecord.ExceptionInformation[1]);
|
||||||
|
|
||||||
|
|
@ -183,19 +187,45 @@ namespace GleeBug
|
||||||
auto foundPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
auto foundPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
if (foundPage != mProcess->memoryBreakpointPages.end())
|
if (foundPage != mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
|
//(this means that by our fault the program generated an exception, we should clean it)
|
||||||
|
mContinueStatus = DBG_CONTINUE;
|
||||||
//if the page contains a memory breakpoint we have to restore the old protection to correctly resume the debuggee
|
//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 & page = foundPage->second;
|
||||||
//TODO: single step and page protection changes
|
const auto pBaseAddr = foundPage->first;
|
||||||
if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.NewProtect))
|
|
||||||
|
//We restore the protection
|
||||||
|
if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first);
|
sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//However the following situations may occur:
|
||||||
|
// The instruction we singlestep to is a software breakpoint, which may execute a callback, that can :
|
||||||
|
// -actually delete a memory breakpoint that takes this page into account
|
||||||
|
// -add more memory breakpoints
|
||||||
|
//The solution: We just try to see if the page is mapped into memoryBreakpointPages. If the page is in deed being used by any memory breakpoint,
|
||||||
|
// then we ought to restore the protection.
|
||||||
|
mThread->StepInternal(std::bind([this, pBaseAddr]()
|
||||||
|
{
|
||||||
|
//seek out the page address
|
||||||
|
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
||||||
|
if (found_page == mProcess->memoryBreakpointPages.end())
|
||||||
|
{
|
||||||
|
//no page being used by bpx? Then just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mProcess->MemProtect(pBaseAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
|
return;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//find the breakpoint associated with the hit breakpoint range
|
/*
|
||||||
|
ASSUME:
|
||||||
|
exceptionAddress is indeed inside a breakpoint range you have defined.
|
||||||
|
*/
|
||||||
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Memory, foundRange->first });
|
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Memory, foundRange->first });
|
||||||
if (foundInfo == mProcess->breakpoints.end())
|
if (foundInfo == mProcess->breakpoints.end())
|
||||||
{
|
{
|
||||||
|
|
@ -206,6 +236,7 @@ namespace GleeBug
|
||||||
|
|
||||||
//check if the memory breakpoint is disabled (meaning we shouldn't intercept the exception)
|
//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
|
//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;
|
const auto info = foundInfo->second;
|
||||||
if (!info.enabled)
|
if (!info.enabled)
|
||||||
return;
|
return;
|
||||||
|
|
@ -213,13 +244,287 @@ namespace GleeBug
|
||||||
printf("memory breakpoint: 0x%p (size: %d)\n", info.address, info.internal.memory.size);
|
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: check if the right type is accessed (ExceptionInformation[0])
|
||||||
|
//FIXED:
|
||||||
|
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
|
auto pageAddr = bpxPage->first;
|
||||||
|
auto pageProperties = bpxPage->second;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: If I only have a page with Read bp and the exception was not on read, I don't execute the callback. Because since this was implemented with PAGE_GUARD, writtes or executes still trigger
|
||||||
|
//This callback.
|
||||||
|
//FIX: If the memoryBreakpointPages for this page does not have a access flag and has a read flag, but the exception was not on read. Then we resume the debuggee.
|
||||||
|
if ((exceptionRecord.ExceptionInformation[0] != 0))
|
||||||
|
{
|
||||||
|
//The bpx is solely on read.
|
||||||
|
if (((pageProperties.Type & 0x2) != 0) && ((pageProperties.Type & 0x1) == 0))
|
||||||
|
{
|
||||||
|
mContinueStatus = DBG_CONTINUE;
|
||||||
|
//We restore the protection
|
||||||
|
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
|
{
|
||||||
|
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
|
||||||
|
cbInternalError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
mThread->StepInternal(std::bind([this, pageAddr]()
|
||||||
|
{
|
||||||
|
//seek out the page address
|
||||||
|
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
|
if (found_page == mProcess->memoryBreakpointPages.end())
|
||||||
|
{
|
||||||
|
//no page being used by bpx? Then just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
|
return;
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (((pageProperties.Type & 0x1) != 0))
|
||||||
|
{
|
||||||
|
//We are fine if the breakpoint is on Access and somethine other than a read occurred.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//This exception handler was called within a page that had no breakpoints on read or access. Probably the program generated this exception! what a 0x1337 brat.
|
||||||
|
//In this situation we return control to debuggee.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The generated exception is on read.
|
||||||
|
//If the page doesn't have a breakpoint on read or on access then something else must have gone wrong - we pass execution to debuggee.
|
||||||
|
if ((!(pageProperties.Type & 0x2)) && (!(pageProperties.Type & 0x1)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
ASSUME:
|
||||||
|
The breakpoint at exceptionAddress was indeed generated by me.
|
||||||
|
Its safe to call the callbacks.
|
||||||
|
*/
|
||||||
|
//generic breakpoint callback function.
|
||||||
|
cbBreakpoint(info);
|
||||||
|
|
||||||
//TODO: execute the user callback (if present)
|
//TODO: execute the user callback (if present)
|
||||||
|
//FIXED:
|
||||||
|
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
|
//TODO: single step and restore page protection
|
||||||
|
//FIXED:
|
||||||
|
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
|
{
|
||||||
|
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
|
||||||
|
cbInternalError(error);
|
||||||
|
}
|
||||||
|
//Pass info as well
|
||||||
|
mThread->StepInternal(std::bind([this, pageAddr]()
|
||||||
|
{
|
||||||
|
//With page check this should work better: So when we reach this part of the code we are sure that:
|
||||||
|
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
||||||
|
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
||||||
|
//So our new technique basically checks if the page address is still inside memoryBreakpointRanges structure. If this is true, we simply apply the NewProtect.
|
||||||
|
//Wide variety of possible scenarios:
|
||||||
|
//-Bpx on this page and bpx is not singleshot: In the case of PAGE_GUARD page protection (handled by this exception handler), if the page permission map persists, we simply
|
||||||
|
// enforce the newProtect because this page belongs to a breakpoint somewhere.
|
||||||
|
//-Bpx is singleshot: Then it was deleted by the end of this call. If the refcount is zero, then we dont find the page on the Memory map, so assume no more memory breakpoints happen there.
|
||||||
|
// therefore, we do not enforce new protection.
|
||||||
|
//-Bpx was deleted on the handler: Again the page may or may not be mapped on memoryBreakpointPages. If the bp was deleted, and there are no more breakpoints in this page - The page does not exist on the map and therefore we do not restore old page protection.
|
||||||
|
//-Bpx was deleted on the handler AND a new breakpoint was added: if the bpx was deleted, and a new one was added on this page then, surely the page is mapped under memoryBreakpointPages.
|
||||||
|
//Check if the memory page is mapped
|
||||||
|
|
||||||
|
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
|
if (found_page != mProcess->memoryBreakpointPages.end())
|
||||||
|
{
|
||||||
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (info.singleshoot)
|
||||||
|
{
|
||||||
|
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Debugger::exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance)
|
void Debugger::exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance)
|
||||||
{
|
{
|
||||||
//TODO: memory breakpoint code
|
/*
|
||||||
|
ASSUME:
|
||||||
|
exceptionAddress may or may not have been generated by your breakpoints.
|
||||||
|
*/
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
//(this means that by our fault the program generated an exception, we should clean it)
|
||||||
|
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;
|
||||||
|
|
||||||
|
//We restore the protection
|
||||||
|
if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
||||||
|
{
|
||||||
|
sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first);
|
||||||
|
cbInternalError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
//However the following situations may occur:
|
||||||
|
// The instruction we singlestep to is a software breakpoint, which may execute a callback, that can :
|
||||||
|
// -actually delete a memory breakpoint that takes this page into account
|
||||||
|
// -add more memory breakpoints
|
||||||
|
//The solution: We just try to see if the page is mapped into memoryBreakpointPages. If the page is in deed being used by any memory breakpoint,
|
||||||
|
// then we ought to restore the protection.
|
||||||
|
mThread->StepInternal(std::bind([this, pBaseAddr]()
|
||||||
|
{
|
||||||
|
//seek out the page address
|
||||||
|
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
||||||
|
if (found_page == mProcess->memoryBreakpointPages.end())
|
||||||
|
{
|
||||||
|
//no page being used by bpx? Then just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mProcess->MemProtect(pBaseAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
|
return;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ASSUME:
|
||||||
|
exceptionAddress is indeed inside a breakpoint range you have defined.
|
||||||
|
*/
|
||||||
|
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:
|
||||||
|
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
|
auto pageAddr = bpxPage->first;
|
||||||
|
auto pageProperties = bpxPage->second;
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
//ExceptionInformation[0] should be considered as 1 or 8, because these are for exceptions generated on write or execute.
|
||||||
|
//Execute is only implemented with page guard if no Data-Execution-Prevention is implemented by the Kernel.
|
||||||
|
if ((exceptionRecord.ExceptionInformation[0] == 1) && (!(pageProperties.Type & 4)))
|
||||||
|
{
|
||||||
|
//The exception was on Write but there was no page breakpoint in Write? Then the program changed the page permissions, or naturally overwritten protected data. We do not interfere.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((exceptionRecord.ExceptionInformation[0] == 8) && (!(pageProperties.Type & 8)))
|
||||||
|
{
|
||||||
|
//The exception was on Execution but there was no page breakpoint in Execute? Then the program changed the page permissions, or naturally executed protected code. We do not interfere.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
ASSUME:
|
||||||
|
The breakpoint at exceptionAddress was indeed generated by me.
|
||||||
|
*/
|
||||||
|
//generic breakpoint callback function.
|
||||||
|
cbBreakpoint(info);
|
||||||
|
|
||||||
|
//TODO: execute the user callback (if present)
|
||||||
|
//FIXED:
|
||||||
|
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(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
|
{
|
||||||
|
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
|
||||||
|
cbInternalError(error);
|
||||||
|
}
|
||||||
|
//Pass info as well
|
||||||
|
mThread->StepInternal(std::bind([this, pageAddr]()
|
||||||
|
{
|
||||||
|
//With page check this should work better: So when we reach this part of the code we are sure that:
|
||||||
|
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
||||||
|
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
||||||
|
//So our new technique basically checks if the page address is still inside memoryBreakpointRanges structure. If this is true, we simply apply the NewProtect.
|
||||||
|
//Wide variety of possible scenarios:
|
||||||
|
//-Bpx on this page and bpx is not singleshot: In the case of PAGE_GUARD page protection (handled by this exception handler), if the page permission map persists, we simply
|
||||||
|
// enforce the newProtect because this page belongs to a breakpoint somewhere.
|
||||||
|
//-Bpx is singleshot: Then it was deleted by the end of this call. If the refcount is zero, then we dont find the page on the Memory map, so assume no more memory breakpoints happen there.
|
||||||
|
// therefore, we do not enforce new protection.
|
||||||
|
//-Bpx was deleted on the handler: Again the page may or may not be mapped on memoryBreakpointPages. If the bp was deleted, and there are no more breakpoints in this page - The page does not exist on the map and therefore we do not restore old page protection.
|
||||||
|
//-Bpx was deleted on the handler AND a new breakpoint was added: if the bpx was deleted, and a new one was added on this page then, surely the page is mapped under memoryBreakpointPages.
|
||||||
|
//Check if the memory page is mapped
|
||||||
|
|
||||||
|
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
|
if (found_page != mProcess->memoryBreakpointPages.end())
|
||||||
|
{
|
||||||
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (info.singleshoot)
|
||||||
|
{
|
||||||
|
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,7 @@ namespace GleeBug
|
||||||
|
|
||||||
static DWORD RemoveExecuteAccess(DWORD dwAccess)
|
static DWORD RemoveExecuteAccess(DWORD dwAccess)
|
||||||
{
|
{
|
||||||
|
//These settings can trigger access violation.
|
||||||
DWORD dwBase = dwAccess & 0xFF;
|
DWORD dwBase = dwAccess & 0xFF;
|
||||||
DWORD dwHigh = dwAccess & 0xFFFFFF00;
|
DWORD dwHigh = dwAccess & 0xFFFFFF00;
|
||||||
switch (dwBase)
|
switch (dwBase)
|
||||||
|
|
@ -208,7 +209,7 @@ namespace GleeBug
|
||||||
case PAGE_EXECUTE_READ:
|
case PAGE_EXECUTE_READ:
|
||||||
case PAGE_EXECUTE_READWRITE:
|
case PAGE_EXECUTE_READWRITE:
|
||||||
case PAGE_EXECUTE_WRITECOPY:
|
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:
|
default:
|
||||||
return dwAccess;
|
return dwAccess;
|
||||||
}
|
}
|
||||||
|
|
@ -252,12 +253,16 @@ namespace GleeBug
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto & oldData = found->second;
|
auto & oldData = found->second;
|
||||||
data.Type = oldData.Type | uint32(type);
|
data.Type = oldData.Type | uint32(type); //combines new protection
|
||||||
data.OldProtect = oldData.OldProtect;
|
data.OldProtect = oldData.OldProtect; // old protection remains the same
|
||||||
data.Refcount = oldData.Refcount + 1;
|
data.Refcount = oldData.Refcount + 1; //increment reference count
|
||||||
if (data.Type & uint32(MemoryType::Access) || data.Type & uint32(MemoryType::Read)) //Access/Read always becomes PAGE_GUARD
|
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 | 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.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;
|
data.NewProtect = permanentDep ? RemoveExecuteAccess(RemoveWriteAccess(data.OldProtect)) : data.OldProtect | PAGE_GUARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -381,6 +386,8 @@ namespace GleeBug
|
||||||
if (data.Refcount)
|
if (data.Refcount)
|
||||||
{
|
{
|
||||||
//TODO: properly determine the new protection flag
|
//TODO: properly determine the new protection flag
|
||||||
|
//Are there any other protections left?
|
||||||
|
//If so add the guard
|
||||||
if (data.Type & ~uint32(info.internal.memory.type))
|
if (data.Type & ~uint32(info.internal.memory.type))
|
||||||
data.NewProtect = data.OldProtect | PAGE_GUARD;
|
data.NewProtect = data.OldProtect | PAGE_GUARD;
|
||||||
Protect = data.NewProtect;
|
Protect = data.NewProtect;
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ namespace GleeBug
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
FALSE,
|
FALSE,
|
||||||
DEBUG_PROCESS | CREATE_NEW_CONSOLE,
|
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE,
|
||||||
nullptr,
|
nullptr,
|
||||||
szCurrentDirectory,
|
szCurrentDirectory,
|
||||||
&mMainStartupInfo,
|
&mMainStartupInfo,
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,44 @@ using namespace GleeBug;
|
||||||
class MyDebugger : public Debugger
|
class MyDebugger : public Debugger
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
void cbMemoryBreakpoint2(const BreakpointInfo & info)
|
||||||
|
{
|
||||||
|
printf("Reached memory breakpoint#2! GIP: 0x%p\n",
|
||||||
|
mRegisters->Gip());
|
||||||
|
}
|
||||||
|
|
||||||
void cbMemoryBreakpoint(const BreakpointInfo & info)
|
void cbMemoryBreakpoint(const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
|
unsigned char dataToExec[4];
|
||||||
|
const char tmp[] = "aaaa";
|
||||||
|
|
||||||
|
|
||||||
printf("Reached memory breakpoint! GIP: 0x%p\n",
|
printf("Reached memory breakpoint! GIP: 0x%p\n",
|
||||||
mRegisters->Gip());
|
mRegisters->Gip());
|
||||||
|
|
||||||
|
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
|
||||||
|
printf("\n What are my bytes? I am so lost.. Dump: ");
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
printf("%02X ", dataToExec[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mProcess->DeleteMemoryBreakpoint(mRegisters->Gip());
|
||||||
|
memcpy(dataToExec, tmp, 4);
|
||||||
|
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
|
||||||
|
printf("\n What are my bytes? I am so lost.. Dump: ");
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
printf("%02X ", dataToExec[i]);
|
||||||
|
}
|
||||||
|
mProcess->SetMemoryBreakpoint(mRegisters->Gip() + 1, 0x1, this, &MyDebugger::cbMemoryBreakpoint2, MemoryType::Access, false);
|
||||||
|
memcpy(dataToExec, tmp, 4);
|
||||||
|
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
|
||||||
|
printf("\n What are my bytes? I am so lost.. Dump: ");
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
printf("%02X ", dataToExec[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbEntryBreakpoint(const BreakpointInfo & info)
|
void cbEntryBreakpoint(const BreakpointInfo & info)
|
||||||
|
|
@ -24,7 +58,7 @@ protected:
|
||||||
auto addr = mRegisters->Esi();
|
auto addr = mRegisters->Esi();
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
printf("Addr: 0x%p\n", addr);
|
printf("Addr: 0x%p\n", addr);
|
||||||
if (mProcess->SetMemoryBreakpoint(addr, 0x1000, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Access))
|
if (mProcess->SetMemoryBreakpoint(addr, 0x10000, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Execute, false))
|
||||||
puts("Memory breakpoint set!");
|
puts("Memory breakpoint set!");
|
||||||
else
|
else
|
||||||
puts("Failed to set memory breakpoint...");
|
puts("Failed to set memory breakpoint...");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue