mirror of https://github.com/x64dbg/GleeBug
staff
This commit is contained in:
parent
ee855d6c50
commit
f32d1e1fd8
|
|
@ -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,28 +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;
|
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;
|
||||||
const auto pBaseAddr = foundPage->first;
|
const auto pBaseAddr = foundPage->first;
|
||||||
//TODO: single step and page protection changes
|
|
||||||
//FIXED
|
//We restore the protection
|
||||||
if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
|
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);
|
||||||
}
|
}
|
||||||
//step + restore new protection to keep bp
|
|
||||||
mThread->StepInternal(std::bind([this, page, pBaseAddr]()
|
//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]()
|
||||||
{
|
{
|
||||||
mProcess->MemProtect(pBaseAddr, PAGE_SIZE, page.NewProtect);
|
//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;
|
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())
|
||||||
{
|
{
|
||||||
|
|
@ -223,36 +244,46 @@ 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: Marques
|
//FIXED:
|
||||||
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
|
auto pageAddr = bpxPage->first;
|
||||||
|
auto pageProperties = bpxPage->second;
|
||||||
|
|
||||||
if (bpxPage == mProcess->memoryBreakpointPages.end())
|
if (bpxPage == mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", exceptionAddress & ~(PAGE_SIZE - 1));
|
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Access = 1,
|
Access = 1,
|
||||||
Read = 2,
|
Read = 2,
|
||||||
Write = 4,
|
Write = 4,
|
||||||
Execute = 8
|
Execute = 8
|
||||||
*/
|
*/
|
||||||
//Read but our bpx page is not bp on Read
|
//The generated exception on this page was on Read. It should be expected that the breakpoint is also on Read. Or on Access.
|
||||||
|
//Yes - I know that the software itself may have been 0x1337 enough and purposely generated an exception convincing me that it is my bpx >_>.
|
||||||
//We shouldn't care about other stuff such as Write or Execute since these breakpoints are implemented with Access Violation.
|
//We shouldn't care about other stuff such as Write or Execute since these breakpoints are implemented with Access Violation.
|
||||||
if (!(bpxPage->second.Type & 0x1))
|
if (!(pageProperties.Type & 0x1))
|
||||||
{
|
{
|
||||||
if ((exceptionRecord.ExceptionInformation[0] == 0) && (!(bpxPage->second.Type & 0x2)))
|
if ((exceptionRecord.ExceptionInformation[0] == 0) && (!(pageProperties.Type & 0x2)))
|
||||||
{
|
{
|
||||||
//perhaps the program generated such exception
|
//perhaps the program generated such exception
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ASSUME:
|
||||||
|
The breakpoint at exceptionAddress was indeed generated by me.
|
||||||
|
*/
|
||||||
//generic breakpoint callback function.
|
//generic breakpoint callback function.
|
||||||
cbBreakpoint(info);
|
cbBreakpoint(info);
|
||||||
|
|
||||||
//TODO: execute the user callback (if present)
|
//TODO: execute the user callback (if present)
|
||||||
//FIXED: Marques
|
//FIXED:
|
||||||
auto bpxCb = mProcess->breakpointCallbacks.find({ BreakpointType::Memory, info.address });
|
auto bpxCb = mProcess->breakpointCallbacks.find({ BreakpointType::Memory, info.address });
|
||||||
if (bpxCb != mProcess->breakpointCallbacks.end())
|
if (bpxCb != mProcess->breakpointCallbacks.end())
|
||||||
{
|
{
|
||||||
|
|
@ -263,26 +294,36 @@ namespace GleeBug
|
||||||
mContinueStatus = DBG_CONTINUE;
|
mContinueStatus = DBG_CONTINUE;
|
||||||
//TODO: single step and restore page protection
|
//TODO: single step and restore page protection
|
||||||
//FIXED:
|
//FIXED:
|
||||||
if (!mProcess->MemProtect(bpxPage->first, PAGE_SIZE, bpxPage->second.OldProtect))
|
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", bpxPage->first);
|
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
}
|
}
|
||||||
//Pass info as well
|
//Pass info as well
|
||||||
auto pageAddr = bpxPage->first;
|
mThread->StepInternal(std::bind([this, pageAddr]()
|
||||||
auto pageProperties = bpxPage->second;
|
|
||||||
mThread->StepInternal(std::bind([this, info, pageAddr, pageProperties]()
|
|
||||||
{
|
{
|
||||||
//Check if the bpx still exists
|
//With page check this should work better: So when we reach this part of the code we are sure that:
|
||||||
auto found_range = mProcess->memoryBreakpointRanges.find(Range(info.address, info.address));
|
//-The exception Address In deed corresponded to an existing (now possibly deleted) memory breakpoint range
|
||||||
if (found_range != mProcess->memoryBreakpointRanges.end())
|
//-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, pageProperties.NewProtect);
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (foundInfo->second.singleshoot)
|
if (info.singleshoot)
|
||||||
{
|
{
|
||||||
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,32 @@ 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];
|
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);
|
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
|
||||||
printf("\n You Bpxed Correctly: ");
|
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());
|
||||||
|
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++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
printf("%02X ", dataToExec[i]);
|
printf("%02X ", dataToExec[i]);
|
||||||
|
|
@ -32,7 +50,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, false))
|
if (mProcess->SetMemoryBreakpoint(addr, 0x1, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Access, 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