mirror of https://github.com/x64dbg/GleeBug
AStyle format
This commit is contained in:
parent
63a6668514
commit
30217c92d4
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||||
|
<section name="AStyleHelper.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
|
||||||
|
<applicationSettings>
|
||||||
|
<AStyleHelper.Properties.Settings>
|
||||||
|
<setting name="Pattern" serializeAs="String">
|
||||||
|
<value>*.c;*.h;*.cpp;*.hpp</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="Options" serializeAs="String">
|
||||||
|
<value>style=allman, convert-tabs, align-pointer=type, align-reference=middle, indent=spaces, indent-namespaces, indent-col1-comments, pad-oper, unpad-paren, keep-one-line-blocks, close-templates</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="Ignore" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
|
<setting name="License" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
|
</AStyleHelper.Properties.Settings>
|
||||||
|
</applicationSettings>
|
||||||
|
</configuration>
|
||||||
|
|
@ -21,7 +21,7 @@ namespace GleeBug
|
||||||
_In_ HANDLE /*hProcess*/,
|
_In_ HANDLE /*hProcess*/,
|
||||||
_Out_ LPDWORD /*lpFlags*/,
|
_Out_ LPDWORD /*lpFlags*/,
|
||||||
_Out_ PBOOL /*lpPermanent*/
|
_Out_ PBOOL /*lpPermanent*/
|
||||||
);
|
);
|
||||||
static auto GPDP = GETPROCESSDEPPOLICY(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy"));
|
static auto GPDP = GETPROCESSDEPPOLICY(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy"));
|
||||||
if(GPDP)
|
if(GPDP)
|
||||||
{
|
{
|
||||||
|
|
@ -75,7 +75,7 @@ namespace GleeBug
|
||||||
|
|
||||||
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
||||||
{
|
{
|
||||||
if (mThread->isInternalStepping) //handle internal steps
|
if(mThread->isInternalStepping) //handle internal steps
|
||||||
{
|
{
|
||||||
//set internal status
|
//set internal status
|
||||||
mThread->isInternalStepping = false;
|
mThread->isInternalStepping = false;
|
||||||
|
|
@ -84,7 +84,7 @@ namespace GleeBug
|
||||||
//call the internal step callback
|
//call the internal step callback
|
||||||
mThread->cbInternalStep();
|
mThread->cbInternalStep();
|
||||||
}
|
}
|
||||||
if (mThread->isSingleStepping) //handle single step
|
if(mThread->isSingleStepping) //handle single step
|
||||||
{
|
{
|
||||||
//set internal status
|
//set internal status
|
||||||
mThread->isSingleStepping = false;
|
mThread->isSingleStepping = false;
|
||||||
|
|
@ -96,7 +96,7 @@ namespace GleeBug
|
||||||
//call the user callbacks
|
//call the user callbacks
|
||||||
auto cbStepCopy = mThread->stepCallbacks;
|
auto cbStepCopy = mThread->stepCallbacks;
|
||||||
mThread->stepCallbacks.clear();
|
mThread->stepCallbacks.clear();
|
||||||
for (auto cbStep : cbStepCopy)
|
for(auto cbStep : cbStepCopy)
|
||||||
cbStep();
|
cbStep();
|
||||||
}
|
}
|
||||||
else //handle hardware breakpoint single step exceptions
|
else //handle hardware breakpoint single step exceptions
|
||||||
|
|
@ -112,22 +112,22 @@ namespace GleeBug
|
||||||
ptr dr6 = registers.Dr6();
|
ptr dr6 = registers.Dr6();
|
||||||
HardwareSlot breakpointSlot;
|
HardwareSlot breakpointSlot;
|
||||||
ptr breakpointAddress;
|
ptr breakpointAddress;
|
||||||
if (exceptionAddress == registers.Dr0() || dr6 & 0x1)
|
if(exceptionAddress == registers.Dr0() || dr6 & 0x1)
|
||||||
{
|
{
|
||||||
breakpointAddress = registers.Dr0();
|
breakpointAddress = registers.Dr0();
|
||||||
breakpointSlot = HardwareSlot::Dr0;
|
breakpointSlot = HardwareSlot::Dr0;
|
||||||
}
|
}
|
||||||
else if (exceptionAddress == registers.Dr1() || dr6 & 0x2)
|
else if(exceptionAddress == registers.Dr1() || dr6 & 0x2)
|
||||||
{
|
{
|
||||||
breakpointAddress = registers.Dr1();
|
breakpointAddress = registers.Dr1();
|
||||||
breakpointSlot = HardwareSlot::Dr1;
|
breakpointSlot = HardwareSlot::Dr1;
|
||||||
}
|
}
|
||||||
else if (exceptionAddress == registers.Dr2() || dr6 & 0x4)
|
else if(exceptionAddress == registers.Dr2() || dr6 & 0x4)
|
||||||
{
|
{
|
||||||
breakpointAddress = registers.Dr2();
|
breakpointAddress = registers.Dr2();
|
||||||
breakpointSlot = HardwareSlot::Dr2;
|
breakpointSlot = HardwareSlot::Dr2;
|
||||||
}
|
}
|
||||||
else if (exceptionAddress == registers.Dr3() || dr6 & 0x8)
|
else if(exceptionAddress == registers.Dr3() || dr6 & 0x8)
|
||||||
{
|
{
|
||||||
breakpointAddress = registers.Dr3();
|
breakpointAddress = registers.Dr3();
|
||||||
breakpointSlot = HardwareSlot::Dr3;
|
breakpointSlot = HardwareSlot::Dr3;
|
||||||
|
|
@ -137,10 +137,10 @@ namespace GleeBug
|
||||||
|
|
||||||
//find the breakpoint in the internal structures
|
//find the breakpoint in the internal structures
|
||||||
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
|
||||||
if (foundInfo == mProcess->breakpoints.end())
|
if(foundInfo == mProcess->breakpoints.end())
|
||||||
return; //not a valid hardware breakpoint
|
return; //not a valid hardware breakpoint
|
||||||
const auto info = foundInfo->second;
|
const auto info = foundInfo->second;
|
||||||
if (info.internal.hardware.slot != breakpointSlot)
|
if(info.internal.hardware.slot != breakpointSlot)
|
||||||
return; //not a valid hardware breakpoint
|
return; //not a valid hardware breakpoint
|
||||||
|
|
||||||
//set continue status
|
//set continue status
|
||||||
|
|
@ -151,7 +151,7 @@ namespace GleeBug
|
||||||
mThread->StepInternal(std::bind([this, info]()
|
mThread->StepInternal(std::bind([this, info]()
|
||||||
{
|
{
|
||||||
//only restore if the breakpoint still exists
|
//only restore if the breakpoint still exists
|
||||||
if (mProcess->breakpoints.find({ BreakpointType::Hardware, info.address }) != mProcess->breakpoints.end())
|
if(mProcess->breakpoints.find({ BreakpointType::Hardware, info.address }) != mProcess->breakpoints.end())
|
||||||
mThread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
mThread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -160,11 +160,11 @@ namespace GleeBug
|
||||||
|
|
||||||
//call the user callback
|
//call the user callback
|
||||||
auto foundCallback = mProcess->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
auto foundCallback = mProcess->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
|
||||||
if (foundCallback != mProcess->breakpointCallbacks.end())
|
if(foundCallback != mProcess->breakpointCallbacks.end())
|
||||||
foundCallback->second(info);
|
foundCallback->second(info);
|
||||||
|
|
||||||
//delete the breakpoint if it is singleshoot
|
//delete the breakpoint if it is singleshoot
|
||||||
if (info.singleshoot)
|
if(info.singleshoot)
|
||||||
mProcess->DeleteGenericBreakpoint(info);
|
mProcess->DeleteGenericBreakpoint(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,11 +179,11 @@ namespace GleeBug
|
||||||
|
|
||||||
//check if the exception address is directly in the range of a memory breakpoint
|
//check if the exception address is directly in the range of a memory breakpoint
|
||||||
auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress));
|
auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress));
|
||||||
if (foundRange == mProcess->memoryBreakpointRanges.end())
|
if(foundRange == mProcess->memoryBreakpointRanges.end())
|
||||||
{
|
{
|
||||||
//if not in range, check if a memory breakpoint is in the accessed page
|
//if not in range, check if a memory breakpoint is in the accessed page
|
||||||
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)
|
//(this means that by our fault the program generated an exception, we should clean it)
|
||||||
mContinueStatus = DBG_CONTINUE;
|
mContinueStatus = DBG_CONTINUE;
|
||||||
|
|
@ -192,7 +192,7 @@ namespace GleeBug
|
||||||
const auto pBaseAddr = foundPage->first;
|
const auto pBaseAddr = foundPage->first;
|
||||||
|
|
||||||
//We restore the protection
|
//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", (void*)foundPage->first);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -200,7 +200,7 @@ namespace GleeBug
|
||||||
|
|
||||||
//However the following situations may occur:
|
//However the following situations may occur:
|
||||||
// The instruction we singlestep to is a software breakpoint, which may execute a callback, that can :
|
// 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
|
// -actually delete a memory breakpoint that takes this page into account
|
||||||
// -add more memory breakpoints
|
// -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,
|
//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.
|
// then we ought to restore the protection.
|
||||||
|
|
@ -208,7 +208,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//seek out the page address
|
//seek out the page address
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
||||||
if (found_page == mProcess->memoryBreakpointPages.end())
|
if(found_page == mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
//no page being used by bpx? Then just return
|
//no page being used by bpx? Then just return
|
||||||
return;
|
return;
|
||||||
|
|
@ -225,7 +225,7 @@ namespace GleeBug
|
||||||
exceptionAddress is indeed inside a breakpoint range you have defined.
|
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())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -238,12 +238,12 @@ namespace GleeBug
|
||||||
const auto info = foundInfo->second;
|
const auto info = foundInfo->second;
|
||||||
|
|
||||||
//TODO: check if the right type is accessed (ExceptionInformation[0])
|
//TODO: check if the right type is accessed (ExceptionInformation[0])
|
||||||
//FIXED:
|
//FIXED:
|
||||||
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
auto pageAddr = bpxPage->first;
|
auto pageAddr = bpxPage->first;
|
||||||
auto pageProperties = bpxPage->second;
|
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", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -253,34 +253,34 @@ namespace GleeBug
|
||||||
//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
|
//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.
|
//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.
|
//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))
|
if((exceptionRecord.ExceptionInformation[0] != 0))
|
||||||
{
|
{
|
||||||
//The bpx is solely on read.
|
//The bpx is solely on read.
|
||||||
if (((pageProperties.Type & 0x2) != 0) && ((pageProperties.Type & 0x1) == 0))
|
if(((pageProperties.Type & 0x2) != 0) && ((pageProperties.Type & 0x1) == 0))
|
||||||
{
|
{
|
||||||
mContinueStatus = DBG_CONTINUE;
|
mContinueStatus = DBG_CONTINUE;
|
||||||
//We restore the protection
|
//We restore the protection
|
||||||
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
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))
|
|
||||||
|
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.
|
//We are fine if the breakpoint is on Access and somethine other than a read occurred.
|
||||||
}
|
}
|
||||||
|
|
@ -296,12 +296,12 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//The generated exception is on read.
|
//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 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)))
|
if((!(pageProperties.Type & 0x2)) && (!(pageProperties.Type & 0x1)))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ASSUME:
|
ASSUME:
|
||||||
|
|
@ -314,7 +314,7 @@ namespace GleeBug
|
||||||
//TODO: execute the user callback (if present)
|
//TODO: execute the user callback (if present)
|
||||||
//FIXED:
|
//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())
|
||||||
{
|
{
|
||||||
bpxCb->second(info);
|
bpxCb->second(info);
|
||||||
}
|
}
|
||||||
|
|
@ -323,7 +323,7 @@ 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(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -336,7 +336,7 @@ namespace GleeBug
|
||||||
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
//-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.
|
//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:
|
//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
|
//-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.
|
// 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.
|
//-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.
|
// therefore, we do not enforce new protection.
|
||||||
|
|
@ -345,14 +345,14 @@ namespace GleeBug
|
||||||
//Check if the memory page is mapped
|
//Check if the memory page is mapped
|
||||||
|
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
if (found_page != mProcess->memoryBreakpointPages.end())
|
if(found_page != mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (info.singleshoot)
|
if(info.singleshoot)
|
||||||
{
|
{
|
||||||
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
||||||
}
|
}
|
||||||
|
|
@ -371,11 +371,11 @@ namespace GleeBug
|
||||||
|
|
||||||
//check if the exception address is directly in the range of a memory breakpoint
|
//check if the exception address is directly in the range of a memory breakpoint
|
||||||
auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress));
|
auto foundRange = mProcess->memoryBreakpointRanges.find(Range(exceptionAddress, exceptionAddress));
|
||||||
if (foundRange == mProcess->memoryBreakpointRanges.end())
|
if(foundRange == mProcess->memoryBreakpointRanges.end())
|
||||||
{
|
{
|
||||||
//if not in range, check if a memory breakpoint is in the accessed page
|
//if not in range, check if a memory breakpoint is in the accessed page
|
||||||
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)
|
//(this means that by our fault the program generated an exception, we should clean it)
|
||||||
mContinueStatus = DBG_CONTINUE;
|
mContinueStatus = DBG_CONTINUE;
|
||||||
|
|
@ -384,7 +384,7 @@ namespace GleeBug
|
||||||
const auto pBaseAddr = foundPage->first;
|
const auto pBaseAddr = foundPage->first;
|
||||||
|
|
||||||
//We restore the protection
|
//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", (void*)foundPage->first);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -392,7 +392,7 @@ namespace GleeBug
|
||||||
|
|
||||||
//However the following situations may occur:
|
//However the following situations may occur:
|
||||||
// The instruction we singlestep to is a software breakpoint, which may execute a callback, that can :
|
// 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
|
// -actually delete a memory breakpoint that takes this page into account
|
||||||
// -add more memory breakpoints
|
// -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,
|
//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.
|
// then we ought to restore the protection.
|
||||||
|
|
@ -400,7 +400,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//seek out the page address
|
//seek out the page address
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pBaseAddr);
|
||||||
if (found_page == mProcess->memoryBreakpointPages.end())
|
if(found_page == mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
//no page being used by bpx? Then just return
|
//no page being used by bpx? Then just return
|
||||||
return;
|
return;
|
||||||
|
|
@ -417,7 +417,7 @@ namespace GleeBug
|
||||||
exceptionAddress is indeed inside a breakpoint range you have defined.
|
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())
|
||||||
{
|
{
|
||||||
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -430,9 +430,9 @@ namespace GleeBug
|
||||||
const auto info = foundInfo->second;
|
const auto info = foundInfo->second;
|
||||||
|
|
||||||
//TODO: check if the right type is accessed (ExceptionInformation[0])
|
//TODO: check if the right type is accessed (ExceptionInformation[0])
|
||||||
//FIXED:
|
//FIXED:
|
||||||
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
auto bpxPage = mProcess->memoryBreakpointPages.find(exceptionAddress & ~(PAGE_SIZE - 1));
|
||||||
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", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -449,13 +449,13 @@ namespace GleeBug
|
||||||
*/
|
*/
|
||||||
//ExceptionInformation[0] should be considered as 1 or 8, because these are for exceptions generated on write or execute.
|
//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.
|
//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)))
|
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.
|
//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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((exceptionRecord.ExceptionInformation[0] == 8) && (!(pageProperties.Type & 8)))
|
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.
|
//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;
|
return;
|
||||||
|
|
@ -470,7 +470,7 @@ namespace GleeBug
|
||||||
//TODO: execute the user callback (if present)
|
//TODO: execute the user callback (if present)
|
||||||
//FIXED:
|
//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())
|
||||||
{
|
{
|
||||||
bpxCb->second(info);
|
bpxCb->second(info);
|
||||||
}
|
}
|
||||||
|
|
@ -479,7 +479,7 @@ 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(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
if(!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
|
||||||
{
|
{
|
||||||
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
|
||||||
cbInternalError(error);
|
cbInternalError(error);
|
||||||
|
|
@ -492,7 +492,7 @@ namespace GleeBug
|
||||||
//-memoryBreakpointPages was in deed consistent with this memory address that generated the exception (The data structure wasn't corrupted somehow)
|
//-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.
|
//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:
|
//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
|
//-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.
|
// 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.
|
//-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.
|
// therefore, we do not enforce new protection.
|
||||||
|
|
@ -501,14 +501,14 @@ namespace GleeBug
|
||||||
//Check if the memory page is mapped
|
//Check if the memory page is mapped
|
||||||
|
|
||||||
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
auto found_page = mProcess->memoryBreakpointPages.find(pageAddr);
|
||||||
if (found_page != mProcess->memoryBreakpointPages.end())
|
if(found_page != mProcess->memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
mProcess->MemProtect(pageAddr, PAGE_SIZE, found_page->second.NewProtect);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (info.singleshoot)
|
if(info.singleshoot)
|
||||||
{
|
{
|
||||||
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
mProcess->DeleteMemoryBreakpoint(exceptionAddress);
|
||||||
}
|
}
|
||||||
|
|
@ -526,7 +526,7 @@ namespace GleeBug
|
||||||
cbExceptionEvent(exceptionInfo);
|
cbExceptionEvent(exceptionInfo);
|
||||||
|
|
||||||
//dispatch the exception (https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx)
|
//dispatch the exception (https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx)
|
||||||
switch (exceptionInfo.ExceptionRecord.ExceptionCode)
|
switch(exceptionInfo.ExceptionRecord.ExceptionCode)
|
||||||
{
|
{
|
||||||
case STATUS_BREAKPOINT:
|
case STATUS_BREAKPOINT:
|
||||||
exceptionBreakpoint(exceptionRecord, firstChance);
|
exceptionBreakpoint(exceptionRecord, firstChance);
|
||||||
|
|
@ -543,7 +543,7 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
//call the unhandled exception callback
|
//call the unhandled exception callback
|
||||||
if (mContinueStatus == DBG_EXCEPTION_NOT_HANDLED)
|
if(mContinueStatus == DBG_EXCEPTION_NOT_HANDLED)
|
||||||
cbUnhandledException(exceptionRecord, firstChance);
|
cbUnhandledException(exceptionRecord, firstChance);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -17,18 +17,20 @@ namespace GleeBug
|
||||||
|
|
||||||
//process housekeeping
|
//process housekeeping
|
||||||
mProcesses.insert({ mDebugEvent.dwProcessId,
|
mProcesses.insert({ mDebugEvent.dwProcessId,
|
||||||
std::make_unique<Process>(createProcess.hProcess,
|
std::make_unique<Process>(createProcess.hProcess,
|
||||||
mDebugEvent.dwProcessId,
|
mDebugEvent.dwProcessId,
|
||||||
mDebugEvent.dwThreadId,
|
mDebugEvent.dwThreadId,
|
||||||
createProcess) });
|
createProcess)
|
||||||
|
});
|
||||||
mProcess = mProcesses.find(mDebugEvent.dwProcessId)->second.get();
|
mProcess = mProcesses.find(mDebugEvent.dwProcessId)->second.get();
|
||||||
|
|
||||||
//thread housekeeping (main thread is created implicitly)
|
//thread housekeeping (main thread is created implicitly)
|
||||||
mProcess->threads.insert({ mDebugEvent.dwThreadId,
|
mProcess->threads.insert({ mDebugEvent.dwThreadId,
|
||||||
std::make_unique<Thread>(createProcess.hThread,
|
std::make_unique<Thread>(createProcess.hThread,
|
||||||
mDebugEvent.dwThreadId,
|
mDebugEvent.dwThreadId,
|
||||||
createProcess.lpThreadLocalBase,
|
createProcess.lpThreadLocalBase,
|
||||||
createProcess.lpStartAddress) });
|
createProcess.lpStartAddress)
|
||||||
|
});
|
||||||
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
|
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
|
|
@ -39,14 +41,14 @@ namespace GleeBug
|
||||||
CloseHandle(createProcess.hFile);
|
CloseHandle(createProcess.hFile);
|
||||||
|
|
||||||
//call attach breakpoint after process creation
|
//call attach breakpoint after process creation
|
||||||
if (attachBreakpoint)
|
if(attachBreakpoint)
|
||||||
cbAttachBreakpoint();
|
cbAttachBreakpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
|
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
|
||||||
{
|
{
|
||||||
//check if the terminated process is the main debuggee
|
//check if the terminated process is the main debuggee
|
||||||
if (mDebugEvent.dwProcessId == mMainProcess.dwProcessId)
|
if(mDebugEvent.dwProcessId == mMainProcess.dwProcessId)
|
||||||
mBreakDebugger = true;
|
mBreakDebugger = true;
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//thread housekeeping
|
//thread housekeeping
|
||||||
mProcess->threads.insert({ mDebugEvent.dwThreadId,
|
mProcess->threads.insert({ mDebugEvent.dwThreadId,
|
||||||
std::make_unique<Thread>(createThread.hThread,
|
std::make_unique<Thread>(createThread.hThread,
|
||||||
mDebugEvent.dwThreadId,
|
mDebugEvent.dwThreadId,
|
||||||
createThread.lpThreadLocalBase,
|
createThread.lpThreadLocalBase,
|
||||||
createThread.lpStartAddress) });
|
createThread.lpStartAddress)
|
||||||
|
});
|
||||||
|
|
||||||
//set the current thread
|
//set the current thread
|
||||||
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
|
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
|
||||||
|
|
|
||||||
|
|
@ -12,38 +12,38 @@ namespace GleeBug
|
||||||
mDetachAndBreak = false;
|
mDetachAndBreak = false;
|
||||||
|
|
||||||
//use correct WaitForDebugEvent function
|
//use correct WaitForDebugEvent function
|
||||||
typedef BOOL(WINAPI *MYWAITFORDEBUGEVENT)(
|
typedef BOOL(WINAPI * MYWAITFORDEBUGEVENT)(
|
||||||
_Out_ LPDEBUG_EVENT lpDebugEvent,
|
_Out_ LPDEBUG_EVENT lpDebugEvent,
|
||||||
_In_ DWORD dwMilliseconds
|
_In_ DWORD dwMilliseconds
|
||||||
);
|
);
|
||||||
static auto WFDEX = MYWAITFORDEBUGEVENT(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "WaitForDebugEventEx"));
|
static auto WFDEX = MYWAITFORDEBUGEVENT(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "WaitForDebugEventEx"));
|
||||||
static auto MyWaitForDebugEvent = WFDEX ? WFDEX : MYWAITFORDEBUGEVENT(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "WaitForDebugEvent"));
|
static auto MyWaitForDebugEvent = WFDEX ? WFDEX : MYWAITFORDEBUGEVENT(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "WaitForDebugEvent"));
|
||||||
if (!MyWaitForDebugEvent)
|
if(!MyWaitForDebugEvent)
|
||||||
{
|
{
|
||||||
cbInternalError("MyWaitForDebugEvent not set!");
|
cbInternalError("MyWaitForDebugEvent not set!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!mBreakDebugger)
|
while(!mBreakDebugger)
|
||||||
{
|
{
|
||||||
//wait for a debug event
|
//wait for a debug event
|
||||||
mIsRunning = true;
|
mIsRunning = true;
|
||||||
if (!MyWaitForDebugEvent(&mDebugEvent, 100))
|
if(!MyWaitForDebugEvent(&mDebugEvent, 100))
|
||||||
{
|
{
|
||||||
if (mDetach)
|
if(mDetach)
|
||||||
{
|
{
|
||||||
if (!UnsafeDetach())
|
if(!UnsafeDetach())
|
||||||
cbInternalError("Debugger::Detach failed!");
|
cbInternalError("Debugger::Detach failed!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
// Fix based on work by https://github.com/number201724
|
// Fix based on work by https://github.com/number201724
|
||||||
if (WaitForSingleObject(mMainProcess.hProcess, 0) == WAIT_OBJECT_0)
|
if(WaitForSingleObject(mMainProcess.hProcess, 0) == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
mDebugEvent.dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
|
mDebugEvent.dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
|
||||||
mDebugEvent.dwProcessId = mMainProcess.dwProcessId;
|
mDebugEvent.dwProcessId = mMainProcess.dwProcessId;
|
||||||
mDebugEvent.dwThreadId = mMainProcess.dwThreadId;
|
mDebugEvent.dwThreadId = mMainProcess.dwThreadId;
|
||||||
if (!GetExitCodeProcess(mMainProcess.hProcess, &mDebugEvent.u.ExitProcess.dwExitCode))
|
if(!GetExitCodeProcess(mMainProcess.hProcess, &mDebugEvent.u.ExitProcess.dwExitCode))
|
||||||
mDebugEvent.u.ExitProcess.dwExitCode = 0xFFFFFFFF;
|
mDebugEvent.u.ExitProcess.dwExitCode = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -60,11 +60,11 @@ namespace GleeBug
|
||||||
|
|
||||||
//set the current process and thread
|
//set the current process and thread
|
||||||
auto processFound = mProcesses.find(mDebugEvent.dwProcessId);
|
auto processFound = mProcesses.find(mDebugEvent.dwProcessId);
|
||||||
if (processFound != mProcesses.end())
|
if(processFound != mProcesses.end())
|
||||||
{
|
{
|
||||||
mProcess = processFound->second.get();
|
mProcess = processFound->second.get();
|
||||||
auto threadFound = mProcess->threads.find(mDebugEvent.dwThreadId);
|
auto threadFound = mProcess->threads.find(mDebugEvent.dwThreadId);
|
||||||
if (threadFound != mProcess->threads.end())
|
if(threadFound != mProcess->threads.end())
|
||||||
{
|
{
|
||||||
mThread = mProcess->thread = threadFound->second.get();
|
mThread = mProcess->thread = threadFound->second.get();
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ namespace GleeBug
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mThread = nullptr;
|
mThread = nullptr;
|
||||||
if (mProcess)
|
if(mProcess)
|
||||||
{
|
{
|
||||||
mProcess->thread = nullptr;
|
mProcess->thread = nullptr;
|
||||||
mProcess = nullptr;
|
mProcess = nullptr;
|
||||||
|
|
@ -87,7 +87,7 @@ namespace GleeBug
|
||||||
cbPreDebugEvent(mDebugEvent);
|
cbPreDebugEvent(mDebugEvent);
|
||||||
|
|
||||||
//dispatch the debug event (documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679302(v=vs.85).aspx)
|
//dispatch the debug event (documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679302(v=vs.85).aspx)
|
||||||
switch (mDebugEvent.dwDebugEventCode)
|
switch(mDebugEvent.dwDebugEventCode)
|
||||||
{
|
{
|
||||||
case CREATE_PROCESS_DEBUG_EVENT:
|
case CREATE_PROCESS_DEBUG_EVENT:
|
||||||
createProcessEvent(mDebugEvent.u.CreateProcessInfo);
|
createProcessEvent(mDebugEvent.u.CreateProcessInfo);
|
||||||
|
|
@ -125,27 +125,27 @@ namespace GleeBug
|
||||||
cbPostDebugEvent(mDebugEvent);
|
cbPostDebugEvent(mDebugEvent);
|
||||||
|
|
||||||
//execute the delayed-detach
|
//execute the delayed-detach
|
||||||
if (mDetachAndBreak)
|
if(mDetachAndBreak)
|
||||||
{
|
{
|
||||||
if (!UnsafeDetachAndBreak())
|
if(!UnsafeDetachAndBreak())
|
||||||
cbInternalError("Debugger::DetachAndBreak failed!");
|
cbInternalError("Debugger::DetachAndBreak failed!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear trap flag when set by GleeBug (to prevent an EXCEPTION_SINGLE_STEP after detach)
|
//clear trap flag when set by GleeBug (to prevent an EXCEPTION_SINGLE_STEP after detach)
|
||||||
if (mDetach && mThread)
|
if(mDetach && mThread)
|
||||||
{
|
{
|
||||||
if (mThread->isInternalStepping || mThread->isSingleStepping)
|
if(mThread->isInternalStepping || mThread->isSingleStepping)
|
||||||
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
|
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//continue the debug event
|
//continue the debug event
|
||||||
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
|
if(!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (mDetach || mDetachAndBreak)
|
if(mDetach || mDetachAndBreak)
|
||||||
{
|
{
|
||||||
if (!UnsafeDetach())
|
if(!UnsafeDetach())
|
||||||
cbInternalError("Debugger::Detach failed!");
|
cbInternalError("Debugger::Detach failed!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ namespace GleeBug
|
||||||
bool Process::SetBreakpoint(ptr address, bool singleshoot, SoftwareType type)
|
bool Process::SetBreakpoint(ptr address, bool singleshoot, SoftwareType type)
|
||||||
{
|
{
|
||||||
//check the address
|
//check the address
|
||||||
if (!MemIsValidPtr(address) ||
|
if(!MemIsValidPtr(address) ||
|
||||||
breakpoints.find({ BreakpointType::Software, address }) != breakpoints.end())
|
breakpoints.find({ BreakpointType::Software, address }) != breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//setup the breakpoint information struct
|
//setup the breakpoint information struct
|
||||||
|
|
@ -16,7 +16,7 @@ namespace GleeBug
|
||||||
info.type = BreakpointType::Software;
|
info.type = BreakpointType::Software;
|
||||||
|
|
||||||
//determine breakpoint byte and size from the type
|
//determine breakpoint byte and size from the type
|
||||||
switch (type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case SoftwareType::ShortInt3:
|
case SoftwareType::ShortInt3:
|
||||||
info.internal.software.newbytes[0] = 0xCC;
|
info.internal.software.newbytes[0] = 0xCC;
|
||||||
|
|
@ -28,10 +28,10 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
//read/write the breakpoint
|
//read/write the breakpoint
|
||||||
if (!MemReadUnsafe(address, info.internal.software.oldbytes, info.internal.software.size))
|
if(!MemReadUnsafe(address, info.internal.software.oldbytes, info.internal.software.size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!MemWriteUnsafe(address, info.internal.software.newbytes, info.internal.software.size))
|
if(!MemWriteUnsafe(address, info.internal.software.newbytes, info.internal.software.size))
|
||||||
return false;
|
return false;
|
||||||
FlushInstructionCache(hProcess, nullptr, 0);
|
FlushInstructionCache(hProcess, nullptr, 0);
|
||||||
|
|
||||||
|
|
@ -45,10 +45,10 @@ namespace GleeBug
|
||||||
bool Process::SetBreakpoint(ptr address, const BreakpointCallback & cbBreakpoint, bool singleshoot, SoftwareType type)
|
bool Process::SetBreakpoint(ptr address, const BreakpointCallback & cbBreakpoint, bool singleshoot, SoftwareType type)
|
||||||
{
|
{
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if (breakpointCallbacks.find({ BreakpointType::Software, address }) != breakpointCallbacks.end())
|
if(breakpointCallbacks.find({ BreakpointType::Software, address }) != breakpointCallbacks.end())
|
||||||
return false;
|
return false;
|
||||||
//set the breakpoint
|
//set the breakpoint
|
||||||
if (!SetBreakpoint(address, singleshoot, type))
|
if(!SetBreakpoint(address, singleshoot, type))
|
||||||
return false;
|
return false;
|
||||||
//insert the callback
|
//insert the callback
|
||||||
breakpointCallbacks.insert({ { BreakpointType::Software, address }, cbBreakpoint });
|
breakpointCallbacks.insert({ { BreakpointType::Software, address }, cbBreakpoint });
|
||||||
|
|
@ -59,12 +59,12 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//find the breakpoint
|
//find the breakpoint
|
||||||
auto found = breakpoints.find({ BreakpointType::Software, address });
|
auto found = breakpoints.find({ BreakpointType::Software, address });
|
||||||
if (found == breakpoints.end())
|
if(found == breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
const auto & info = found->second;
|
const auto & info = found->second;
|
||||||
|
|
||||||
//restore the breakpoint bytes
|
//restore the breakpoint bytes
|
||||||
if (!MemWriteUnsafe(address, info.internal.software.oldbytes, info.internal.software.size))
|
if(!MemWriteUnsafe(address, info.internal.software.oldbytes, info.internal.software.size))
|
||||||
return false;
|
return false;
|
||||||
FlushInstructionCache(hProcess, nullptr, 0);
|
FlushInstructionCache(hProcess, nullptr, 0);
|
||||||
|
|
||||||
|
|
@ -78,9 +78,9 @@ namespace GleeBug
|
||||||
bool Process::GetFreeHardwareBreakpointSlot(HardwareSlot & slot) const
|
bool Process::GetFreeHardwareBreakpointSlot(HardwareSlot & slot) const
|
||||||
{
|
{
|
||||||
//find a free hardware breakpoint slot
|
//find a free hardware breakpoint slot
|
||||||
for (int i = 0; i < HWBP_COUNT; i++)
|
for(int i = 0; i < HWBP_COUNT; i++)
|
||||||
{
|
{
|
||||||
if (!hardwareBreakpoints[i].internal.hardware.enabled)
|
if(!hardwareBreakpoints[i].internal.hardware.enabled)
|
||||||
{
|
{
|
||||||
slot = HardwareSlot(i);
|
slot = HardwareSlot(i);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -92,15 +92,15 @@ namespace GleeBug
|
||||||
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, HardwareType type, HardwareSize size, bool singleshoot)
|
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, HardwareType type, HardwareSize size, bool singleshoot)
|
||||||
{
|
{
|
||||||
//check the address
|
//check the address
|
||||||
if (!MemIsValidPtr(address) ||
|
if(!MemIsValidPtr(address) ||
|
||||||
breakpoints.find({ BreakpointType::Hardware, address }) != breakpoints.end())
|
breakpoints.find({ BreakpointType::Hardware, address }) != breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//attempt to set the hardware breakpoint in every thread
|
//attempt to set the hardware breakpoint in every thread
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (auto & thread : threads)
|
for(auto & thread : threads)
|
||||||
{
|
{
|
||||||
if (!thread.second->SetHardwareBreakpoint(address, slot, type, size))
|
if(!thread.second->SetHardwareBreakpoint(address, slot, type, size))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
|
|
@ -108,9 +108,9 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
//if setting failed, unset all
|
//if setting failed, unset all
|
||||||
if (!success)
|
if(!success)
|
||||||
{
|
{
|
||||||
for (auto & thread : threads)
|
for(auto & thread : threads)
|
||||||
thread.second->DeleteHardwareBreakpoint(slot);
|
thread.second->DeleteHardwareBreakpoint(slot);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -137,10 +137,10 @@ namespace GleeBug
|
||||||
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, const BreakpointCallback & cbBreakpoint, HardwareType type, HardwareSize size, bool singleshoot)
|
bool Process::SetHardwareBreakpoint(ptr address, HardwareSlot slot, const BreakpointCallback & cbBreakpoint, HardwareType type, HardwareSize size, bool singleshoot)
|
||||||
{
|
{
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
if(breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
|
||||||
return false;
|
return false;
|
||||||
//set the hardware breakpoint
|
//set the hardware breakpoint
|
||||||
if (!SetHardwareBreakpoint(address, slot, type, size, singleshoot))
|
if(!SetHardwareBreakpoint(address, slot, type, size, singleshoot))
|
||||||
return false;
|
return false;
|
||||||
//insert the callback
|
//insert the callback
|
||||||
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
|
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
|
||||||
|
|
@ -151,7 +151,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//find the hardware breakpoint
|
//find the hardware breakpoint
|
||||||
auto found = breakpoints.find({ BreakpointType::Hardware, address });
|
auto found = breakpoints.find({ BreakpointType::Hardware, address });
|
||||||
if (found == breakpoints.end())
|
if(found == breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
const auto & info = found->second;
|
const auto & info = found->second;
|
||||||
|
|
||||||
|
|
@ -160,9 +160,9 @@ namespace GleeBug
|
||||||
|
|
||||||
//delete the hardware breakpoint from the registers
|
//delete the hardware breakpoint from the registers
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (auto & thread : threads)
|
for(auto & thread : threads)
|
||||||
{
|
{
|
||||||
if (!thread.second->DeleteHardwareBreakpoint(info.internal.hardware.slot))
|
if(!thread.second->DeleteHardwareBreakpoint(info.internal.hardware.slot))
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,7 +198,7 @@ namespace GleeBug
|
||||||
//These settings can trigger access violation.
|
//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)
|
||||||
{
|
{
|
||||||
case PAGE_EXECUTE:
|
case PAGE_EXECUTE:
|
||||||
return dwHigh | PAGE_READONLY;
|
return dwHigh | PAGE_READONLY;
|
||||||
|
|
@ -214,7 +214,7 @@ namespace GleeBug
|
||||||
static DWORD RemoveWriteAccess(DWORD dwAccess)
|
static DWORD RemoveWriteAccess(DWORD dwAccess)
|
||||||
{
|
{
|
||||||
DWORD dwBase = dwAccess & 0xFF;
|
DWORD dwBase = dwAccess & 0xFF;
|
||||||
switch (dwBase)
|
switch(dwBase)
|
||||||
{
|
{
|
||||||
case PAGE_READWRITE:
|
case PAGE_READWRITE:
|
||||||
case PAGE_EXECUTE_READWRITE:
|
case PAGE_EXECUTE_READWRITE:
|
||||||
|
|
@ -230,10 +230,10 @@ namespace GleeBug
|
||||||
//TODO: handle PAGE_NOACCESS and such correctly (since it cannot be combined with PAGE_GUARD)
|
//TODO: handle PAGE_NOACCESS and such correctly (since it cannot be combined with PAGE_GUARD)
|
||||||
|
|
||||||
auto found = memoryBreakpointPages.find(page);
|
auto found = memoryBreakpointPages.find(page);
|
||||||
if (found == memoryBreakpointPages.end())
|
if(found == memoryBreakpointPages.end())
|
||||||
{
|
{
|
||||||
data.Refcount = 1;
|
data.Refcount = 1;
|
||||||
switch (type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case MemoryType::Access:
|
case MemoryType::Access:
|
||||||
case MemoryType::Read:
|
case MemoryType::Read:
|
||||||
|
|
@ -253,13 +253,13 @@ namespace GleeBug
|
||||||
data.Type = oldData.Type | uint32(type); //combines new protection
|
data.Type = oldData.Type | uint32(type); //combines new protection
|
||||||
data.OldProtect = oldData.OldProtect; // old protection remains the same
|
data.OldProtect = oldData.OldProtect; // old protection remains the same
|
||||||
data.Refcount = oldData.Refcount + 1; //increment reference count
|
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.
|
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;
|
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?
|
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
|
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
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,12 +274,12 @@ namespace GleeBug
|
||||||
//TODO: error reporting
|
//TODO: error reporting
|
||||||
|
|
||||||
//basic checks
|
//basic checks
|
||||||
if (!MemIsValidPtr(address) || !size)
|
if(!MemIsValidPtr(address) || !size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//check if the range is unused for any previous memory breakpoints
|
//check if the range is unused for any previous memory breakpoints
|
||||||
auto range = Range(address, address + size - 1);
|
auto range = Range(address, address + size - 1);
|
||||||
if (memoryBreakpointRanges.find(range) != memoryBreakpointRanges.end())
|
if(memoryBreakpointRanges.find(range) != memoryBreakpointRanges.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//change page protections
|
//change page protections
|
||||||
|
|
@ -297,17 +297,17 @@ namespace GleeBug
|
||||||
MemoryBreakpointData data;
|
MemoryBreakpointData data;
|
||||||
data.Type = uint32(type);
|
data.Type = uint32(type);
|
||||||
auto alignedAddress = PAGE_ALIGN(address);
|
auto alignedAddress = PAGE_ALIGN(address);
|
||||||
for (auto page = alignedAddress; page < alignedAddress + ROUND_TO_PAGES(size); page += PAGE_SIZE)
|
for(auto page = alignedAddress; page < alignedAddress + ROUND_TO_PAGES(size); page += PAGE_SIZE)
|
||||||
{
|
{
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
if (!VirtualQueryEx(hProcess, LPCVOID(page), &mbi, sizeof(mbi)))
|
if(!VirtualQueryEx(hProcess, LPCVOID(page), &mbi, sizeof(mbi)))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
dprintf("!VirtualQueryEx\n");
|
dprintf("!VirtualQueryEx\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data.OldProtect = mbi.Protect;
|
data.OldProtect = mbi.Protect;
|
||||||
if (!SetNewPageProtection(page, data, type))
|
if(!SetNewPageProtection(page, data, type))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
dprintf("!SetNewPageProtection\n");
|
dprintf("!SetNewPageProtection\n");
|
||||||
|
|
@ -321,15 +321,15 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
//if changing the page protections failed, attempt to revert all protection changes
|
//if changing the page protections failed, attempt to revert all protection changes
|
||||||
if (!success)
|
if(!success)
|
||||||
{
|
{
|
||||||
for (const auto & page : breakpointData)
|
for(const auto & page : breakpointData)
|
||||||
MemProtect(page.addr, PAGE_SIZE, page.OldProtect);
|
MemProtect(page.addr, PAGE_SIZE, page.OldProtect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set the page data
|
//set the page data
|
||||||
for (const auto & page : breakpointData)
|
for(const auto & page : breakpointData)
|
||||||
memoryBreakpointPages[page.addr] = page.data;
|
memoryBreakpointPages[page.addr] = page.data;
|
||||||
|
|
||||||
//setup the breakpoint information struct
|
//setup the breakpoint information struct
|
||||||
|
|
@ -350,10 +350,10 @@ namespace GleeBug
|
||||||
bool Process::SetMemoryBreakpoint(ptr address, ptr size, const BreakpointCallback & cbBreakpoint, MemoryType type, bool singleshoot)
|
bool Process::SetMemoryBreakpoint(ptr address, ptr size, const BreakpointCallback & cbBreakpoint, MemoryType type, bool singleshoot)
|
||||||
{
|
{
|
||||||
//check if a callback on this address was already found
|
//check if a callback on this address was already found
|
||||||
if (breakpointCallbacks.find({ BreakpointType::Memory, address }) != breakpointCallbacks.end())
|
if(breakpointCallbacks.find({ BreakpointType::Memory, address }) != breakpointCallbacks.end())
|
||||||
return false;
|
return false;
|
||||||
//set the memory breakpoint
|
//set the memory breakpoint
|
||||||
if (!SetMemoryBreakpoint(address, size, type, singleshoot))
|
if(!SetMemoryBreakpoint(address, size, type, singleshoot))
|
||||||
return false;
|
return false;
|
||||||
//insert the callback
|
//insert the callback
|
||||||
breakpointCallbacks.insert({ { BreakpointType::Memory, address }, cbBreakpoint });
|
breakpointCallbacks.insert({ { BreakpointType::Memory, address }, cbBreakpoint });
|
||||||
|
|
@ -369,35 +369,35 @@ namespace GleeBug
|
||||||
|
|
||||||
//find the memory breakpoint
|
//find the memory breakpoint
|
||||||
auto found = breakpoints.find({ BreakpointType::Memory, range->first });
|
auto found = breakpoints.find({ BreakpointType::Memory, range->first });
|
||||||
if (found == breakpoints.end())
|
if(found == breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
const auto & info = found->second;
|
const auto & info = found->second;
|
||||||
|
|
||||||
//delete the memory breakpoint from the pages
|
//delete the memory breakpoint from the pages
|
||||||
bool success = true;
|
bool success = true;
|
||||||
auto alignedAddress = PAGE_ALIGN(info.address);
|
auto alignedAddress = PAGE_ALIGN(info.address);
|
||||||
for (auto page = alignedAddress; page < alignedAddress + ROUND_TO_PAGES(info.internal.memory.size); page += PAGE_SIZE)
|
for(auto page = alignedAddress; page < alignedAddress + ROUND_TO_PAGES(info.internal.memory.size); page += PAGE_SIZE)
|
||||||
{
|
{
|
||||||
auto foundData = memoryBreakpointPages.find(page);
|
auto foundData = memoryBreakpointPages.find(page);
|
||||||
if (foundData == memoryBreakpointPages.end())
|
if(foundData == memoryBreakpointPages.end())
|
||||||
continue; //TODO: error reporting
|
continue; //TODO: error reporting
|
||||||
auto & data = foundData->second;
|
auto & data = foundData->second;
|
||||||
DWORD Protect;
|
DWORD Protect;
|
||||||
data.Refcount--;
|
data.Refcount--;
|
||||||
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?
|
//Are there any other protections left?
|
||||||
//If so add the guard
|
//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;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Protect = data.OldProtect;
|
Protect = data.OldProtect;
|
||||||
if (!MemProtect(page, PAGE_SIZE, Protect))
|
if(!MemProtect(page, PAGE_SIZE, Protect))
|
||||||
success = false;
|
success = false;
|
||||||
if (!data.Refcount)
|
if(!data.Refcount)
|
||||||
memoryBreakpointPages.erase(foundData);
|
memoryBreakpointPages.erase(foundData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,7 +410,7 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Process::DeleteGenericBreakpoint(const BreakpointInfo & info)
|
bool Process::DeleteGenericBreakpoint(const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
switch (info.type)
|
switch(info.type)
|
||||||
{
|
{
|
||||||
case BreakpointType::Software:
|
case BreakpointType::Software:
|
||||||
return DeleteBreakpoint(info.address);
|
return DeleteBreakpoint(info.address);
|
||||||
|
|
|
||||||
|
|
@ -6,46 +6,46 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//TODO: change page protection if reading failed
|
//TODO: change page protection if reading failed
|
||||||
ptr read;
|
ptr read;
|
||||||
if (!bytesRead)
|
if(!bytesRead)
|
||||||
bytesRead = &read;
|
bytesRead = &read;
|
||||||
return !!ReadProcessMemory(this->hProcess, reinterpret_cast<const void*>(address), buffer, size, (SIZE_T*)bytesRead);
|
return !!ReadProcessMemory(this->hProcess, reinterpret_cast<const void*>(address), buffer, size, (SIZE_T*)bytesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process::MemReadSafe(ptr address, void* buffer, ptr size, ptr* bytesRead) const
|
bool Process::MemReadSafe(ptr address, void* buffer, ptr size, ptr* bytesRead) const
|
||||||
{
|
{
|
||||||
if (!MemReadUnsafe(address, buffer, size, bytesRead))
|
if(!MemReadUnsafe(address, buffer, size, bytesRead))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//choose the filter method that has the lowest cost
|
//choose the filter method that has the lowest cost
|
||||||
auto start = address;
|
auto start = address;
|
||||||
auto end = start + size;
|
auto end = start + size;
|
||||||
if (size > breakpoints.size())
|
if(size > breakpoints.size())
|
||||||
{
|
{
|
||||||
for (const auto & breakpoint : breakpoints)
|
for(const auto & breakpoint : breakpoints)
|
||||||
{
|
{
|
||||||
if (breakpoint.first.first != BreakpointType::Software)
|
if(breakpoint.first.first != BreakpointType::Software)
|
||||||
continue;
|
continue;
|
||||||
const auto & info = breakpoint.second;
|
const auto & info = breakpoint.second;
|
||||||
auto curAddress = info.address;
|
auto curAddress = info.address;
|
||||||
for (ptr j = 0; j < info.internal.software.size; j++)
|
for(ptr j = 0; j < info.internal.software.size; j++)
|
||||||
{
|
{
|
||||||
if (curAddress + j >= start && curAddress + j < end)
|
if(curAddress + j >= start && curAddress + j < end)
|
||||||
((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j];
|
((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (ptr i = start; i < end; i++)
|
for(ptr i = start; i < end; i++)
|
||||||
{
|
{
|
||||||
auto found = softwareBreakpointReferences.find(i);
|
auto found = softwareBreakpointReferences.find(i);
|
||||||
if (found == softwareBreakpointReferences.end())
|
if(found == softwareBreakpointReferences.end())
|
||||||
continue;
|
continue;
|
||||||
const auto & info = found->second->second;
|
const auto & info = found->second->second;
|
||||||
auto curAddress = info.address;
|
auto curAddress = info.address;
|
||||||
for (ptr j = 0; j < info.internal.software.size && i < end; j++, i++)
|
for(ptr j = 0; j < info.internal.software.size && i < end; j++, i++)
|
||||||
{
|
{
|
||||||
if (curAddress + j >= start && curAddress + j < end)
|
if(curAddress + j >= start && curAddress + j < end)
|
||||||
((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j];
|
((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j];
|
||||||
}
|
}
|
||||||
i += info.internal.software.size - 1;
|
i += info.internal.software.size - 1;
|
||||||
|
|
@ -58,7 +58,7 @@ namespace GleeBug
|
||||||
bool Process::MemWriteUnsafe(ptr address, const void* buffer, ptr size, ptr* bytesWritten)
|
bool Process::MemWriteUnsafe(ptr address, const void* buffer, ptr size, ptr* bytesWritten)
|
||||||
{
|
{
|
||||||
ptr written;
|
ptr written;
|
||||||
if (!bytesWritten)
|
if(!bytesWritten)
|
||||||
bytesWritten = &written;
|
bytesWritten = &written;
|
||||||
return !!WriteProcessMemory(this->hProcess, reinterpret_cast<void*>(address), buffer, size, (SIZE_T*)bytesWritten);
|
return !!WriteProcessMemory(this->hProcess, reinterpret_cast<void*>(address), buffer, size, (SIZE_T*)bytesWritten);
|
||||||
}
|
}
|
||||||
|
|
@ -79,9 +79,9 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
DWORD dwOldProtect;
|
DWORD dwOldProtect;
|
||||||
auto vps = VirtualProtectEx(hProcess, LPVOID(address), size, newProtect, &dwOldProtect);
|
auto vps = VirtualProtectEx(hProcess, LPVOID(address), size, newProtect, &dwOldProtect);
|
||||||
if (!vps)
|
if(!vps)
|
||||||
return false;
|
return false;
|
||||||
if (oldProtect)
|
if(oldProtect)
|
||||||
*oldProtect = dwOldProtect;
|
*oldProtect = dwOldProtect;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +89,7 @@ namespace GleeBug
|
||||||
ptr Process::MemFindPattern(ptr data, size_t datasize, const Pattern::WildcardPattern & pattern, bool safe) const
|
ptr Process::MemFindPattern(ptr data, size_t datasize, const Pattern::WildcardPattern & pattern, bool safe) const
|
||||||
{
|
{
|
||||||
std::vector<uint8> buffer(datasize);
|
std::vector<uint8> buffer(datasize);
|
||||||
if (!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
if(!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
||||||
return 0;
|
return 0;
|
||||||
auto found = Pattern::Find(buffer.data(), datasize, pattern);
|
auto found = Pattern::Find(buffer.data(), datasize, pattern);
|
||||||
return found == -1 ? 0 : found + data;
|
return found == -1 ? 0 : found + data;
|
||||||
|
|
@ -98,7 +98,7 @@ namespace GleeBug
|
||||||
ptr Process::MemFindPattern(ptr data, size_t datasize, const uint8* pattern, size_t patternsize, bool safe) const
|
ptr Process::MemFindPattern(ptr data, size_t datasize, const uint8* pattern, size_t patternsize, bool safe) const
|
||||||
{
|
{
|
||||||
std::vector<uint8> buffer(datasize);
|
std::vector<uint8> buffer(datasize);
|
||||||
if (!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
if(!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
||||||
return 0;
|
return 0;
|
||||||
auto found = Pattern::Find(buffer.data(), datasize, pattern, patternsize);
|
auto found = Pattern::Find(buffer.data(), datasize, pattern, patternsize);
|
||||||
return found == -1 ? 0 : found + data;
|
return found == -1 ? 0 : found + data;
|
||||||
|
|
@ -107,7 +107,7 @@ namespace GleeBug
|
||||||
bool Process::MemWritePattern(ptr data, size_t datasize, const Pattern::WildcardPattern & pattern, bool safe)
|
bool Process::MemWritePattern(ptr data, size_t datasize, const Pattern::WildcardPattern & pattern, bool safe)
|
||||||
{
|
{
|
||||||
std::vector<uint8> buffer(datasize);
|
std::vector<uint8> buffer(datasize);
|
||||||
if (!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
if(!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
||||||
return false;
|
return false;
|
||||||
Pattern::Write(buffer.data(), datasize, pattern);
|
Pattern::Write(buffer.data(), datasize, pattern);
|
||||||
return MemWrite(data, buffer.data(), datasize, nullptr, safe);
|
return MemWrite(data, buffer.data(), datasize, nullptr, safe);
|
||||||
|
|
@ -116,9 +116,9 @@ namespace GleeBug
|
||||||
bool Process::MemSearchAndReplace(ptr data, size_t datasize, const Pattern::WildcardPattern & searchpattern, const Pattern::WildcardPattern & replacepattern, bool safe)
|
bool Process::MemSearchAndReplace(ptr data, size_t datasize, const Pattern::WildcardPattern & searchpattern, const Pattern::WildcardPattern & replacepattern, bool safe)
|
||||||
{
|
{
|
||||||
std::vector<uint8> buffer(datasize);
|
std::vector<uint8> buffer(datasize);
|
||||||
if (!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
if(!MemRead(data, buffer.data(), datasize, nullptr, safe))
|
||||||
return false;
|
return false;
|
||||||
if (!Pattern::SearchAndReplace(buffer.data(), datasize, searchpattern, replacepattern))
|
if(!Pattern::SearchAndReplace(buffer.data(), datasize, searchpattern, replacepattern))
|
||||||
return false;
|
return false;
|
||||||
return MemWrite(data, buffer.data(), datasize, nullptr, safe);
|
return MemWrite(data, buffer.data(), datasize, nullptr, safe);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace GleeBug
|
||||||
systemBreakpoint(false),
|
systemBreakpoint(false),
|
||||||
permanentDep(false)
|
permanentDep(false)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < HWBP_COUNT; i++)
|
for(int i = 0; i < HWBP_COUNT; i++)
|
||||||
hardwareBreakpoints[i].internal.hardware.enabled = false;
|
hardwareBreakpoints[i].internal.hardware.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
auto gip = Registers(thread->hThread, CONTEXT_CONTROL).Gip();
|
auto gip = Registers(thread->hThread, CONTEXT_CONTROL).Gip();
|
||||||
unsigned char data[16];
|
unsigned char data[16];
|
||||||
if (MemReadSafe(gip, data, sizeof(data)))
|
if(MemReadSafe(gip, data, sizeof(data)))
|
||||||
{
|
{
|
||||||
ZydisInstructionInfo info;
|
ZydisInstructionInfo info;
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
@ -47,7 +47,7 @@ namespace GleeBug
|
||||||
stepOver = (info.attributes & repAttributes) != 0;
|
stepOver = (info.attributes & repAttributes) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stepOver)
|
if(stepOver)
|
||||||
{
|
{
|
||||||
SetBreakpoint(gip + info.length, [cbStep](const BreakpointInfo & info)
|
SetBreakpoint(gip + info.length, [cbStep](const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ namespace GleeBug
|
||||||
*/
|
*/
|
||||||
bool MemRead(ptr address, void* buffer, ptr size, ptr* bytesRead = nullptr, bool safe = true) const
|
bool MemRead(ptr address, void* buffer, ptr size, ptr* bytesRead = nullptr, bool safe = true) const
|
||||||
{
|
{
|
||||||
if (safe)
|
if(safe)
|
||||||
return MemReadSafe(address, buffer, size, bytesRead);
|
return MemReadSafe(address, buffer, size, bytesRead);
|
||||||
return MemRead(address, buffer, size, bytesRead);
|
return MemRead(address, buffer, size, bytesRead);
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ namespace GleeBug
|
||||||
*/
|
*/
|
||||||
bool MemWrite(ptr address, const void* buffer, ptr size, ptr* bytesWritten = nullptr, bool safe = true)
|
bool MemWrite(ptr address, const void* buffer, ptr size, ptr* bytesWritten = nullptr, bool safe = true)
|
||||||
{
|
{
|
||||||
if (safe)
|
if(safe)
|
||||||
return MemWriteSafe(address, buffer, size, bytesWritten);
|
return MemWriteSafe(address, buffer, size, bytesWritten);
|
||||||
return MemWriteUnsafe(address, buffer, size, bytesWritten);
|
return MemWriteUnsafe(address, buffer, size, bytesWritten);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,53 +41,53 @@ namespace GleeBug
|
||||||
static ptr dr7_ptr(const DR7 & dr7)
|
static ptr dr7_ptr(const DR7 & dr7)
|
||||||
{
|
{
|
||||||
ptr result = 0;
|
ptr result = 0;
|
||||||
if (BITGET(dr7.DR7_MODE[0], 0))
|
if(BITGET(dr7.DR7_MODE[0], 0))
|
||||||
BITSET(result, 0);
|
BITSET(result, 0);
|
||||||
if (BITGET(dr7.DR7_MODE[0], 1))
|
if(BITGET(dr7.DR7_MODE[0], 1))
|
||||||
BITSET(result, 1);
|
BITSET(result, 1);
|
||||||
if (BITGET(dr7.DR7_MODE[1], 0))
|
if(BITGET(dr7.DR7_MODE[1], 0))
|
||||||
BITSET(result, 2);
|
BITSET(result, 2);
|
||||||
if (BITGET(dr7.DR7_MODE[1], 1))
|
if(BITGET(dr7.DR7_MODE[1], 1))
|
||||||
BITSET(result, 3);
|
BITSET(result, 3);
|
||||||
if (BITGET(dr7.DR7_MODE[2], 0))
|
if(BITGET(dr7.DR7_MODE[2], 0))
|
||||||
BITSET(result, 4);
|
BITSET(result, 4);
|
||||||
if (BITGET(dr7.DR7_MODE[2], 1))
|
if(BITGET(dr7.DR7_MODE[2], 1))
|
||||||
BITSET(result, 5);
|
BITSET(result, 5);
|
||||||
if (BITGET(dr7.DR7_MODE[3], 0))
|
if(BITGET(dr7.DR7_MODE[3], 0))
|
||||||
BITSET(result, 6);
|
BITSET(result, 6);
|
||||||
if (BITGET(dr7.DR7_MODE[3], 1))
|
if(BITGET(dr7.DR7_MODE[3], 1))
|
||||||
BITSET(result, 7);
|
BITSET(result, 7);
|
||||||
if (BITGET(dr7.DR7_TYPE[0], 0))
|
if(BITGET(dr7.DR7_TYPE[0], 0))
|
||||||
BITSET(result, 16);
|
BITSET(result, 16);
|
||||||
if (BITGET(dr7.DR7_TYPE[0], 1))
|
if(BITGET(dr7.DR7_TYPE[0], 1))
|
||||||
BITSET(result, 17);
|
BITSET(result, 17);
|
||||||
if (BITGET(dr7.DR7_SIZE[0], 0))
|
if(BITGET(dr7.DR7_SIZE[0], 0))
|
||||||
BITSET(result, 18);
|
BITSET(result, 18);
|
||||||
if (BITGET(dr7.DR7_SIZE[0], 1))
|
if(BITGET(dr7.DR7_SIZE[0], 1))
|
||||||
BITSET(result, 19);
|
BITSET(result, 19);
|
||||||
if (BITGET(dr7.DR7_TYPE[1], 0))
|
if(BITGET(dr7.DR7_TYPE[1], 0))
|
||||||
BITSET(result, 20);
|
BITSET(result, 20);
|
||||||
if (BITGET(dr7.DR7_TYPE[1], 1))
|
if(BITGET(dr7.DR7_TYPE[1], 1))
|
||||||
BITSET(result, 21);
|
BITSET(result, 21);
|
||||||
if (BITGET(dr7.DR7_SIZE[1], 0))
|
if(BITGET(dr7.DR7_SIZE[1], 0))
|
||||||
BITSET(result, 22);
|
BITSET(result, 22);
|
||||||
if (BITGET(dr7.DR7_SIZE[1], 1))
|
if(BITGET(dr7.DR7_SIZE[1], 1))
|
||||||
BITSET(result, 23);
|
BITSET(result, 23);
|
||||||
if (BITGET(dr7.DR7_TYPE[2], 0))
|
if(BITGET(dr7.DR7_TYPE[2], 0))
|
||||||
BITSET(result, 24);
|
BITSET(result, 24);
|
||||||
if (BITGET(dr7.DR7_TYPE[2], 1))
|
if(BITGET(dr7.DR7_TYPE[2], 1))
|
||||||
BITSET(result, 25);
|
BITSET(result, 25);
|
||||||
if (BITGET(dr7.DR7_SIZE[2], 0))
|
if(BITGET(dr7.DR7_SIZE[2], 0))
|
||||||
BITSET(result, 26);
|
BITSET(result, 26);
|
||||||
if (BITGET(dr7.DR7_SIZE[2], 1))
|
if(BITGET(dr7.DR7_SIZE[2], 1))
|
||||||
BITSET(result, 27);
|
BITSET(result, 27);
|
||||||
if (BITGET(dr7.DR7_TYPE[3], 0))
|
if(BITGET(dr7.DR7_TYPE[3], 0))
|
||||||
BITSET(result, 28);
|
BITSET(result, 28);
|
||||||
if (BITGET(dr7.DR7_TYPE[3], 1))
|
if(BITGET(dr7.DR7_TYPE[3], 1))
|
||||||
BITSET(result, 29);
|
BITSET(result, 29);
|
||||||
if (BITGET(dr7.DR7_SIZE[3], 0))
|
if(BITGET(dr7.DR7_SIZE[3], 0))
|
||||||
BITSET(result, 30);
|
BITSET(result, 30);
|
||||||
if (BITGET(dr7.DR7_SIZE[3], 1))
|
if(BITGET(dr7.DR7_SIZE[3], 1))
|
||||||
BITSET(result, 31);
|
BITSET(result, 31);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -96,60 +96,60 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
DR7 result;
|
DR7 result;
|
||||||
memset(&result, 0, sizeof(DR7));
|
memset(&result, 0, sizeof(DR7));
|
||||||
if (BITGET(dr7, 0))
|
if(BITGET(dr7, 0))
|
||||||
BITSET(result.DR7_MODE[0], 0);
|
BITSET(result.DR7_MODE[0], 0);
|
||||||
if (BITGET(dr7, 1))
|
if(BITGET(dr7, 1))
|
||||||
BITSET(result.DR7_MODE[0], 1);
|
BITSET(result.DR7_MODE[0], 1);
|
||||||
if (BITGET(dr7, 2))
|
if(BITGET(dr7, 2))
|
||||||
BITSET(result.DR7_MODE[1], 0);
|
BITSET(result.DR7_MODE[1], 0);
|
||||||
if (BITGET(dr7, 3))
|
if(BITGET(dr7, 3))
|
||||||
BITSET(result.DR7_MODE[1], 1);
|
BITSET(result.DR7_MODE[1], 1);
|
||||||
if (BITGET(dr7, 4))
|
if(BITGET(dr7, 4))
|
||||||
BITSET(result.DR7_MODE[2], 0);
|
BITSET(result.DR7_MODE[2], 0);
|
||||||
if (BITGET(dr7, 5))
|
if(BITGET(dr7, 5))
|
||||||
BITSET(result.DR7_MODE[2], 1);
|
BITSET(result.DR7_MODE[2], 1);
|
||||||
if (BITGET(dr7, 6))
|
if(BITGET(dr7, 6))
|
||||||
BITSET(result.DR7_MODE[3], 0);
|
BITSET(result.DR7_MODE[3], 0);
|
||||||
if (BITGET(dr7, 7))
|
if(BITGET(dr7, 7))
|
||||||
BITSET(result.DR7_MODE[3], 1);
|
BITSET(result.DR7_MODE[3], 1);
|
||||||
if (BITGET(dr7, 16))
|
if(BITGET(dr7, 16))
|
||||||
BITSET(result.DR7_TYPE[0], 0);
|
BITSET(result.DR7_TYPE[0], 0);
|
||||||
if (BITGET(dr7, 17))
|
if(BITGET(dr7, 17))
|
||||||
BITSET(result.DR7_TYPE[0], 1);
|
BITSET(result.DR7_TYPE[0], 1);
|
||||||
if (BITGET(dr7, 18))
|
if(BITGET(dr7, 18))
|
||||||
BITSET(result.DR7_SIZE[0], 0);
|
BITSET(result.DR7_SIZE[0], 0);
|
||||||
if (BITGET(dr7, 19))
|
if(BITGET(dr7, 19))
|
||||||
BITSET(result.DR7_SIZE[0], 1);
|
BITSET(result.DR7_SIZE[0], 1);
|
||||||
if (BITGET(dr7, 20))
|
if(BITGET(dr7, 20))
|
||||||
BITSET(result.DR7_TYPE[1], 0);
|
BITSET(result.DR7_TYPE[1], 0);
|
||||||
if (BITGET(dr7, 21))
|
if(BITGET(dr7, 21))
|
||||||
BITSET(result.DR7_TYPE[1], 1);
|
BITSET(result.DR7_TYPE[1], 1);
|
||||||
if (BITGET(dr7, 22))
|
if(BITGET(dr7, 22))
|
||||||
BITSET(result.DR7_SIZE[1], 0);
|
BITSET(result.DR7_SIZE[1], 0);
|
||||||
if (BITGET(dr7, 23))
|
if(BITGET(dr7, 23))
|
||||||
BITSET(result.DR7_SIZE[1], 1);
|
BITSET(result.DR7_SIZE[1], 1);
|
||||||
if (BITGET(dr7, 24))
|
if(BITGET(dr7, 24))
|
||||||
BITSET(result.DR7_TYPE[2], 0);
|
BITSET(result.DR7_TYPE[2], 0);
|
||||||
if (BITGET(dr7, 25))
|
if(BITGET(dr7, 25))
|
||||||
BITSET(result.DR7_TYPE[2], 1);
|
BITSET(result.DR7_TYPE[2], 1);
|
||||||
if (BITGET(dr7, 26))
|
if(BITGET(dr7, 26))
|
||||||
BITSET(result.DR7_SIZE[2], 0);
|
BITSET(result.DR7_SIZE[2], 0);
|
||||||
if (BITGET(dr7, 27))
|
if(BITGET(dr7, 27))
|
||||||
BITSET(result.DR7_SIZE[2], 1);
|
BITSET(result.DR7_SIZE[2], 1);
|
||||||
if (BITGET(dr7, 28))
|
if(BITGET(dr7, 28))
|
||||||
BITSET(result.DR7_TYPE[3], 0);
|
BITSET(result.DR7_TYPE[3], 0);
|
||||||
if (BITGET(dr7, 29))
|
if(BITGET(dr7, 29))
|
||||||
BITSET(result.DR7_TYPE[3], 1);
|
BITSET(result.DR7_TYPE[3], 1);
|
||||||
if (BITGET(dr7, 30))
|
if(BITGET(dr7, 30))
|
||||||
BITSET(result.DR7_SIZE[3], 0);
|
BITSET(result.DR7_SIZE[3], 0);
|
||||||
if (BITGET(dr7, 31))
|
if(BITGET(dr7, 31))
|
||||||
BITSET(result.DR7_SIZE[3], 1);
|
BITSET(result.DR7_SIZE[3], 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DR7_SIZE size_dr7(HardwareSize size)
|
static DR7_SIZE size_dr7(HardwareSize size)
|
||||||
{
|
{
|
||||||
switch (size)
|
switch(size)
|
||||||
{
|
{
|
||||||
case HardwareSize::SizeByte:
|
case HardwareSize::SizeByte:
|
||||||
return SIZE_1;
|
return SIZE_1;
|
||||||
|
|
@ -168,7 +168,7 @@ namespace GleeBug
|
||||||
|
|
||||||
static DR7_TYPE type_dr7(HardwareType type)
|
static DR7_TYPE type_dr7(HardwareType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case HardwareType::Access:
|
case HardwareType::Access:
|
||||||
return TYPE_READWRITE;
|
return TYPE_READWRITE;
|
||||||
|
|
@ -184,13 +184,13 @@ namespace GleeBug
|
||||||
bool Thread::SetHardwareBreakpoint(ptr address, HardwareSlot slot, HardwareType type, HardwareSize size)
|
bool Thread::SetHardwareBreakpoint(ptr address, HardwareSlot slot, HardwareType type, HardwareSize size)
|
||||||
{
|
{
|
||||||
//check if the alignment is correct
|
//check if the alignment is correct
|
||||||
if ((address % int(size) != 0))
|
if((address % int(size) != 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Registers registers(hThread, CONTEXT_DEBUG_REGISTERS);
|
Registers registers(hThread, CONTEXT_DEBUG_REGISTERS);
|
||||||
|
|
||||||
//set the address register
|
//set the address register
|
||||||
switch (slot)
|
switch(slot)
|
||||||
{
|
{
|
||||||
case HardwareSlot::Dr0:
|
case HardwareSlot::Dr0:
|
||||||
registers.Dr0 = address;
|
registers.Dr0 = address;
|
||||||
|
|
@ -224,7 +224,7 @@ namespace GleeBug
|
||||||
Registers registers(hThread, CONTEXT_DEBUG_REGISTERS);
|
Registers registers(hThread, CONTEXT_DEBUG_REGISTERS);
|
||||||
|
|
||||||
//zero the address register
|
//zero the address register
|
||||||
switch (slot)
|
switch(slot)
|
||||||
{
|
{
|
||||||
case HardwareSlot::Dr0:
|
case HardwareSlot::Dr0:
|
||||||
registers.Dr0 = 0;
|
registers.Dr0 = 0;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
ptr Registers::Get(R reg)
|
ptr Registers::Get(R reg)
|
||||||
{
|
{
|
||||||
switch (reg)
|
switch(reg)
|
||||||
{
|
{
|
||||||
case R::DR0:
|
case R::DR0:
|
||||||
return ptr(mContext.Dr0);
|
return ptr(mContext.Dr0);
|
||||||
|
|
@ -258,7 +258,7 @@ namespace GleeBug
|
||||||
|
|
||||||
void Registers::Set(R reg, ptr value)
|
void Registers::Set(R reg, ptr value)
|
||||||
{
|
{
|
||||||
switch (reg)
|
switch(reg)
|
||||||
{
|
{
|
||||||
case R::DR0:
|
case R::DR0:
|
||||||
mContext.Dr0 = value;
|
mContext.Dr0 = value;
|
||||||
|
|
@ -556,7 +556,7 @@ namespace GleeBug
|
||||||
|
|
||||||
void Registers::SetFlag(F flag, bool set)
|
void Registers::SetFlag(F flag, bool set)
|
||||||
{
|
{
|
||||||
if (set)
|
if(set)
|
||||||
mContext.EFlags |= ptr(flag);
|
mContext.EFlags |= ptr(flag);
|
||||||
else
|
else
|
||||||
mContext.EFlags &= ~ptr(flag);
|
mContext.EFlags &= ~ptr(flag);
|
||||||
|
|
@ -564,7 +564,7 @@ namespace GleeBug
|
||||||
|
|
||||||
void* Registers::getPtr(R reg)
|
void* Registers::getPtr(R reg)
|
||||||
{
|
{
|
||||||
switch (reg)
|
switch(reg)
|
||||||
{
|
{
|
||||||
case R::DR0:
|
case R::DR0:
|
||||||
return REGPTR(mContext.Dr0);
|
return REGPTR(mContext.Dr0);
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ public:
|
||||||
Type Get() const
|
Type Get() const
|
||||||
{
|
{
|
||||||
auto ptr = (Type*)mRegisters->getPtr(RegisterIndex);
|
auto ptr = (Type*)mRegisters->getPtr(RegisterIndex);
|
||||||
if (ptr)
|
if(ptr)
|
||||||
return *ptr;
|
return *ptr;
|
||||||
return Type();
|
return Type();
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +149,7 @@ public:
|
||||||
void Set(Type value)
|
void Set(Type value)
|
||||||
{
|
{
|
||||||
auto ptr = (Type*)mRegisters->getPtr(RegisterIndex);
|
auto ptr = (Type*)mRegisters->getPtr(RegisterIndex);
|
||||||
if (ptr)
|
if(ptr)
|
||||||
*ptr = value;
|
*ptr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
memset(&mContext, 0, sizeof(CONTEXT));
|
memset(&mContext, 0, sizeof(CONTEXT));
|
||||||
mContext.ContextFlags = ContextFlags;
|
mContext.ContextFlags = ContextFlags;
|
||||||
if (!!GetThreadContext(hThread, &mContext))
|
if(!!GetThreadContext(hThread, &mContext))
|
||||||
{
|
{
|
||||||
this->hThread = hThread;
|
this->hThread = hThread;
|
||||||
memcpy(&mOldContext, &mContext, sizeof(CONTEXT));
|
memcpy(&mOldContext, &mContext, sizeof(CONTEXT));
|
||||||
|
|
@ -121,7 +121,7 @@ namespace GleeBug
|
||||||
|
|
||||||
Registers::~Registers()
|
Registers::~Registers()
|
||||||
{
|
{
|
||||||
if (hThread && memcmp(&mContext, &mOldContext, sizeof(CONTEXT)) != 0)
|
if(hThread && memcmp(&mContext, &mOldContext, sizeof(CONTEXT)) != 0)
|
||||||
SetThreadContext(hThread, &mContext);
|
SetThreadContext(hThread, &mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,11 @@ namespace GleeBug
|
||||||
void Thread::StepInto(const StepCallback & cbStep)
|
void Thread::StepInto(const StepCallback & cbStep)
|
||||||
{
|
{
|
||||||
StepInto();
|
StepInto();
|
||||||
|
|
||||||
auto target = cbStep.target<void()>();
|
auto target = cbStep.target<void()>();
|
||||||
for (const auto & cb : stepCallbacks)
|
for(const auto & cb : stepCallbacks)
|
||||||
{
|
{
|
||||||
if (target == cb.target<void()>())
|
if(target == cb.target<void()>())
|
||||||
{
|
{
|
||||||
puts("duplicate StepInto callback detected!");
|
puts("duplicate StepInto callback detected!");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,17 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Debugger::Init(const wchar_t* szFilePath,
|
bool Debugger::Init(const wchar_t* szFilePath,
|
||||||
const wchar_t* szCommandLine,
|
const wchar_t* szCommandLine,
|
||||||
const wchar_t* szCurrentDirectory,
|
const wchar_t* szCurrentDirectory,
|
||||||
bool newConsole,
|
bool newConsole,
|
||||||
bool startSuspended)
|
bool startSuspended)
|
||||||
{
|
{
|
||||||
memset(&mMainStartupInfo, 0, sizeof(mMainStartupInfo));
|
memset(&mMainStartupInfo, 0, sizeof(mMainStartupInfo));
|
||||||
memset(&mMainProcess, 0, sizeof(mMainProcess));
|
memset(&mMainProcess, 0, sizeof(mMainProcess));
|
||||||
const wchar_t* szFileNameCreateProcess;
|
const wchar_t* szFileNameCreateProcess;
|
||||||
wchar_t* szCommandLineCreateProcess;
|
wchar_t* szCommandLineCreateProcess;
|
||||||
wchar_t* szCreateWithCmdLine = nullptr;
|
wchar_t* szCreateWithCmdLine = nullptr;
|
||||||
if (szCommandLine == nullptr || !wcslen(szCommandLine))
|
if(szCommandLine == nullptr || !wcslen(szCommandLine))
|
||||||
{
|
{
|
||||||
szCommandLineCreateProcess = nullptr;
|
szCommandLineCreateProcess = nullptr;
|
||||||
szFileNameCreateProcess = szFilePath;
|
szFileNameCreateProcess = szFilePath;
|
||||||
|
|
@ -38,15 +38,15 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = !!CreateProcessW(szFileNameCreateProcess,
|
bool result = !!CreateProcessW(szFileNameCreateProcess,
|
||||||
szCommandLineCreateProcess,
|
szCommandLineCreateProcess,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
FALSE,
|
FALSE,
|
||||||
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | (newConsole ? CREATE_NEW_CONSOLE : 0) | (startSuspended ? CREATE_SUSPENDED : 0),
|
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | (newConsole ? CREATE_NEW_CONSOLE : 0) | (startSuspended ? CREATE_SUSPENDED : 0),
|
||||||
nullptr,
|
nullptr,
|
||||||
szCurrentDirectory,
|
szCurrentDirectory,
|
||||||
&mMainStartupInfo,
|
&mMainStartupInfo,
|
||||||
&mMainProcess);
|
&mMainProcess);
|
||||||
|
|
||||||
delete[] szCreateWithCmdLine;
|
delete[] szCreateWithCmdLine;
|
||||||
mAttachedToProcess = false;
|
mAttachedToProcess = false;
|
||||||
|
|
@ -87,7 +87,7 @@ namespace GleeBug
|
||||||
|
|
||||||
bool Debugger::UnsafeDetachAndBreak()
|
bool Debugger::UnsafeDetachAndBreak()
|
||||||
{
|
{
|
||||||
if (!mProcess || !mThread) //fail when there is no process or thread currently specified
|
if(!mProcess || !mThread) //fail when there is no process or thread currently specified
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//trigger an EXCEPTION_SINGLE_STEP in the debuggee
|
//trigger an EXCEPTION_SINGLE_STEP in the debuggee
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,10 @@ namespace GleeBug
|
||||||
\return true if the debuggee was started correctly, false otherwise.
|
\return true if the debuggee was started correctly, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool Init(const wchar_t* szFilePath,
|
bool Init(const wchar_t* szFilePath,
|
||||||
const wchar_t* szCommandLine,
|
const wchar_t* szCommandLine,
|
||||||
const wchar_t* szCurrentDirectory,
|
const wchar_t* szCurrentDirectory,
|
||||||
bool newConsole = true,
|
bool newConsole = true,
|
||||||
bool startSuspended = false);
|
bool startSuspended = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Attach to a debuggee.
|
\brief Attach to a debuggee.
|
||||||
|
|
@ -287,7 +287,7 @@ namespace GleeBug
|
||||||
bool mBreakDebugger = false;
|
bool mBreakDebugger = false;
|
||||||
DEBUG_EVENT mDebugEvent;
|
DEBUG_EVENT mDebugEvent;
|
||||||
ProcessMap mProcesses;
|
ProcessMap mProcesses;
|
||||||
bool mIsRunning = false; //TODO: needs a dedicated critical section to prevent ContinueDebugEvent and change of registers to race
|
bool mIsRunning = false; //TODO: needs a dedicated critical section to prevent ContinueDebugEvent and change of registers to race
|
||||||
bool mIsDebugging = false;
|
bool mIsDebugging = false;
|
||||||
bool mDetach = false;
|
bool mDetach = false;
|
||||||
bool mDetachAndBreak = false;
|
bool mDetachAndBreak = false;
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
BufferFile::BufferFile(void* data, uint32 size)
|
BufferFile::BufferFile(void* data, uint32 size)
|
||||||
: File(nullptr),
|
: File(nullptr),
|
||||||
mData(data),
|
mData(data),
|
||||||
mSize(size)
|
mSize(size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,34 +40,34 @@ namespace GleeBug
|
||||||
|
|
||||||
bool BufferFile::Read(uint32 offset, void* data, uint32 size, uint32* bytesRead) const
|
bool BufferFile::Read(uint32 offset, void* data, uint32 size, uint32* bytesRead) const
|
||||||
{
|
{
|
||||||
if (offset >= mSize)
|
if(offset >= mSize)
|
||||||
return false;
|
return false;
|
||||||
auto readSize = size;
|
auto readSize = size;
|
||||||
auto result = true;
|
auto result = true;
|
||||||
if (offset + size > mSize)
|
if(offset + size > mSize)
|
||||||
{
|
{
|
||||||
readSize = mSize - offset;
|
readSize = mSize - offset;
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
memcpy(data, (uint8*)mData + offset, readSize);
|
memcpy(data, (uint8*)mData + offset, readSize);
|
||||||
if (bytesRead)
|
if(bytesRead)
|
||||||
*bytesRead = readSize;
|
*bytesRead = readSize;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferFile::Write(uint32 offset, const void* data, uint32 size, uint32* bytesWritten)
|
bool BufferFile::Write(uint32 offset, const void* data, uint32 size, uint32* bytesWritten)
|
||||||
{
|
{
|
||||||
if (offset >= mSize)
|
if(offset >= mSize)
|
||||||
return false;
|
return false;
|
||||||
auto writeSize = size;
|
auto writeSize = size;
|
||||||
auto result = true;
|
auto result = true;
|
||||||
if (offset + size > mSize)
|
if(offset + size > mSize)
|
||||||
{
|
{
|
||||||
writeSize = mSize - offset;
|
writeSize = mSize - offset;
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
memcpy((uint8*)mData + offset, data, writeSize);
|
memcpy((uint8*)mData + offset, data, writeSize);
|
||||||
if (bytesWritten)
|
if(bytesWritten)
|
||||||
*bytesWritten = writeSize;
|
*bytesWritten = writeSize;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
File::File(const wchar_t* szFileName, File::Mode mode)
|
File::File(const wchar_t* szFileName, File::Mode mode)
|
||||||
: mFileName(szFileName ? szFileName : L""),
|
: mFileName(szFileName ? szFileName : L""),
|
||||||
mMode(mode),
|
mMode(mode),
|
||||||
mhFile(INVALID_HANDLE_VALUE)
|
mhFile(INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace GleeBug
|
||||||
|
|
||||||
void File::Close()
|
void File::Close()
|
||||||
{
|
{
|
||||||
if (IsOpen())
|
if(IsOpen())
|
||||||
{
|
{
|
||||||
CloseHandle(mhFile);
|
CloseHandle(mhFile);
|
||||||
mhFile = INVALID_HANDLE_VALUE;
|
mhFile = INVALID_HANDLE_VALUE;
|
||||||
|
|
@ -45,30 +45,30 @@ namespace GleeBug
|
||||||
|
|
||||||
bool File::Read(uint32 offset, void* data, uint32 size, uint32* bytesRead) const
|
bool File::Read(uint32 offset, void* data, uint32 size, uint32* bytesRead) const
|
||||||
{
|
{
|
||||||
if (!IsOpen() || SetFilePointer(mhFile, offset, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
if(!IsOpen() || SetFilePointer(mhFile, offset, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
||||||
{
|
{
|
||||||
if (bytesRead)
|
if(bytesRead)
|
||||||
*bytesRead = 0;
|
*bytesRead = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DWORD NumberOfBytesRead = 0;
|
DWORD NumberOfBytesRead = 0;
|
||||||
auto result = !!ReadFile(mhFile, data, size, &NumberOfBytesRead, nullptr);
|
auto result = !!ReadFile(mhFile, data, size, &NumberOfBytesRead, nullptr);
|
||||||
if (bytesRead)
|
if(bytesRead)
|
||||||
*bytesRead = uint32(NumberOfBytesRead);
|
*bytesRead = uint32(NumberOfBytesRead);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::Write(uint32 offset, const void* data, uint32 size, uint32* bytesWritten)
|
bool File::Write(uint32 offset, const void* data, uint32 size, uint32* bytesWritten)
|
||||||
{
|
{
|
||||||
if (!IsOpen() || SetFilePointer(mhFile, offset, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
if(!IsOpen() || SetFilePointer(mhFile, offset, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
||||||
{
|
{
|
||||||
if (bytesWritten)
|
if(bytesWritten)
|
||||||
*bytesWritten = 0;
|
*bytesWritten = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DWORD NumberOfBytesWritten = 0;
|
DWORD NumberOfBytesWritten = 0;
|
||||||
auto result = !!WriteFile(mhFile, data, size, &NumberOfBytesWritten, nullptr);
|
auto result = !!WriteFile(mhFile, data, size, &NumberOfBytesWritten, nullptr);
|
||||||
if (bytesWritten)
|
if(bytesWritten)
|
||||||
*bytesWritten = uint32(NumberOfBytesWritten);
|
*bytesWritten = uint32(NumberOfBytesWritten);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,7 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//get the access and sharemode flags
|
//get the access and sharemode flags
|
||||||
DWORD access, sharemode;
|
DWORD access, sharemode;
|
||||||
switch (mMode)
|
switch(mMode)
|
||||||
{
|
{
|
||||||
case ReadOnly:
|
case ReadOnly:
|
||||||
access = GENERIC_READ;
|
access = GENERIC_READ;
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(patterntext.length());
|
result.reserve(patterntext.length());
|
||||||
for (auto ch : patterntext)
|
for(auto ch : patterntext)
|
||||||
{
|
{
|
||||||
if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f' || ch == '?')
|
if(ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f' || ch == '?')
|
||||||
result += ch;
|
result += ch;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -19,10 +19,10 @@ namespace GleeBug
|
||||||
std::vector<Byte> pattern;
|
std::vector<Byte> pattern;
|
||||||
auto formattext = FormatPattern(patterntext);
|
auto formattext = FormatPattern(patterntext);
|
||||||
auto len = formattext.length();
|
auto len = formattext.length();
|
||||||
if (!len)
|
if(!len)
|
||||||
return pattern;
|
return pattern;
|
||||||
|
|
||||||
if (len % 2) //not a multiple of 2
|
if(len % 2) //not a multiple of 2
|
||||||
{
|
{
|
||||||
formattext += '?';
|
formattext += '?';
|
||||||
len++;
|
len++;
|
||||||
|
|
@ -32,20 +32,20 @@ namespace GleeBug
|
||||||
|
|
||||||
auto hexChToInt = [](char ch)
|
auto hexChToInt = [](char ch)
|
||||||
{
|
{
|
||||||
if (ch >= '0' && ch <= '9')
|
if(ch >= '0' && ch <= '9')
|
||||||
return ch - '0';
|
return ch - '0';
|
||||||
if (ch >= 'A' && ch <= 'F')
|
if(ch >= 'A' && ch <= 'F')
|
||||||
return ch - 'A' + 10;
|
return ch - 'A' + 10;
|
||||||
if (ch >= 'a' && ch <= 'f')
|
if(ch >= 'a' && ch <= 'f')
|
||||||
return ch - 'a' + 10;
|
return ch - 'a' + 10;
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
Byte newByte;
|
Byte newByte;
|
||||||
auto j = 0;
|
auto j = 0;
|
||||||
for (auto ch : formattext)
|
for(auto ch : formattext)
|
||||||
{
|
{
|
||||||
if (ch == '?') //wildcard
|
if(ch == '?') //wildcard
|
||||||
{
|
{
|
||||||
newByte.nibble[j].wildcard = true; //match anything
|
newByte.nibble[j].wildcard = true; //match anything
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
j++;
|
j++;
|
||||||
if (j == 2) //two nibbles = one byte
|
if(j == 2) //two nibbles = one byte
|
||||||
{
|
{
|
||||||
j = 0;
|
j = 0;
|
||||||
pattern.push_back(newByte);
|
pattern.push_back(newByte);
|
||||||
|
|
@ -72,32 +72,32 @@ namespace GleeBug
|
||||||
auto matched = 0;
|
auto matched = 0;
|
||||||
|
|
||||||
unsigned char n1 = (byte >> 4) & 0xF;
|
unsigned char n1 = (byte >> 4) & 0xF;
|
||||||
if (pbyte.nibble[0].wildcard)
|
if(pbyte.nibble[0].wildcard)
|
||||||
matched++;
|
matched++;
|
||||||
else if (pbyte.nibble[0].data == n1)
|
else if(pbyte.nibble[0].data == n1)
|
||||||
matched++;
|
matched++;
|
||||||
|
|
||||||
unsigned char n2 = byte & 0xF;
|
unsigned char n2 = byte & 0xF;
|
||||||
if (pbyte.nibble[1].wildcard)
|
if(pbyte.nibble[1].wildcard)
|
||||||
matched++;
|
matched++;
|
||||||
else if (pbyte.nibble[1].data == n2)
|
else if(pbyte.nibble[1].data == n2)
|
||||||
matched++;
|
matched++;
|
||||||
|
|
||||||
return matched == 2;
|
return matched == 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto searchpatternsize = pattern.size();
|
auto searchpatternsize = pattern.size();
|
||||||
if (!searchpatternsize)
|
if(!searchpatternsize)
|
||||||
return -1;
|
return -1;
|
||||||
for (size_t i = 0, pos = 0; i < datasize; i++) //search for the pattern
|
for(size_t i = 0, pos = 0; i < datasize; i++) //search for the pattern
|
||||||
{
|
{
|
||||||
if (MatchByte(data[i], pattern.at(pos))) //check if our pattern matches the current byte
|
if(MatchByte(data[i], pattern.at(pos))) //check if our pattern matches the current byte
|
||||||
{
|
{
|
||||||
pos++;
|
pos++;
|
||||||
if (pos == searchpatternsize) //everything matched
|
if(pos == searchpatternsize) //everything matched
|
||||||
return i - searchpatternsize + 1;
|
return i - searchpatternsize + 1;
|
||||||
}
|
}
|
||||||
else if (pos > 0) //fix by Computer_Angel
|
else if(pos > 0) //fix by Computer_Angel
|
||||||
{
|
{
|
||||||
i -= pos;
|
i -= pos;
|
||||||
pos = 0; //reset current pattern position
|
pos = 0; //reset current pattern position
|
||||||
|
|
@ -108,19 +108,19 @@ namespace GleeBug
|
||||||
|
|
||||||
size_t Pattern::Find(const uint8* data, size_t datasize, const uint8* pattern, size_t patternsize)
|
size_t Pattern::Find(const uint8* data, size_t datasize, const uint8* pattern, size_t patternsize)
|
||||||
{
|
{
|
||||||
if (!patternsize)
|
if(!patternsize)
|
||||||
return -1;
|
return -1;
|
||||||
if (patternsize > datasize)
|
if(patternsize > datasize)
|
||||||
patternsize = datasize;
|
patternsize = datasize;
|
||||||
for (size_t i = 0, pos = 0; i < datasize; i++)
|
for(size_t i = 0, pos = 0; i < datasize; i++)
|
||||||
{
|
{
|
||||||
if (data[i] == pattern[pos])
|
if(data[i] == pattern[pos])
|
||||||
{
|
{
|
||||||
pos++;
|
pos++;
|
||||||
if (pos == patternsize)
|
if(pos == patternsize)
|
||||||
return i - patternsize + 1;
|
return i - patternsize + 1;
|
||||||
}
|
}
|
||||||
else if (pos > 0)
|
else if(pos > 0)
|
||||||
{
|
{
|
||||||
i -= pos;
|
i -= pos;
|
||||||
pos = 0; //reset current pattern position
|
pos = 0; //reset current pattern position
|
||||||
|
|
@ -131,32 +131,32 @@ namespace GleeBug
|
||||||
|
|
||||||
void Pattern::Write(uint8* data, size_t datasize, const WildcardPattern & writepattern)
|
void Pattern::Write(uint8* data, size_t datasize, const WildcardPattern & writepattern)
|
||||||
{
|
{
|
||||||
if (!writepattern.size())
|
if(!writepattern.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto writepatternsize = writepattern.size();
|
auto writepatternsize = writepattern.size();
|
||||||
if (writepatternsize > datasize)
|
if(writepatternsize > datasize)
|
||||||
writepatternsize = datasize;
|
writepatternsize = datasize;
|
||||||
|
|
||||||
auto WriteByte = [](uint8* byte, const Byte & pbyte)
|
auto WriteByte = [](uint8 * byte, const Byte & pbyte)
|
||||||
{
|
{
|
||||||
unsigned char n1 = (*byte >> 4) & 0xF;
|
unsigned char n1 = (*byte >> 4) & 0xF;
|
||||||
unsigned char n2 = *byte & 0xF;
|
unsigned char n2 = *byte & 0xF;
|
||||||
if (!pbyte.nibble[0].wildcard)
|
if(!pbyte.nibble[0].wildcard)
|
||||||
n1 = pbyte.nibble[0].data;
|
n1 = pbyte.nibble[0].data;
|
||||||
if (!pbyte.nibble[1].wildcard)
|
if(!pbyte.nibble[1].wildcard)
|
||||||
n2 = pbyte.nibble[1].data;
|
n2 = pbyte.nibble[1].data;
|
||||||
*byte = ((n1 << 4) & 0xF0) | (n2 & 0xF);
|
*byte = ((n1 << 4) & 0xF0) | (n2 & 0xF);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < writepatternsize; i++)
|
for(size_t i = 0; i < writepatternsize; i++)
|
||||||
WriteByte(&data[i], writepattern.at(i));
|
WriteByte(&data[i], writepattern.at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pattern::SearchAndReplace(uint8* data, size_t datasize, const WildcardPattern & searchpattern, const WildcardPattern & replacepattern)
|
bool Pattern::SearchAndReplace(uint8* data, size_t datasize, const WildcardPattern & searchpattern, const WildcardPattern & replacepattern)
|
||||||
{
|
{
|
||||||
auto found = Find(data, datasize, searchpattern);
|
auto found = Find(data, datasize, searchpattern);
|
||||||
if (found == -1)
|
if(found == -1)
|
||||||
return false;
|
return false;
|
||||||
Write(data + found, datasize - found, replacepattern);
|
Write(data + found, datasize - found, replacepattern);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ namespace GleeBug
|
||||||
public:
|
public:
|
||||||
explicit Section(uint16 index, uint32 alignment, Region<IMAGE_SECTION_HEADER> & headers, Region<uint8> beforeData, Region<uint8> data)
|
explicit Section(uint16 index, uint32 alignment, Region<IMAGE_SECTION_HEADER> & headers, Region<uint8> beforeData, Region<uint8> data)
|
||||||
: mIndex(index),
|
: mIndex(index),
|
||||||
mAlignment(alignment),
|
mAlignment(alignment),
|
||||||
mHeaders(headers),
|
mHeaders(headers),
|
||||||
mBeforeData(beforeData),
|
mBeforeData(beforeData),
|
||||||
mData(data)
|
mData(data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,24 +49,24 @@ namespace GleeBug
|
||||||
|
|
||||||
//read the DOS header
|
//read the DOS header
|
||||||
mDosHeader = readRegion<IMAGE_DOS_HEADER>();
|
mDosHeader = readRegion<IMAGE_DOS_HEADER>();
|
||||||
if (!mDosHeader)
|
if(!mDosHeader)
|
||||||
return ErrorDosHeaderRead;
|
return ErrorDosHeaderRead;
|
||||||
|
|
||||||
//verify the DOS header
|
//verify the DOS header
|
||||||
if (mDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
if(mDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
return ErrorDosHeaderMagic;
|
return ErrorDosHeaderMagic;
|
||||||
|
|
||||||
//get the NT headers offset
|
//get the NT headers offset
|
||||||
auto newOffset = mDosHeader->e_lfanew;
|
auto newOffset = mDosHeader->e_lfanew;
|
||||||
|
|
||||||
//verify the new offset
|
//verify the new offset
|
||||||
if (newOffset < 0 || uint32(newOffset) >= mFile.GetSize())
|
if(newOffset < 0 || uint32(newOffset) >= mFile.GetSize())
|
||||||
return ErrorDosHeaderNtHeaderOffset;
|
return ErrorDosHeaderNtHeaderOffset;
|
||||||
|
|
||||||
//special case where DOS and PE header overlap (tinygui.exe)
|
//special case where DOS and PE header overlap (tinygui.exe)
|
||||||
if (uint32(newOffset) < mOffset)
|
if(uint32(newOffset) < mOffset)
|
||||||
{
|
{
|
||||||
if (!allowOverlap)
|
if(!allowOverlap)
|
||||||
return ErrorDosHeaderNtHeaderOffsetOverlap;
|
return ErrorDosHeaderNtHeaderOffsetOverlap;
|
||||||
|
|
||||||
mDosNtOverlap = true;
|
mDosNtOverlap = true;
|
||||||
|
|
@ -80,38 +80,38 @@ namespace GleeBug
|
||||||
mAfterDosData = readRegion<uint8>(afterDosCount);
|
mAfterDosData = readRegion<uint8>(afterDosCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mAfterDosData)
|
if(!mAfterDosData)
|
||||||
return ErrorAfterDosHeaderData;
|
return ErrorAfterDosHeaderData;
|
||||||
|
|
||||||
//read & verify the signature
|
//read & verify the signature
|
||||||
auto signature = readRegion<DWORD>();
|
auto signature = readRegion<DWORD>();
|
||||||
if (!signature)
|
if(!signature)
|
||||||
return ErrorNtSignatureRead;
|
return ErrorNtSignatureRead;
|
||||||
if (*signature() != IMAGE_NT_SIGNATURE)
|
if(*signature() != IMAGE_NT_SIGNATURE)
|
||||||
return ErrorNtSignatureMagic;
|
return ErrorNtSignatureMagic;
|
||||||
|
|
||||||
//read the file header
|
//read the file header
|
||||||
auto ifh = readRegion<IMAGE_FILE_HEADER>();
|
auto ifh = readRegion<IMAGE_FILE_HEADER>();
|
||||||
if (!ifh)
|
if(!ifh)
|
||||||
return ErrorNtFileHeaderRead;
|
return ErrorNtFileHeaderRead;
|
||||||
|
|
||||||
//read the optional header
|
//read the optional header
|
||||||
uint32 realSizeOfIoh;
|
uint32 realSizeOfIoh;
|
||||||
switch (ifh->Machine)
|
switch(ifh->Machine)
|
||||||
{
|
{
|
||||||
case IMAGE_FILE_MACHINE_I386:
|
case IMAGE_FILE_MACHINE_I386:
|
||||||
{
|
{
|
||||||
//read & verify the optional header
|
//read & verify the optional header
|
||||||
realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER32));
|
realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER32));
|
||||||
auto ioh = readRegion<IMAGE_OPTIONAL_HEADER32>();
|
auto ioh = readRegion<IMAGE_OPTIONAL_HEADER32>();
|
||||||
if (!ioh) //TODO: support truncated optional header (tinyXP.exe)
|
if(!ioh) //TODO: support truncated optional header (tinyXP.exe)
|
||||||
return ErrorNtOptionalHeaderRead;
|
return ErrorNtOptionalHeaderRead;
|
||||||
if (ioh->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
if(ioh->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||||
return ErrorNtOptionalHeaderMagic;
|
return ErrorNtOptionalHeaderMagic;
|
||||||
|
|
||||||
//construct & verify the NT headers region
|
//construct & verify the NT headers region
|
||||||
mNtHeaders32 = Region<IMAGE_NT_HEADERS32>(&mData, signature.Offset());
|
mNtHeaders32 = Region<IMAGE_NT_HEADERS32>(&mData, signature.Offset());
|
||||||
if (!mNtHeaders32)
|
if(!mNtHeaders32)
|
||||||
return ErrorNtHeadersRegionSize;
|
return ErrorNtHeadersRegionSize;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -123,14 +123,14 @@ namespace GleeBug
|
||||||
//read & verify the optional header
|
//read & verify the optional header
|
||||||
realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER64));
|
realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER64));
|
||||||
auto ioh = readRegion<IMAGE_OPTIONAL_HEADER64>();
|
auto ioh = readRegion<IMAGE_OPTIONAL_HEADER64>();
|
||||||
if (!ioh)
|
if(!ioh)
|
||||||
return ErrorNtOptionalHeaderRead;
|
return ErrorNtOptionalHeaderRead;
|
||||||
if (ioh->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
if(ioh->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
||||||
return ErrorNtOptionalHeaderMagic;
|
return ErrorNtOptionalHeaderMagic;
|
||||||
|
|
||||||
//construct & verify the NT headers region
|
//construct & verify the NT headers region
|
||||||
mNtHeaders64 = Region<IMAGE_NT_HEADERS64>(&mData, signature.Offset());
|
mNtHeaders64 = Region<IMAGE_NT_HEADERS64>(&mData, signature.Offset());
|
||||||
if (!mNtHeaders64)
|
if(!mNtHeaders64)
|
||||||
return ErrorNtHeadersRegionSize;
|
return ErrorNtHeadersRegionSize;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -139,11 +139,11 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
//try the best possible effort (corkami's d_resource.dll)
|
//try the best possible effort (corkami's d_resource.dll)
|
||||||
auto ioh = readRegion<uint8>(ifh->SizeOfOptionalHeader);
|
auto ioh = readRegion<uint8>(ifh->SizeOfOptionalHeader);
|
||||||
if (!ioh)
|
if(!ioh)
|
||||||
return ErrorNtFileHeaderUnsupportedMachineOptionalHeaderRead;
|
return ErrorNtFileHeaderUnsupportedMachineOptionalHeaderRead;
|
||||||
|
|
||||||
mNtHeaders32 = Region<IMAGE_NT_HEADERS32>(&mData, signature.Offset());
|
mNtHeaders32 = Region<IMAGE_NT_HEADERS32>(&mData, signature.Offset());
|
||||||
if (!mNtHeaders32)
|
if(!mNtHeaders32)
|
||||||
return ErrorNtFileHeaderUnsupportedMachineNtHeadersRegionSize;
|
return ErrorNtFileHeaderUnsupportedMachineNtHeadersRegionSize;
|
||||||
|
|
||||||
return ErrorNtFileHeaderUnsupportedMachine;
|
return ErrorNtFileHeaderUnsupportedMachine;
|
||||||
|
|
@ -154,23 +154,23 @@ namespace GleeBug
|
||||||
|
|
||||||
//check the SizeOfOptionalHeader field
|
//check the SizeOfOptionalHeader field
|
||||||
auto sizeOfIoh = ifh->SizeOfOptionalHeader;
|
auto sizeOfIoh = ifh->SizeOfOptionalHeader;
|
||||||
if (numberOfSections && sizeOfIoh < realSizeOfIoh) //TODO: this can be valid in certain circumstances (nullSOH-XP)
|
if(numberOfSections && sizeOfIoh < realSizeOfIoh) //TODO: this can be valid in certain circumstances (nullSOH-XP)
|
||||||
return ErrorNtFileHeaderSizeOfOptionalHeaderOverlap;
|
return ErrorNtFileHeaderSizeOfOptionalHeaderOverlap;
|
||||||
|
|
||||||
//read data after the optional header (TODO: check if this is even possible)
|
//read data after the optional header (TODO: check if this is even possible)
|
||||||
uint32 afterOptionalSize = realSizeOfIoh < sizeOfIoh ? sizeOfIoh - realSizeOfIoh : 0;
|
uint32 afterOptionalSize = realSizeOfIoh < sizeOfIoh ? sizeOfIoh - realSizeOfIoh : 0;
|
||||||
mAfterOptionalData = readRegion<uint8>(afterOptionalSize);
|
mAfterOptionalData = readRegion<uint8>(afterOptionalSize);
|
||||||
if (!mAfterOptionalData)
|
if(!mAfterOptionalData)
|
||||||
return ErrorAfterOptionalHeaderDataRead;
|
return ErrorAfterOptionalHeaderDataRead;
|
||||||
|
|
||||||
//read the section headers
|
//read the section headers
|
||||||
mSectionHeaders = readRegion<IMAGE_SECTION_HEADER>(numberOfSections);
|
mSectionHeaders = readRegion<IMAGE_SECTION_HEADER>(numberOfSections);
|
||||||
if (!mSectionHeaders)
|
if(!mSectionHeaders)
|
||||||
return ErrorSectionHeadersRead;
|
return ErrorSectionHeadersRead;
|
||||||
|
|
||||||
//parse the sections
|
//parse the sections
|
||||||
auto sectionsError = parseSections(numberOfSections);
|
auto sectionsError = parseSections(numberOfSections);
|
||||||
if (sectionsError != ErrorOk)
|
if(sectionsError != ErrorOk)
|
||||||
return sectionsError;
|
return sectionsError;
|
||||||
|
|
||||||
//TODO: parse data directories
|
//TODO: parse data directories
|
||||||
|
|
@ -179,13 +179,13 @@ namespace GleeBug
|
||||||
|
|
||||||
uint32 Pe::ConvertOffsetToRva(uint32 offset)
|
uint32 Pe::ConvertOffsetToRva(uint32 offset)
|
||||||
{
|
{
|
||||||
if (!mOffsetSectionMap.size()) //TODO: verify this (no sections means direct mapping)
|
if(!mOffsetSectionMap.size()) //TODO: verify this (no sections means direct mapping)
|
||||||
return offset;
|
return offset;
|
||||||
const auto found = mOffsetSectionMap.find(Range(offset, offset));
|
const auto found = mOffsetSectionMap.find(Range(offset, offset));
|
||||||
if (found == mOffsetSectionMap.end())
|
if(found == mOffsetSectionMap.end())
|
||||||
return INVALID_VALUE;
|
return INVALID_VALUE;
|
||||||
auto index = found->second;
|
auto index = found->second;
|
||||||
if (index == HeaderSection)
|
if(index == HeaderSection)
|
||||||
return offset;
|
return offset;
|
||||||
const auto & section = mSections[index];
|
const auto & section = mSections[index];
|
||||||
offset -= uint32(found->first.first); //adjust the offset to be relative to the offset range in the map
|
offset -= uint32(found->first.first); //adjust the offset to be relative to the offset range in the map
|
||||||
|
|
@ -194,13 +194,13 @@ namespace GleeBug
|
||||||
|
|
||||||
uint32 Pe::ConvertRvaToOffset(uint32 rva)
|
uint32 Pe::ConvertRvaToOffset(uint32 rva)
|
||||||
{
|
{
|
||||||
if (!mRvaSectionMap.size()) //TODO: verify this (no sections means direct mapping)
|
if(!mRvaSectionMap.size()) //TODO: verify this (no sections means direct mapping)
|
||||||
return rva;
|
return rva;
|
||||||
const auto found = mRvaSectionMap.find(Range(rva, rva));
|
const auto found = mRvaSectionMap.find(Range(rva, rva));
|
||||||
if (found == mRvaSectionMap.end())
|
if(found == mRvaSectionMap.end())
|
||||||
return INVALID_VALUE;
|
return INVALID_VALUE;
|
||||||
auto index = found->second;
|
auto index = found->second;
|
||||||
if (index == HeaderSection)
|
if(index == HeaderSection)
|
||||||
return rva;
|
return rva;
|
||||||
const auto & section = mSections[index];
|
const auto & section = mSections[index];
|
||||||
rva -= uint32(found->first.first); //adjust the rva to be relative to the rva range in the map
|
rva -= uint32(found->first.first); //adjust the rva to be relative to the rva range in the map
|
||||||
|
|
@ -209,7 +209,7 @@ namespace GleeBug
|
||||||
|
|
||||||
Pe::Error Pe::parseSections(uint16 count, uint32 alignment)
|
Pe::Error Pe::parseSections(uint16 count, uint32 alignment)
|
||||||
{
|
{
|
||||||
if (!count)
|
if(!count)
|
||||||
return ErrorOk;
|
return ErrorOk;
|
||||||
|
|
||||||
auto sectionHeaders = GetSectionHeaders();
|
auto sectionHeaders = GetSectionHeaders();
|
||||||
|
|
@ -225,7 +225,7 @@ namespace GleeBug
|
||||||
//sort sections on raw address to prevent read errors and have a contiguous buffer
|
//sort sections on raw address to prevent read errors and have a contiguous buffer
|
||||||
std::vector<SectionInfo> sortedHeaders;
|
std::vector<SectionInfo> sortedHeaders;
|
||||||
sortedHeaders.reserve(count);
|
sortedHeaders.reserve(count);
|
||||||
for (uint16 i = 0; i < count; i++)
|
for(uint16 i = 0; i < count; i++)
|
||||||
sortedHeaders.push_back(SectionInfo{ i, sectionHeaders[i] });
|
sortedHeaders.push_back(SectionInfo{ i, sectionHeaders[i] });
|
||||||
|
|
||||||
std::sort(sortedHeaders.begin(), sortedHeaders.end(), [](const SectionInfo & a, const SectionInfo & b)
|
std::sort(sortedHeaders.begin(), sortedHeaders.end(), [](const SectionInfo & a, const SectionInfo & b)
|
||||||
|
|
@ -270,14 +270,14 @@ namespace GleeBug
|
||||||
|
|
||||||
//add the sections to the mSections vector
|
//add the sections to the mSections vector
|
||||||
mSections.reserve(count);
|
mSections.reserve(count);
|
||||||
for (uint16 i = 0; i < count; i++)
|
for(uint16 i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
const auto & section = sortedHeaders[i];
|
const auto & section = sortedHeaders[i];
|
||||||
mSections.push_back(Section(i, alignment, mSectionHeaders, section.beforeData, section.data));
|
mSections.push_back(Section(i, alignment, mSectionHeaders, section.beforeData, section.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
//create rva/offset -> section maps
|
//create rva/offset -> section maps
|
||||||
if (count) //insert pe header offset/rva (file start -> first section is the PE header)
|
if(count) //insert pe header offset/rva (file start -> first section is the PE header)
|
||||||
{
|
{
|
||||||
const auto & section = mSections[0];
|
const auto & section = mSections[0];
|
||||||
mOffsetSectionMap.insert({ Range(0, section.GetHeader().PointerToRawData - 1), HeaderSection });
|
mOffsetSectionMap.insert({ Range(0, section.GetHeader().PointerToRawData - 1), HeaderSection });
|
||||||
|
|
@ -287,7 +287,7 @@ namespace GleeBug
|
||||||
else //TODO: handle file without sections
|
else //TODO: handle file without sections
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
for (const auto & section : mSections)
|
for(const auto & section : mSections)
|
||||||
{
|
{
|
||||||
//offset -> section index
|
//offset -> section index
|
||||||
auto offset = section.GetHeader().PointerToRawData;
|
auto offset = section.GetHeader().PointerToRawData;
|
||||||
|
|
@ -308,11 +308,11 @@ namespace GleeBug
|
||||||
|
|
||||||
uint32 Pe::readData(uint32 size)
|
uint32 Pe::readData(uint32 size)
|
||||||
{
|
{
|
||||||
if (!size)
|
if(!size)
|
||||||
return mOffset;
|
return mOffset;
|
||||||
std::vector<uint8> temp(size);
|
std::vector<uint8> temp(size);
|
||||||
|
|
||||||
if (!mFile.Read(mOffset, temp.data(), size))
|
if(!mFile.Read(mOffset, temp.data(), size))
|
||||||
return INVALID_VALUE;
|
return INVALID_VALUE;
|
||||||
|
|
||||||
auto result = mOffset;
|
auto result = mOffset;
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ namespace GleeBug
|
||||||
*/
|
*/
|
||||||
explicit Region(std::vector<uint8>* data, uint32 offset, uint32 count = 1)
|
explicit Region(std::vector<uint8>* data, uint32 offset, uint32 count = 1)
|
||||||
: mData(data),
|
: mData(data),
|
||||||
mOffset(offset),
|
mOffset(offset),
|
||||||
mCount(count)
|
mCount(count)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace GleeBug
|
||||||
*/
|
*/
|
||||||
T* Data() const
|
T* Data() const
|
||||||
{
|
{
|
||||||
if (!Valid())
|
if(!Valid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return (T*)(mData->data() + mOffset);
|
return (T*)(mData->data() + mOffset);
|
||||||
}
|
}
|
||||||
|
|
@ -83,9 +83,9 @@ namespace GleeBug
|
||||||
bool Valid() const
|
bool Valid() const
|
||||||
{
|
{
|
||||||
return mOffset != INVALID_VALUE &&
|
return mOffset != INVALID_VALUE &&
|
||||||
mCount != INVALID_VALUE &&
|
mCount != INVALID_VALUE &&
|
||||||
mData && mData->data() &&
|
mData && mData->data() &&
|
||||||
mOffset + mCount * sizeof(T) <= mData->size();
|
mOffset + mCount * sizeof(T) <= mData->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -107,7 +107,7 @@ namespace GleeBug
|
||||||
/**
|
/**
|
||||||
\brief Returns Data().
|
\brief Returns Data().
|
||||||
*/
|
*/
|
||||||
T* operator ()() const
|
T* operator()() const
|
||||||
{
|
{
|
||||||
return Data();
|
return Data();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ protected:
|
||||||
void cbMemoryBreakpoint2(const BreakpointInfo & info)
|
void cbMemoryBreakpoint2(const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
printf("Reached memory breakpoint#2! GIP: 0x%p\n",
|
printf("Reached memory breakpoint#2! GIP: 0x%p\n",
|
||||||
(void*)Registers(mThread->hThread).Gip());
|
(void*)Registers(mThread->hThread).Gip());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbMemoryBreakpoint(const BreakpointInfo & info)
|
void cbMemoryBreakpoint(const BreakpointInfo & info)
|
||||||
|
|
@ -22,11 +22,11 @@ protected:
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
|
|
||||||
printf("Reached memory breakpoint! GIP: 0x%p\n",
|
printf("Reached memory breakpoint! GIP: 0x%p\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
|
|
||||||
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
|
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
|
||||||
printf("\n What are my bytes? I am so lost.. Dump: ");
|
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]);
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +35,7 @@ protected:
|
||||||
memcpy(dataToExec, tmp, 4);
|
memcpy(dataToExec, tmp, 4);
|
||||||
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
|
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
|
||||||
printf("\n What are my bytes? I am so lost.. Dump: ");
|
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]);
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +43,7 @@ protected:
|
||||||
memcpy(dataToExec, tmp, 4);
|
memcpy(dataToExec, tmp, 4);
|
||||||
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
|
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
|
||||||
printf("\n What are my bytes? I am so lost.. Dump: ");
|
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]);
|
||||||
}
|
}
|
||||||
|
|
@ -53,14 +53,14 @@ protected:
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("Reached entry breakpoint! GIP: 0x%p\n",
|
printf("Reached entry breakpoint! GIP: 0x%p\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
auto addr = registers.Rbx();
|
auto addr = registers.Rbx();
|
||||||
#else
|
#else
|
||||||
auto addr = registers.Esi();
|
auto addr = registers.Esi();
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
printf("Addr: 0x%p\n", (void*)addr);
|
printf("Addr: 0x%p\n", (void*)addr);
|
||||||
if (mProcess->SetMemoryBreakpoint(addr, 0x10000, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Execute, false))
|
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...");
|
||||||
|
|
@ -82,8 +82,8 @@ protected:
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
|
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
if (mProcess->DeleteHardwareBreakpoint(info.address))
|
if(mProcess->DeleteHardwareBreakpoint(info.address))
|
||||||
printf("Entry hardware breakpoint deleted!\n");
|
printf("Entry hardware breakpoint deleted!\n");
|
||||||
else
|
else
|
||||||
printf("Failed to delete entry hardware breakpoint...\n");
|
printf("Failed to delete entry hardware breakpoint...\n");
|
||||||
|
|
@ -91,7 +91,7 @@ protected:
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
|
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,15 +99,15 @@ protected:
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("Reached step after system breakpoint, GIP: 0x%p!\n",
|
printf("Reached step after system breakpoint, GIP: 0x%p!\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const Process & process) override
|
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const Process & process) override
|
||||||
{
|
{
|
||||||
ptr entry = ptr(createProcess.lpStartAddress);
|
ptr entry = ptr(createProcess.lpStartAddress);
|
||||||
printf("Process %d created with entry 0x%p\n",
|
printf("Process %d created with entry 0x%p\n",
|
||||||
mDebugEvent.dwProcessId,
|
mDebugEvent.dwProcessId,
|
||||||
(void*)entry);
|
(void*)entry);
|
||||||
/*HardwareSlot slot;
|
/*HardwareSlot slot;
|
||||||
if (mProcess->GetFreeHardwareBreakpointSlot(slot))
|
if (mProcess->GetFreeHardwareBreakpointSlot(slot))
|
||||||
{
|
{
|
||||||
|
|
@ -133,12 +133,12 @@ protected:
|
||||||
ptr start = entry - 2;
|
ptr start = entry - 2;
|
||||||
printf("unsafe: ");
|
printf("unsafe: ");
|
||||||
mProcess->MemReadUnsafe(start, test, sizeof(test));
|
mProcess->MemReadUnsafe(start, test, sizeof(test));
|
||||||
for (int i = 0; i < sizeof(test); i++)
|
for(int i = 0; i < sizeof(test); i++)
|
||||||
printf("%02X ", test[i]);
|
printf("%02X ", test[i]);
|
||||||
puts("");
|
puts("");
|
||||||
mProcess->MemReadSafe(start, test, sizeof(test));
|
mProcess->MemReadSafe(start, test, sizeof(test));
|
||||||
printf(" safe: ");
|
printf(" safe: ");
|
||||||
for (int i = 0; i < sizeof(test); i++)
|
for(int i = 0; i < sizeof(test); i++)
|
||||||
printf("%02X ", test[i]);
|
printf("%02X ", test[i]);
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
|
|
@ -146,96 +146,96 @@ protected:
|
||||||
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const Process & process) override
|
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const Process & process) override
|
||||||
{
|
{
|
||||||
printf("Process %u terminated with exit code 0x%08X\n",
|
printf("Process %u terminated with exit code 0x%08X\n",
|
||||||
mDebugEvent.dwProcessId,
|
mDebugEvent.dwProcessId,
|
||||||
exitProcess.dwExitCode);
|
exitProcess.dwExitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const Thread & thread) override
|
void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const Thread & thread) override
|
||||||
{
|
{
|
||||||
printf("Thread %u created with entry 0x%p\n",
|
printf("Thread %u created with entry 0x%p\n",
|
||||||
mDebugEvent.dwThreadId,
|
mDebugEvent.dwThreadId,
|
||||||
createThread.lpStartAddress);
|
createThread.lpStartAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const Thread & thread) override
|
void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const Thread & thread) override
|
||||||
{
|
{
|
||||||
printf("Thread %u terminated with exit code 0x%08X\n",
|
printf("Thread %u terminated with exit code 0x%08X\n",
|
||||||
mDebugEvent.dwThreadId,
|
mDebugEvent.dwThreadId,
|
||||||
exitThread.dwExitCode);
|
exitThread.dwExitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll) override
|
void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll) override
|
||||||
{
|
{
|
||||||
printf("DLL loaded at 0x%p\n",
|
printf("DLL loaded at 0x%p\n",
|
||||||
loadDll.lpBaseOfDll);
|
loadDll.lpBaseOfDll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll) override
|
void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll) override
|
||||||
{
|
{
|
||||||
printf("DLL 0x%p unloaded\n",
|
printf("DLL 0x%p unloaded\n",
|
||||||
unloadDll.lpBaseOfDll);
|
unloadDll.lpBaseOfDll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) override
|
void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) override
|
||||||
{
|
{
|
||||||
const char* exceptionType = exceptionInfo.dwFirstChance ? "First Chance" : "Second Chance";
|
const char* exceptionType = exceptionInfo.dwFirstChance ? "First Chance" : "Second Chance";
|
||||||
printf("%s exception with code 0x%08X at 0x%p\n",
|
printf("%s exception with code 0x%08X at 0x%p\n",
|
||||||
exceptionType,
|
exceptionType,
|
||||||
exceptionInfo.ExceptionRecord.ExceptionCode,
|
exceptionInfo.ExceptionRecord.ExceptionCode,
|
||||||
exceptionInfo.ExceptionRecord.ExceptionAddress);
|
exceptionInfo.ExceptionRecord.ExceptionAddress);
|
||||||
for (DWORD i = 0; i < exceptionInfo.ExceptionRecord.NumberParameters; i++)
|
for(DWORD i = 0; i < exceptionInfo.ExceptionRecord.NumberParameters; i++)
|
||||||
printf(" ExceptionInformation[%d] = 0x%p\n", i, (void*)exceptionInfo.ExceptionRecord.ExceptionInformation[i]);
|
printf(" ExceptionInformation[%d] = 0x%p\n", i, (void*)exceptionInfo.ExceptionRecord.ExceptionInformation[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
|
void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
|
||||||
{
|
{
|
||||||
printf("Debug string at 0x%p with length %d\n",
|
printf("Debug string at 0x%p with length %d\n",
|
||||||
debugString.lpDebugStringData,
|
debugString.lpDebugStringData,
|
||||||
debugString.nDebugStringLength);
|
debugString.nDebugStringLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbRipEvent(const RIP_INFO & rip) override
|
void cbRipEvent(const RIP_INFO & rip) override
|
||||||
{
|
{
|
||||||
printf("RIP event type 0x%X, error 0x%X",
|
printf("RIP event type 0x%X, error 0x%X",
|
||||||
rip.dwType,
|
rip.dwType,
|
||||||
rip.dwError);
|
rip.dwError);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbAttachBreakpoint() override
|
void cbAttachBreakpoint() override
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("Attach breakpoint reached, GIP: 0x%p\n",
|
printf("Attach breakpoint reached, GIP: 0x%p\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbSystemBreakpoint() override
|
void cbSystemBreakpoint() override
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("System breakpoint reached, GIP: 0x%p\n",
|
printf("System breakpoint reached, GIP: 0x%p\n",
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
mThread->StepInto(this, &MyDebugger::cbStepSystem);
|
mThread->StepInto(this, &MyDebugger::cbStepSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbInternalError(const std::string & error) override
|
void cbInternalError(const std::string & error) override
|
||||||
{
|
{
|
||||||
printf("Internal Error: %s\n",
|
printf("Internal Error: %s\n",
|
||||||
error.c_str());
|
error.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbBreakpoint(const BreakpointInfo & info) override
|
void cbBreakpoint(const BreakpointInfo & info) override
|
||||||
{
|
{
|
||||||
printf("Breakpoint on 0x%p!\n",
|
printf("Breakpoint on 0x%p!\n",
|
||||||
(void*)info.address);
|
(void*)info.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) override
|
void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) override
|
||||||
{
|
{
|
||||||
Registers registers(mThread->hThread);
|
Registers registers(mThread->hThread);
|
||||||
printf("Unhandled exception (%s) 0x%08X on 0x%p, GIP: 0x%p\n",
|
printf("Unhandled exception (%s) 0x%08X on 0x%p, GIP: 0x%p\n",
|
||||||
firstChance ? "first chance" : "second chance",
|
firstChance ? "first chance" : "second chance",
|
||||||
exceptionRecord.ExceptionCode,
|
exceptionRecord.ExceptionCode,
|
||||||
exceptionRecord.ExceptionAddress,
|
exceptionRecord.ExceptionAddress,
|
||||||
(void*)registers.Gip());
|
(void*)registers.Gip());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ static void testDebugger()
|
||||||
wchar_t szCommandLine[256] = L"";
|
wchar_t szCommandLine[256] = L"";
|
||||||
wchar_t szCurrentDir[256] = L"c:\\";
|
wchar_t szCurrentDir[256] = L"c:\\";
|
||||||
MyDebugger dbg;
|
MyDebugger dbg;
|
||||||
if (dbg.Init(szFilePath, szCommandLine, szCurrentDir))
|
if(dbg.Init(szFilePath, szCommandLine, szCurrentDir))
|
||||||
{
|
{
|
||||||
puts("Debugger::Init success!");
|
puts("Debugger::Init success!");
|
||||||
dbg.Start();
|
dbg.Start();
|
||||||
|
|
@ -30,12 +30,12 @@ template<typename T>
|
||||||
static void printRegion(const char* str, Region<T> region, bool newline = true)
|
static void printRegion(const char* str, Region<T> region, bool newline = true)
|
||||||
{
|
{
|
||||||
printf("\n%s (offset: 0x%X, size: 0x%X, v: %s, e: %s)",
|
printf("\n%s (offset: 0x%X, size: 0x%X, v: %s, e: %s)",
|
||||||
str,
|
str,
|
||||||
region.Offset(),
|
region.Offset(),
|
||||||
region.Size(),
|
region.Size(),
|
||||||
region.Valid() ? "true" : "false",
|
region.Valid() ? "true" : "false",
|
||||||
region.Empty() ? "true" : "false");
|
region.Empty() ? "true" : "false");
|
||||||
if (newline)
|
if(newline)
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,19 +65,19 @@ static bool testPeFile(const wchar_t* szFileName, bool dumpData = true)
|
||||||
using namespace GleeBug;
|
using namespace GleeBug;
|
||||||
auto result = false;
|
auto result = false;
|
||||||
File diskFile(szFileName, File::ReadOnly);
|
File diskFile(szFileName, File::ReadOnly);
|
||||||
if (diskFile.Open())
|
if(diskFile.Open())
|
||||||
{
|
{
|
||||||
auto diskSize = diskFile.GetSize();
|
auto diskSize = diskFile.GetSize();
|
||||||
std::vector<uint8> diskData(diskSize);
|
std::vector<uint8> diskData(diskSize);
|
||||||
if (diskFile.Read(0, diskData.data(), diskSize))
|
if(diskFile.Read(0, diskData.data(), diskSize))
|
||||||
{
|
{
|
||||||
BufferFile file(diskData.data(), diskSize);
|
BufferFile file(diskData.data(), diskSize);
|
||||||
Pe pe(file);
|
Pe pe(file);
|
||||||
auto parseError = pe.Parse(true);
|
auto parseError = pe.Parse(true);
|
||||||
if (parseError == Pe::ErrorOk)
|
if(parseError == Pe::ErrorOk)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
if (!dumpData)
|
if(!dumpData)
|
||||||
return result;
|
return result;
|
||||||
auto idh = pe.GetDosHeader();
|
auto idh = pe.GetDosHeader();
|
||||||
printRegion("DOS Header:", idh);
|
printRegion("DOS Header:", idh);
|
||||||
|
|
@ -87,7 +87,7 @@ static bool testPeFile(const wchar_t* szFileName, bool dumpData = true)
|
||||||
auto afterDosData = pe.GetAfterDosData();
|
auto afterDosData = pe.GetAfterDosData();
|
||||||
printRegion("After DOS Data", afterDosData);
|
printRegion("After DOS Data", afterDosData);
|
||||||
|
|
||||||
if (pe.IsPe64())
|
if(pe.IsPe64())
|
||||||
printNtHeaders(pe.GetNtHeaders64());
|
printNtHeaders(pe.GetNtHeaders64());
|
||||||
else
|
else
|
||||||
printNtHeaders(pe.GetNtHeaders32());
|
printNtHeaders(pe.GetNtHeaders32());
|
||||||
|
|
@ -100,9 +100,9 @@ static bool testPeFile(const wchar_t* szFileName, bool dumpData = true)
|
||||||
auto afterSectionHeadersData = pe.GetAfterSectionHeadersData();
|
auto afterSectionHeadersData = pe.GetAfterSectionHeadersData();
|
||||||
printRegion("After Section Headers Data", afterSectionHeadersData);
|
printRegion("After Section Headers Data", afterSectionHeadersData);
|
||||||
auto sections = pe.GetSections();
|
auto sections = pe.GetSections();
|
||||||
for (const auto & section : sections)
|
for(const auto & section : sections)
|
||||||
{
|
{
|
||||||
if (section.GetIndex())
|
if(section.GetIndex())
|
||||||
puts("");
|
puts("");
|
||||||
printf(" Section %d:\n", section.GetIndex());
|
printf(" Section %d:\n", section.GetIndex());
|
||||||
auto cur = section.GetHeader();
|
auto cur = section.GetHeader();
|
||||||
|
|
@ -118,13 +118,13 @@ static bool testPeFile(const wchar_t* szFileName, bool dumpData = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nOffset -> Section:\n");
|
printf("\nOffset -> Section:\n");
|
||||||
for (auto range : pe.GetOffsetSectionMap())
|
for(auto range : pe.GetOffsetSectionMap())
|
||||||
{
|
{
|
||||||
printf(" %08llX:%08llX -> %d\n", range.first.first, range.first.second, range.second);
|
printf(" %08llX:%08llX -> %d\n", range.first.first, range.first.second, range.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nRva -> Section:\n");
|
printf("\nRva -> Section:\n");
|
||||||
for (auto range : pe.GetRvaSectionMap())
|
for(auto range : pe.GetRvaSectionMap())
|
||||||
{
|
{
|
||||||
printf(" %08llX:%08llX -> %d\n", range.first.first, range.first.second, range.second);
|
printf(" %08llX:%08llX -> %d\n", range.first.first, range.first.second, range.second);
|
||||||
}
|
}
|
||||||
|
|
@ -145,11 +145,11 @@ static void testCorkami()
|
||||||
#include "PeTests.h"
|
#include "PeTests.h"
|
||||||
wchar_t szBasePath[MAX_PATH] = L"c:\\!exclude\\pe\\bin\\";
|
wchar_t szBasePath[MAX_PATH] = L"c:\\!exclude\\pe\\bin\\";
|
||||||
int okCount = 0;
|
int okCount = 0;
|
||||||
for (auto i = 0; i < _countof(peTestFiles); i++)
|
for(auto i = 0; i < _countof(peTestFiles); i++)
|
||||||
{
|
{
|
||||||
std::wstring fileName(szBasePath);
|
std::wstring fileName(szBasePath);
|
||||||
fileName += peTestFiles[i];
|
fileName += peTestFiles[i];
|
||||||
if (testPeFile(fileName.c_str(), false))
|
if(testPeFile(fileName.c_str(), false))
|
||||||
okCount++;
|
okCount++;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,8 @@ public:
|
||||||
dwMainThreadId = te.th32ThreadID;
|
dwMainThreadId = te.th32ThreadID;
|
||||||
}
|
}
|
||||||
te.dwSize = sizeof(te);
|
te.dwSize = sizeof(te);
|
||||||
} while(Thread32Next(h, &te));
|
}
|
||||||
|
while(Thread32Next(h, &te));
|
||||||
}
|
}
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +152,7 @@ public:
|
||||||
mProcessInfo.dwThreadId = dwMainThreadId;
|
mProcessInfo.dwThreadId = dwMainThreadId;
|
||||||
mProcessInfo.hThread = mThreadList[dwMainThreadId];
|
mProcessInfo.hThread = mThreadList[dwMainThreadId];
|
||||||
*mAttachProcessInfo = mProcessInfo;
|
*mAttachProcessInfo = mProcessInfo;
|
||||||
|
|
||||||
//create process
|
//create process
|
||||||
CREATE_PROCESS_DEBUG_INFO createProcess;
|
CREATE_PROCESS_DEBUG_INFO createProcess;
|
||||||
memset(&createProcess, 0, sizeof(CREATE_PROCESS_DEBUG_INFO));
|
memset(&createProcess, 0, sizeof(CREATE_PROCESS_DEBUG_INFO));
|
||||||
|
|
@ -190,7 +191,7 @@ public:
|
||||||
if(!dllName.empty())
|
if(!dllName.empty())
|
||||||
CloseHandle(loadDll.hFile);
|
CloseHandle(loadDll.hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
//create threads
|
//create threads
|
||||||
for(auto it : mThreadList)
|
for(auto it : mThreadList)
|
||||||
{
|
{
|
||||||
|
|
@ -211,7 +212,7 @@ public:
|
||||||
|
|
||||||
//attach breakpoint
|
//attach breakpoint
|
||||||
mCbATTACHBREAKPOINT();
|
mCbATTACHBREAKPOINT();
|
||||||
|
|
||||||
//system breakpoint
|
//system breakpoint
|
||||||
mCbSYSTEMBREAKPOINT(nullptr);
|
mCbSYSTEMBREAKPOINT(nullptr);
|
||||||
|
|
||||||
|
|
@ -244,11 +245,11 @@ public:
|
||||||
if(!lpNumberOfBytesRead)
|
if(!lpNumberOfBytesRead)
|
||||||
lpNumberOfBytesRead = &s;
|
lpNumberOfBytesRead = &s;
|
||||||
auto x = !!ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
|
auto x = !!ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
|
||||||
if (!x && nSize <= 0x1000)
|
if(!x && nSize <= 0x1000)
|
||||||
{
|
{
|
||||||
NtSuspendProcess(hProcess);
|
NtSuspendProcess(hProcess);
|
||||||
DWORD oldProtect = 0;
|
DWORD oldProtect = 0;
|
||||||
if (VirtualProtectEx(hProcess, lpBaseAddress, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtect))
|
if(VirtualProtectEx(hProcess, lpBaseAddress, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtect))
|
||||||
{
|
{
|
||||||
x = !!ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
|
x = !!ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
|
||||||
VirtualProtectEx(hProcess, lpBaseAddress, 0x1000, oldProtect, &oldProtect);
|
VirtualProtectEx(hProcess, lpBaseAddress, 0x1000, oldProtect, &oldProtect);
|
||||||
|
|
@ -275,7 +276,7 @@ public:
|
||||||
//Engine
|
//Engine
|
||||||
bool EngineCheckStructAlignment(DWORD StructureType, ULONG_PTR StructureSize) const
|
bool EngineCheckStructAlignment(DWORD StructureType, ULONG_PTR StructureSize) const
|
||||||
{
|
{
|
||||||
if (StructureType == UE_STRUCT_TITAN_ENGINE_CONTEXT)
|
if(StructureType == UE_STRUCT_TITAN_ENGINE_CONTEXT)
|
||||||
return StructureSize == sizeof(TITAN_ENGINE_CONTEXT_t);
|
return StructureSize == sizeof(TITAN_ENGINE_CONTEXT_t);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +293,7 @@ public:
|
||||||
|
|
||||||
void SetCustomHandler(DWORD ExceptionId, PVOID CallBack)
|
void SetCustomHandler(DWORD ExceptionId, PVOID CallBack)
|
||||||
{
|
{
|
||||||
switch (ExceptionId)
|
switch(ExceptionId)
|
||||||
{
|
{
|
||||||
case UE_CH_CREATEPROCESS:
|
case UE_CH_CREATEPROCESS:
|
||||||
mCbCREATEPROCESS = CUSTOMHANDLER(CallBack);
|
mCbCREATEPROCESS = CUSTOMHANDLER(CallBack);
|
||||||
|
|
@ -386,11 +387,11 @@ public:
|
||||||
|
|
||||||
HANDLE TitanOpenProcess(DWORD dwDesiredAccess, bool bInheritHandle, DWORD dwProcessId)
|
HANDLE TitanOpenProcess(DWORD dwDesiredAccess, bool bInheritHandle, DWORD dwProcessId)
|
||||||
{
|
{
|
||||||
if (mSetDebugPrivilege)
|
if(mSetDebugPrivilege)
|
||||||
setDebugPrivilege(GetCurrentProcess(), true);
|
setDebugPrivilege(GetCurrentProcess(), true);
|
||||||
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
||||||
DWORD dwLastError = GetLastError();
|
DWORD dwLastError = GetLastError();
|
||||||
if (mSetDebugPrivilege)
|
if(mSetDebugPrivilege)
|
||||||
setDebugPrivilege(GetCurrentProcess(), false);
|
setDebugPrivilege(GetCurrentProcess(), false);
|
||||||
SetLastError(dwLastError);
|
SetLastError(dwLastError);
|
||||||
return hProcess;
|
return hProcess;
|
||||||
|
|
@ -398,11 +399,11 @@ public:
|
||||||
|
|
||||||
HANDLE TitanOpenThread(DWORD dwDesiredAccess, bool bInheritHandle, DWORD dwThreadId)
|
HANDLE TitanOpenThread(DWORD dwDesiredAccess, bool bInheritHandle, DWORD dwThreadId)
|
||||||
{
|
{
|
||||||
if (mSetDebugPrivilege)
|
if(mSetDebugPrivilege)
|
||||||
setDebugPrivilege(GetCurrentProcess(), true);
|
setDebugPrivilege(GetCurrentProcess(), true);
|
||||||
HANDLE hThread = OpenThread(dwDesiredAccess, bInheritHandle, dwThreadId);
|
HANDLE hThread = OpenThread(dwDesiredAccess, bInheritHandle, dwThreadId);
|
||||||
DWORD dwLastError = GetLastError();
|
DWORD dwLastError = GetLastError();
|
||||||
if (mSetDebugPrivilege)
|
if(mSetDebugPrivilege)
|
||||||
setDebugPrivilege(GetCurrentProcess(), false);
|
setDebugPrivilege(GetCurrentProcess(), false);
|
||||||
SetLastError(dwLastError);
|
SetLastError(dwLastError);
|
||||||
return hThread;
|
return hThread;
|
||||||
|
|
@ -476,7 +477,7 @@ public:
|
||||||
bool StaticFileLoadW(const wchar_t* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA)
|
bool StaticFileLoadW(const wchar_t* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA)
|
||||||
{
|
{
|
||||||
auto file = new ::FileMap<unsigned char>;
|
auto file = new ::FileMap<unsigned char>;
|
||||||
if (!file->Map(szFileName, DesiredAccess == UE_ACCESS_ALL))
|
if(!file->Map(szFileName, DesiredAccess == UE_ACCESS_ALL))
|
||||||
__debugbreak(); //return false;
|
__debugbreak(); //return false;
|
||||||
*FileHandle = file->hFile;
|
*FileHandle = file->hFile;
|
||||||
*LoadedSize = file->size;
|
*LoadedSize = file->size;
|
||||||
|
|
@ -486,7 +487,7 @@ public:
|
||||||
mappedPe.file = std::move(file);
|
mappedPe.file = std::move(file);
|
||||||
mappedPe.buffer = new BufferFile(mappedPe.file->data, mappedPe.file->size);
|
mappedPe.buffer = new BufferFile(mappedPe.file->data, mappedPe.file->size);
|
||||||
mappedPe.pe = new Pe(*mappedPe.buffer);
|
mappedPe.pe = new Pe(*mappedPe.buffer);
|
||||||
if (mappedPe.pe->Parse(true) != Pe::ErrorOk)
|
if(mappedPe.pe->Parse(true) != Pe::ErrorOk)
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
mappedFiles.insert({ *FileMapVA, mappedPe });
|
mappedFiles.insert({ *FileMapVA, mappedPe });
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -495,7 +496,7 @@ public:
|
||||||
bool StaticFileUnloadW(const wchar_t* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA)
|
bool StaticFileUnloadW(const wchar_t* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA)
|
||||||
{
|
{
|
||||||
auto found = mappedFiles.find(FileMapVA);
|
auto found = mappedFiles.find(FileMapVA);
|
||||||
if (found == mappedFiles.end())
|
if(found == mappedFiles.end())
|
||||||
__debugbreak(); //return false;
|
__debugbreak(); //return false;
|
||||||
delete found->second.pe;
|
delete found->second.pe;
|
||||||
delete found->second.buffer;
|
delete found->second.buffer;
|
||||||
|
|
@ -517,21 +518,21 @@ public:
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto found = mappedFiles.find(FileMapVA);
|
auto found = mappedFiles.find(FileMapVA);
|
||||||
if (found == mappedFiles.end())
|
if(found == mappedFiles.end())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
|
|
||||||
if (!found->second.pe->IsValidPe())
|
if(!found->second.pe->IsValidPe())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
|
|
||||||
if (AddressToConvert < FileMapVA)
|
if(AddressToConvert < FileMapVA)
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
|
|
||||||
// convert: FileOffset -> VA
|
// convert: FileOffset -> VA
|
||||||
auto offset = found->second.pe->ConvertOffsetToRva(
|
auto offset = found->second.pe->ConvertOffsetToRva(
|
||||||
uint32( AddressToConvert - FileMapVA )
|
uint32(AddressToConvert - FileMapVA)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (offset == INVALID_VALUE)
|
if(offset == INVALID_VALUE)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return ReturnType ? FileMapVA + offset : offset;
|
return ReturnType ? FileMapVA + offset : offset;
|
||||||
|
|
@ -551,8 +552,8 @@ public:
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return ConvertVAtoFileOffsetEx(
|
return ConvertVAtoFileOffsetEx(
|
||||||
FileMapVA ,0 ,0 ,
|
FileMapVA, 0, 0,
|
||||||
AddressToConvert, false, ReturnType );
|
AddressToConvert, false, ReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
@ -572,23 +573,23 @@ public:
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto found = mappedFiles.find(FileMapVA);
|
auto found = mappedFiles.find(FileMapVA);
|
||||||
if (found == mappedFiles.end())
|
if(found == mappedFiles.end())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
|
|
||||||
if (!found->second.pe->IsValidPe())
|
if(!found->second.pe->IsValidPe())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
|
|
||||||
// Convert to RVA if needed
|
// Convert to RVA if needed
|
||||||
auto RVA_ToConvert = AddressIsRVA ?
|
auto RVA_ToConvert = AddressIsRVA ?
|
||||||
AddressToConvert :
|
AddressToConvert :
|
||||||
AddressToConvert - ImageBase;
|
AddressToConvert - ImageBase;
|
||||||
|
|
||||||
// convert: VA -> FileOffset
|
// convert: VA -> FileOffset
|
||||||
auto offset = found->second.pe->ConvertRvaToOffset(
|
auto offset = found->second.pe->ConvertRvaToOffset(
|
||||||
uint32( RVA_ToConvert )
|
uint32(RVA_ToConvert)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (offset == INVALID_VALUE)
|
if(offset == INVALID_VALUE)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return ReturnType ? FileMapVA + offset : offset;
|
return ReturnType ? FileMapVA + offset : offset;
|
||||||
|
|
@ -597,7 +598,7 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ULONG_PTR GetPE32DataW_impl(const Region<T> & headers, DWORD WhichSection, DWORD WhichData, const std::vector<Section> & sections)
|
ULONG_PTR GetPE32DataW_impl(const Region<T> & headers, DWORD WhichSection, DWORD WhichData, const std::vector<Section> & sections)
|
||||||
{
|
{
|
||||||
switch (WhichData)
|
switch(WhichData)
|
||||||
{
|
{
|
||||||
case UE_PE_OFFSET:
|
case UE_PE_OFFSET:
|
||||||
return headers.Offset();
|
return headers.Offset();
|
||||||
|
|
@ -652,14 +653,14 @@ public:
|
||||||
ULONG_PTR GetPE32DataFromMappedFile(ULONG_PTR FileMapVA, DWORD WhichSection, DWORD WhichData)
|
ULONG_PTR GetPE32DataFromMappedFile(ULONG_PTR FileMapVA, DWORD WhichSection, DWORD WhichData)
|
||||||
{
|
{
|
||||||
auto found = mappedFiles.find(FileMapVA);
|
auto found = mappedFiles.find(FileMapVA);
|
||||||
if (found == mappedFiles.end())
|
if(found == mappedFiles.end())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
if (!found->second.pe->IsValidPe())
|
if(!found->second.pe->IsValidPe())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
auto sections = found->second.pe->GetSections();
|
auto sections = found->second.pe->GetSections();
|
||||||
return found->second.pe->IsPe64()
|
return found->second.pe->IsPe64()
|
||||||
? GetPE32DataW_impl(found->second.pe->GetNtHeaders64(), WhichSection, WhichData, sections)
|
? GetPE32DataW_impl(found->second.pe->GetNtHeaders64(), WhichSection, WhichData, sections)
|
||||||
: GetPE32DataW_impl(found->second.pe->GetNtHeaders32(), WhichSection, WhichData, sections);
|
: GetPE32DataW_impl(found->second.pe->GetNtHeaders32(), WhichSection, WhichData, sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG_PTR GetPE32Data(const char* szFileName, DWORD WhichSection, DWORD WhichData)
|
ULONG_PTR GetPE32Data(const char* szFileName, DWORD WhichSection, DWORD WhichData)
|
||||||
|
|
@ -670,18 +671,18 @@ public:
|
||||||
ULONG_PTR GetPE32DataW(const wchar_t* szFileName, DWORD WhichSection, DWORD WhichData)
|
ULONG_PTR GetPE32DataW(const wchar_t* szFileName, DWORD WhichSection, DWORD WhichData)
|
||||||
{
|
{
|
||||||
FileMap<unsigned char> file;
|
FileMap<unsigned char> file;
|
||||||
if (!file.Map(szFileName))
|
if(!file.Map(szFileName))
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
BufferFile buf(file.data, file.size);
|
BufferFile buf(file.data, file.size);
|
||||||
Pe pe(buf);
|
Pe pe(buf);
|
||||||
if (pe.Parse(true) != Pe::ErrorOk)
|
if(pe.Parse(true) != Pe::ErrorOk)
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
if (!pe.IsValidPe())
|
if(!pe.IsValidPe())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
auto sections = pe.GetSections();
|
auto sections = pe.GetSections();
|
||||||
return pe.IsPe64()
|
return pe.IsPe64()
|
||||||
? GetPE32DataW_impl(pe.GetNtHeaders64(), WhichSection, WhichData, sections)
|
? GetPE32DataW_impl(pe.GetNtHeaders64(), WhichSection, WhichData, sections)
|
||||||
: GetPE32DataW_impl(pe.GetNtHeaders32(), WhichSection, WhichData, sections);
|
: GetPE32DataW_impl(pe.GetNtHeaders32(), WhichSection, WhichData, sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA)
|
bool IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA)
|
||||||
|
|
@ -767,17 +768,17 @@ private: //functions
|
||||||
{
|
{
|
||||||
DWORD dwLastError;
|
DWORD dwLastError;
|
||||||
HANDLE hToken = 0;
|
HANDLE hToken = 0;
|
||||||
if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
if(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||||
{
|
{
|
||||||
dwLastError = GetLastError();
|
dwLastError = GetLastError();
|
||||||
if (hToken)
|
if(hToken)
|
||||||
CloseHandle(hToken);
|
CloseHandle(hToken);
|
||||||
return dwLastError;
|
return dwLastError;
|
||||||
}
|
}
|
||||||
TOKEN_PRIVILEGES tokenPrivileges;
|
TOKEN_PRIVILEGES tokenPrivileges;
|
||||||
memset(&tokenPrivileges, 0, sizeof(TOKEN_PRIVILEGES));
|
memset(&tokenPrivileges, 0, sizeof(TOKEN_PRIVILEGES));
|
||||||
LUID luid;
|
LUID luid;
|
||||||
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
|
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
|
||||||
{
|
{
|
||||||
dwLastError = GetLastError();
|
dwLastError = GetLastError();
|
||||||
CloseHandle(hToken);
|
CloseHandle(hToken);
|
||||||
|
|
@ -785,7 +786,7 @@ private: //functions
|
||||||
}
|
}
|
||||||
tokenPrivileges.PrivilegeCount = 1;
|
tokenPrivileges.PrivilegeCount = 1;
|
||||||
tokenPrivileges.Privileges[0].Luid = luid;
|
tokenPrivileges.Privileges[0].Luid = luid;
|
||||||
if (bEnablePrivilege)
|
if(bEnablePrivilege)
|
||||||
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
else
|
else
|
||||||
tokenPrivileges.Privileges[0].Attributes = 0;
|
tokenPrivileges.Privileges[0].Attributes = 0;
|
||||||
|
|
|
||||||
|
|
@ -122,10 +122,10 @@ __declspec(dllexport) ULONG_PTR TITCALL ImporterGetRemoteAPIAddressEx(const char
|
||||||
static auto hModule = GetModuleHandleW(X64DBG_DLL);
|
static auto hModule = GetModuleHandleW(X64DBG_DLL);
|
||||||
#undef X64DBG_DLL
|
#undef X64DBG_DLL
|
||||||
|
|
||||||
if (hModule)
|
if(hModule)
|
||||||
{
|
{
|
||||||
static auto DbgValFromString = (ULONG_PTR(*)(const char*))GetProcAddress(hModule, "DbgValFromString");
|
static auto DbgValFromString = (ULONG_PTR(*)(const char*))GetProcAddress(hModule, "DbgValFromString");
|
||||||
if (DbgValFromString)
|
if(DbgValFromString)
|
||||||
{
|
{
|
||||||
char expr[1024] = "";
|
char expr[1024] = "";
|
||||||
_snprintf_s(expr, _TRUNCATE, "\"%s\":%s", szDLLName, szAPIName);
|
_snprintf_s(expr, _TRUNCATE, "\"%s\":%s", szDLLName, szAPIName);
|
||||||
|
|
@ -293,7 +293,7 @@ BOOL WINAPI DllMain(
|
||||||
_In_ LPVOID lpvReserved
|
_In_ LPVOID lpvReserved
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
if(fdwReason == DLL_PROCESS_ATTACH)
|
||||||
emu.engineHandle = hinstDLL;
|
emu.engineHandle = hinstDLL;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ public:
|
||||||
PROCESS_INFORMATION* InitDebugW(const wchar_t* szFileName, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder)
|
PROCESS_INFORMATION* InitDebugW(const wchar_t* szFileName, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder)
|
||||||
{
|
{
|
||||||
mCbATTACHBREAKPOINT = nullptr;
|
mCbATTACHBREAKPOINT = nullptr;
|
||||||
if (!Init(szFileName, szCommandLine, szCurrentFolder))
|
if(!Init(szFileName, szCommandLine, szCurrentFolder))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &mMainProcess;
|
return &mMainProcess;
|
||||||
}
|
}
|
||||||
|
|
@ -36,20 +36,20 @@ public:
|
||||||
PROCESS_INFORMATION* InitDLLDebugW(const wchar_t* szFileName, bool /* ReserveModuleBase = false */, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder, LPVOID /*EntryCallBack = 0 */)
|
PROCESS_INFORMATION* InitDLLDebugW(const wchar_t* szFileName, bool /* ReserveModuleBase = false */, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder, LPVOID /*EntryCallBack = 0 */)
|
||||||
{
|
{
|
||||||
wcscpy_s(szDebuggeeName, szFileName);
|
wcscpy_s(szDebuggeeName, szFileName);
|
||||||
if (TryExtractDllLoader())
|
if(TryExtractDllLoader())
|
||||||
{
|
{
|
||||||
mCbATTACHBREAKPOINT = nullptr;
|
mCbATTACHBREAKPOINT = nullptr;
|
||||||
if (!Init(szDebuggeeName, szCommandLine, szCurrentFolder, true, true))
|
if(!Init(szDebuggeeName, szCommandLine, szCurrentFolder, true, true))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
wchar_t szName[256] = L"";
|
wchar_t szName[256] = L"";
|
||||||
swprintf(szName, 256, L"Local\\szLibraryName%X", mMainProcess.dwProcessId);
|
swprintf(szName, 256, L"Local\\szLibraryName%X", mMainProcess.dwProcessId);
|
||||||
//TODO: close this once we actually see the DLL is loaded in the process
|
//TODO: close this once we actually see the DLL is loaded in the process
|
||||||
HANDLE DebugDLLFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 512 * sizeof(wchar_t), szName);
|
HANDLE DebugDLLFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 512 * sizeof(wchar_t), szName);
|
||||||
if (DebugDLLFileMapping)
|
if(DebugDLLFileMapping)
|
||||||
{
|
{
|
||||||
const size_t filemapSize = 512;
|
const size_t filemapSize = 512;
|
||||||
wchar_t* szLibraryPathMapping = (wchar_t*)MapViewOfFile(DebugDLLFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, filemapSize * sizeof(wchar_t));
|
wchar_t* szLibraryPathMapping = (wchar_t*)MapViewOfFile(DebugDLLFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, filemapSize * sizeof(wchar_t));
|
||||||
if (szLibraryPathMapping)
|
if(szLibraryPathMapping)
|
||||||
{
|
{
|
||||||
wcscpy_s(szLibraryPathMapping, filemapSize, szFileName);
|
wcscpy_s(szLibraryPathMapping, filemapSize, szFileName);
|
||||||
UnmapViewOfFile(szLibraryPathMapping);
|
UnmapViewOfFile(szLibraryPathMapping);
|
||||||
|
|
@ -98,7 +98,7 @@ public:
|
||||||
bool MemoryReadSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead)
|
bool MemoryReadSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead)
|
||||||
{
|
{
|
||||||
auto process = processFromHandle(hProcess);
|
auto process = processFromHandle(hProcess);
|
||||||
if (!process)
|
if(!process)
|
||||||
return false;
|
return false;
|
||||||
return process->MemReadSafe(ptr(lpBaseAddress), lpBuffer, nSize, (ptr*)lpNumberOfBytesRead);
|
return process->MemReadSafe(ptr(lpBaseAddress), lpBuffer, nSize, (ptr*)lpNumberOfBytesRead);
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +106,7 @@ public:
|
||||||
bool MemoryWriteSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten)
|
bool MemoryWriteSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten)
|
||||||
{
|
{
|
||||||
auto process = processFromHandle(hProcess);
|
auto process = processFromHandle(hProcess);
|
||||||
if (!process)
|
if(!process)
|
||||||
return false;
|
return false;
|
||||||
return process->MemWriteSafe(ptr(lpBaseAddress), lpBuffer, nSize, (ptr*)lpNumberOfBytesWritten);
|
return process->MemWriteSafe(ptr(lpBaseAddress), lpBuffer, nSize, (ptr*)lpNumberOfBytesWritten);
|
||||||
}
|
}
|
||||||
|
|
@ -114,11 +114,11 @@ public:
|
||||||
bool Fill(LPVOID MemoryStart, DWORD MemorySize, PBYTE FillByte)
|
bool Fill(LPVOID MemoryStart, DWORD MemorySize, PBYTE FillByte)
|
||||||
{
|
{
|
||||||
//TODO: this is fucking inefficient
|
//TODO: this is fucking inefficient
|
||||||
if (!mProcess)
|
if(!mProcess)
|
||||||
return false;
|
return false;
|
||||||
for (DWORD i = 0; i < MemorySize; i++)
|
for(DWORD i = 0; i < MemorySize; i++)
|
||||||
{
|
{
|
||||||
if (!mProcess->MemWriteSafe(ptr(MemoryStart) + i, FillByte, 1))
|
if(!mProcess->MemWriteSafe(ptr(MemoryStart) + i, FillByte, 1))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -127,7 +127,7 @@ public:
|
||||||
//Engine
|
//Engine
|
||||||
bool EngineCheckStructAlignment(DWORD StructureType, ULONG_PTR StructureSize) const
|
bool EngineCheckStructAlignment(DWORD StructureType, ULONG_PTR StructureSize) const
|
||||||
{
|
{
|
||||||
if (StructureType == UE_STRUCT_TITAN_ENGINE_CONTEXT)
|
if(StructureType == UE_STRUCT_TITAN_ENGINE_CONTEXT)
|
||||||
return StructureSize == sizeof(TITAN_ENGINE_CONTEXT_t);
|
return StructureSize == sizeof(TITAN_ENGINE_CONTEXT_t);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +144,7 @@ public:
|
||||||
|
|
||||||
void SetCustomHandler(DWORD ExceptionId, PVOID CallBack)
|
void SetCustomHandler(DWORD ExceptionId, PVOID CallBack)
|
||||||
{
|
{
|
||||||
switch (ExceptionId)
|
switch(ExceptionId)
|
||||||
{
|
{
|
||||||
case UE_CH_CREATEPROCESS:
|
case UE_CH_CREATEPROCESS:
|
||||||
mCbCREATEPROCESS = CUSTOMHANDLER(CallBack);
|
mCbCREATEPROCESS = CUSTOMHANDLER(CallBack);
|
||||||
|
|
@ -183,7 +183,7 @@ public:
|
||||||
|
|
||||||
void SetEngineVariable(DWORD VariableId, bool VariableSet)
|
void SetEngineVariable(DWORD VariableId, bool VariableSet)
|
||||||
{
|
{
|
||||||
switch (VariableId)
|
switch(VariableId)
|
||||||
{
|
{
|
||||||
case UE_ENGINE_SET_DEBUG_PRIVILEGE:
|
case UE_ENGINE_SET_DEBUG_PRIVILEGE:
|
||||||
mSetDebugPrivilege = VariableSet;
|
mSetDebugPrivilege = VariableSet;
|
||||||
|
|
@ -303,7 +303,7 @@ public:
|
||||||
ULONG_PTR GetDebuggedFileBaseAddress()
|
ULONG_PTR GetDebuggedFileBaseAddress()
|
||||||
{
|
{
|
||||||
auto itr = mProcesses.find(mMainProcess.dwProcessId);
|
auto itr = mProcesses.find(mMainProcess.dwProcessId);
|
||||||
if (itr != mProcesses.end())
|
if(itr != mProcesses.end())
|
||||||
return (ULONG_PTR)itr->second->createProcessInfo.lpBaseOfImage;
|
return (ULONG_PTR)itr->second->createProcessInfo.lpBaseOfImage;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -311,14 +311,14 @@ public:
|
||||||
//Stepping
|
//Stepping
|
||||||
void StepOver(LPVOID CallBack)
|
void StepOver(LPVOID CallBack)
|
||||||
{
|
{
|
||||||
if (!mProcess || !CallBack)
|
if(!mProcess || !CallBack)
|
||||||
return;
|
return;
|
||||||
mProcess->StepOver(STEPCALLBACK(CallBack));
|
mProcess->StepOver(STEPCALLBACK(CallBack));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StepInto(LPVOID CallBack)
|
void StepInto(LPVOID CallBack)
|
||||||
{
|
{
|
||||||
if (!mThread || !CallBack)
|
if(!mThread || !CallBack)
|
||||||
return;
|
return;
|
||||||
mThread->StepInto(STEPCALLBACK(CallBack));
|
mThread->StepInto(STEPCALLBACK(CallBack));
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +328,7 @@ public:
|
||||||
ThreadSuspender(HANDLE hThread, bool running)
|
ThreadSuspender(HANDLE hThread, bool running)
|
||||||
: hThread(running ? hThread : nullptr)
|
: hThread(running ? hThread : nullptr)
|
||||||
{
|
{
|
||||||
if (this->hThread)
|
if(this->hThread)
|
||||||
SuspendThread(this->hThread);
|
SuspendThread(this->hThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,7 +337,7 @@ public:
|
||||||
|
|
||||||
~ThreadSuspender()
|
~ThreadSuspender()
|
||||||
{
|
{
|
||||||
if (this->hThread)
|
if(this->hThread)
|
||||||
ResumeThread(this->hThread);
|
ResumeThread(this->hThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,36 +347,36 @@ public:
|
||||||
//Registers
|
//Registers
|
||||||
ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister)
|
ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister)
|
||||||
{
|
{
|
||||||
if (!hActiveThread)
|
if(!hActiveThread)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ThreadSuspender suspender(hActiveThread, mIsRunning);
|
ThreadSuspender suspender(hActiveThread, mIsRunning);
|
||||||
auto r = registerFromDword(IndexOfRegister);
|
auto r = registerFromDword(IndexOfRegister);
|
||||||
if (r == Registers::R::Invalid)
|
if(r == Registers::R::Invalid)
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
return Registers(hActiveThread).Get(r);
|
return Registers(hActiveThread).Get(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister, ULONG_PTR NewRegisterValue)
|
bool SetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister, ULONG_PTR NewRegisterValue)
|
||||||
{
|
{
|
||||||
if (!hActiveThread)
|
if(!hActiveThread)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ThreadSuspender suspender(hActiveThread, mIsRunning);
|
ThreadSuspender suspender(hActiveThread, mIsRunning);
|
||||||
|
|
||||||
auto r = registerFromDword(IndexOfRegister);
|
auto r = registerFromDword(IndexOfRegister);
|
||||||
if (r != Registers::R::Invalid)
|
if(r != Registers::R::Invalid)
|
||||||
{
|
{
|
||||||
Registers(hActiveThread).Set(r, NewRegisterValue);
|
Registers(hActiveThread).Set(r, NewRegisterValue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TITAN_ENGINE_CONTEXT_t titcontext;
|
TITAN_ENGINE_CONTEXT_t titcontext;
|
||||||
if (!_GetFullContextDataEx(hActiveThread, &titcontext, IndexOfRegister >= UE_MXCSR))
|
if(!_GetFullContextDataEx(hActiveThread, &titcontext, IndexOfRegister >= UE_MXCSR))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool avx_priority = false;
|
bool avx_priority = false;
|
||||||
switch (IndexOfRegister)
|
switch(IndexOfRegister)
|
||||||
{
|
{
|
||||||
case UE_X87_STATUSWORD:
|
case UE_X87_STATUSWORD:
|
||||||
{
|
{
|
||||||
|
|
@ -481,7 +481,8 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: __debugbreak();
|
default:
|
||||||
|
__debugbreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _SetFullContextDataEx(hActiveThread, &titcontext, avx_priority);
|
return _SetFullContextDataEx(hActiveThread, &titcontext, avx_priority);
|
||||||
|
|
@ -505,7 +506,7 @@ public:
|
||||||
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
|
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for(i = 0; i < 8; i++)
|
||||||
mmx[i] = *((uint64_t*)GetRegisterAreaOf87register(titcontext->RegisterArea, x87r0_position, i));
|
mmx[i] = *((uint64_t*)GetRegisterAreaOf87register(titcontext->RegisterArea, x87r0_position, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,7 +523,7 @@ public:
|
||||||
int STInTopStack = GetSTInTOPStackFromStatusWord(titcontext->x87fpu.StatusWord);
|
int STInTopStack = GetSTInTOPStackFromStatusWord(titcontext->x87fpu.StatusWord);
|
||||||
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
|
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for(int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
memcpy(x87FPURegisters[i].data, GetRegisterAreaOf87register(titcontext->RegisterArea, x87r0_position, i), 10);
|
memcpy(x87FPURegisters[i].data, GetRegisterAreaOf87register(titcontext->RegisterArea, x87r0_position, i), 10);
|
||||||
x87FPURegisters[i].st_value = GetSTValueFromIndex(x87r0_position, i);
|
x87FPURegisters[i].st_value = GetSTValueFromIndex(x87r0_position, i);
|
||||||
|
|
@ -595,15 +596,15 @@ public:
|
||||||
if(!found->second.pe->IsValidPe())
|
if(!found->second.pe->IsValidPe())
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
|
|
||||||
if (AddressToConvert < FileMapVA)
|
if(AddressToConvert < FileMapVA)
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
|
|
||||||
// convert: FileOffset -> VA
|
// convert: FileOffset -> VA
|
||||||
auto offset = found->second.pe->ConvertOffsetToRva(
|
auto offset = found->second.pe->ConvertOffsetToRva(
|
||||||
uint32( AddressToConvert - FileMapVA )
|
uint32(AddressToConvert - FileMapVA)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (offset == INVALID_VALUE)
|
if(offset == INVALID_VALUE)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return ReturnType ? FileMapVA + offset : offset;
|
return ReturnType ? FileMapVA + offset : offset;
|
||||||
|
|
@ -623,8 +624,8 @@ public:
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return ConvertVAtoFileOffsetEx(
|
return ConvertVAtoFileOffsetEx(
|
||||||
FileMapVA ,0 ,0 ,
|
FileMapVA, 0, 0,
|
||||||
AddressToConvert, false, ReturnType );
|
AddressToConvert, false, ReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
@ -652,15 +653,15 @@ public:
|
||||||
|
|
||||||
// Convert to RVA if needed
|
// Convert to RVA if needed
|
||||||
auto RVA_ToConvert = AddressIsRVA ?
|
auto RVA_ToConvert = AddressIsRVA ?
|
||||||
AddressToConvert :
|
AddressToConvert :
|
||||||
AddressToConvert - ImageBase;
|
AddressToConvert - ImageBase;
|
||||||
|
|
||||||
// convert: VA -> FileOffset
|
// convert: VA -> FileOffset
|
||||||
auto offset = found->second.pe->ConvertRvaToOffset(
|
auto offset = found->second.pe->ConvertRvaToOffset(
|
||||||
uint32( RVA_ToConvert )
|
uint32(RVA_ToConvert)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (offset == INVALID_VALUE)
|
if(offset == INVALID_VALUE)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return ReturnType ? FileMapVA + offset : offset;
|
return ReturnType ? FileMapVA + offset : offset;
|
||||||
|
|
@ -730,8 +731,8 @@ public:
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
auto sections = found->second.pe->GetSections();
|
auto sections = found->second.pe->GetSections();
|
||||||
return found->second.pe->IsPe64()
|
return found->second.pe->IsPe64()
|
||||||
? GetPE32DataW_impl(found->second.pe->GetNtHeaders64(), WhichSection, WhichData, sections)
|
? GetPE32DataW_impl(found->second.pe->GetNtHeaders64(), WhichSection, WhichData, sections)
|
||||||
: GetPE32DataW_impl(found->second.pe->GetNtHeaders32(), WhichSection, WhichData, sections);
|
: GetPE32DataW_impl(found->second.pe->GetNtHeaders32(), WhichSection, WhichData, sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG_PTR GetPE32Data(const char* szFileName, DWORD WhichSection, DWORD WhichData)
|
ULONG_PTR GetPE32Data(const char* szFileName, DWORD WhichSection, DWORD WhichData)
|
||||||
|
|
@ -752,8 +753,8 @@ public:
|
||||||
__debugbreak(); //return 0;
|
__debugbreak(); //return 0;
|
||||||
auto sections = pe.GetSections();
|
auto sections = pe.GetSections();
|
||||||
return pe.IsPe64()
|
return pe.IsPe64()
|
||||||
? GetPE32DataW_impl(pe.GetNtHeaders64(), WhichSection, WhichData, sections)
|
? GetPE32DataW_impl(pe.GetNtHeaders64(), WhichSection, WhichData, sections)
|
||||||
: GetPE32DataW_impl(pe.GetNtHeaders32(), WhichSection, WhichData, sections);
|
: GetPE32DataW_impl(pe.GetNtHeaders32(), WhichSection, WhichData, sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA)
|
bool IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA)
|
||||||
|
|
@ -764,7 +765,7 @@ public:
|
||||||
//Software Breakpoints
|
//Software Breakpoints
|
||||||
bool SetBPX(ULONG_PTR bpxAddress, DWORD bpxType, LPVOID bpxCallBack)
|
bool SetBPX(ULONG_PTR bpxAddress, DWORD bpxType, LPVOID bpxCallBack)
|
||||||
{
|
{
|
||||||
if (!mProcess)
|
if(!mProcess)
|
||||||
return false;
|
return false;
|
||||||
return mProcess->SetBreakpoint(bpxAddress, [bpxCallBack](const BreakpointInfo &)
|
return mProcess->SetBreakpoint(bpxAddress, [bpxCallBack](const BreakpointInfo &)
|
||||||
{
|
{
|
||||||
|
|
@ -774,7 +775,7 @@ public:
|
||||||
|
|
||||||
bool DeleteBPX(ULONG_PTR bpxAddress)
|
bool DeleteBPX(ULONG_PTR bpxAddress)
|
||||||
{
|
{
|
||||||
if (!mProcess)
|
if(!mProcess)
|
||||||
return false;
|
return false;
|
||||||
return mProcess->DeleteBreakpoint(bpxAddress);
|
return mProcess->DeleteBreakpoint(bpxAddress);
|
||||||
}
|
}
|
||||||
|
|
@ -782,7 +783,7 @@ public:
|
||||||
bool IsBPXEnabled(ULONG_PTR bpxAddress)
|
bool IsBPXEnabled(ULONG_PTR bpxAddress)
|
||||||
{
|
{
|
||||||
return (mProcess->MemIsValidPtr(bpxAddress) &&
|
return (mProcess->MemIsValidPtr(bpxAddress) &&
|
||||||
mProcess->breakpoints.find({ BreakpointType::Software, bpxAddress }) != mProcess->breakpoints.end());
|
mProcess->breakpoints.find({ BreakpointType::Software, bpxAddress }) != mProcess->breakpoints.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBPXOptions(long DefaultBreakPointType)
|
void SetBPXOptions(long DefaultBreakPointType)
|
||||||
|
|
@ -792,7 +793,7 @@ public:
|
||||||
//Memory Breakpoints
|
//Memory Breakpoints
|
||||||
bool SetMemoryBPXEx(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory, DWORD BreakPointType, bool RestoreOnHit, LPVOID bpxCallBack)
|
bool SetMemoryBPXEx(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory, DWORD BreakPointType, bool RestoreOnHit, LPVOID bpxCallBack)
|
||||||
{
|
{
|
||||||
if (!mProcess)
|
if(!mProcess)
|
||||||
return false;
|
return false;
|
||||||
return mProcess->SetMemoryBreakpoint(ptr(MemoryStart), ptr(SizeOfMemory), [bpxCallBack](const BreakpointInfo & info)
|
return mProcess->SetMemoryBreakpoint(ptr(MemoryStart), ptr(SizeOfMemory), [bpxCallBack](const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
|
|
@ -802,7 +803,7 @@ public:
|
||||||
|
|
||||||
bool RemoveMemoryBPX(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory)
|
bool RemoveMemoryBPX(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory)
|
||||||
{
|
{
|
||||||
if (!mProcess)
|
if(!mProcess)
|
||||||
return false;
|
return false;
|
||||||
return mProcess->DeleteMemoryBreakpoint(ptr(MemoryStart));
|
return mProcess->DeleteMemoryBreakpoint(ptr(MemoryStart));
|
||||||
}
|
}
|
||||||
|
|
@ -810,7 +811,7 @@ public:
|
||||||
//Hardware Breakpoints
|
//Hardware Breakpoints
|
||||||
bool SetHardwareBreakPoint(ULONG_PTR bpxAddress, DWORD IndexOfRegister, DWORD bpxType, DWORD bpxSize, LPVOID bpxCallBack)
|
bool SetHardwareBreakPoint(ULONG_PTR bpxAddress, DWORD IndexOfRegister, DWORD bpxType, DWORD bpxSize, LPVOID bpxCallBack)
|
||||||
{
|
{
|
||||||
if (!mProcess)
|
if(!mProcess)
|
||||||
return false;
|
return false;
|
||||||
auto running = mIsRunning;
|
auto running = mIsRunning;
|
||||||
if(running)
|
if(running)
|
||||||
|
|
@ -819,11 +820,11 @@ public:
|
||||||
thread.second->Suspend();
|
thread.second->Suspend();
|
||||||
}
|
}
|
||||||
if(!mProcess->SetHardwareBreakpoint(bpxAddress,
|
if(!mProcess->SetHardwareBreakpoint(bpxAddress,
|
||||||
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
|
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
|
||||||
{
|
{
|
||||||
(HWBPCALLBACK(bpxCallBack))((const void*)info.address);
|
(HWBPCALLBACK(bpxCallBack))((const void*)info.address);
|
||||||
}, hwtypeFromTitan(bpxType), hwsizeFromTitan(bpxSize)))
|
}, hwtypeFromTitan(bpxType), hwsizeFromTitan(bpxSize)))
|
||||||
return false;
|
return false;
|
||||||
if(running)
|
if(running)
|
||||||
{
|
{
|
||||||
for(auto & thread : mProcess->threads)
|
for(auto & thread : mProcess->threads)
|
||||||
|
|
@ -834,7 +835,7 @@ public:
|
||||||
|
|
||||||
bool DeleteHardwareBreakPoint(DWORD IndexOfRegister)
|
bool DeleteHardwareBreakPoint(DWORD IndexOfRegister)
|
||||||
{
|
{
|
||||||
if (!mProcess || IndexOfRegister > 3)
|
if(!mProcess || IndexOfRegister > 3)
|
||||||
return false;
|
return false;
|
||||||
auto address = mProcess->hardwareBreakpoints[IndexOfRegister].address;
|
auto address = mProcess->hardwareBreakpoints[IndexOfRegister].address;
|
||||||
return mProcess->DeleteHardwareBreakpoint(address);
|
return mProcess->DeleteHardwareBreakpoint(address);
|
||||||
|
|
@ -842,11 +843,11 @@ public:
|
||||||
|
|
||||||
bool GetUnusedHardwareBreakPointRegister(LPDWORD RegisterIndex)
|
bool GetUnusedHardwareBreakPointRegister(LPDWORD RegisterIndex)
|
||||||
{
|
{
|
||||||
if (!mProcess || !RegisterIndex)
|
if(!mProcess || !RegisterIndex)
|
||||||
return false;
|
return false;
|
||||||
HardwareSlot slot;
|
HardwareSlot slot;
|
||||||
bool result = mProcess->GetFreeHardwareBreakpointSlot(slot);
|
bool result = mProcess->GetFreeHardwareBreakpointSlot(slot);
|
||||||
if (result)
|
if(result)
|
||||||
*RegisterIndex = (DWORD)slot;
|
*RegisterIndex = (DWORD)slot;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -866,55 +867,55 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const Process & process) override
|
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const Process & process) override
|
||||||
{
|
{
|
||||||
if (mCbCREATEPROCESS)
|
if(mCbCREATEPROCESS)
|
||||||
mCbCREATEPROCESS(&createProcess);
|
mCbCREATEPROCESS(&createProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const Process & process) override
|
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const Process & process) override
|
||||||
{
|
{
|
||||||
if (mCbEXITPROCESS)
|
if(mCbEXITPROCESS)
|
||||||
mCbEXITPROCESS(&exitProcess);
|
mCbEXITPROCESS(&exitProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const Thread & thread) override
|
void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const Thread & thread) override
|
||||||
{
|
{
|
||||||
if (mCbCREATETHREAD)
|
if(mCbCREATETHREAD)
|
||||||
mCbCREATETHREAD(&createThread);
|
mCbCREATETHREAD(&createThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const Thread & thread) override
|
void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const Thread & thread) override
|
||||||
{
|
{
|
||||||
if (mCbEXITTHREAD)
|
if(mCbEXITTHREAD)
|
||||||
mCbEXITTHREAD(&exitThread);
|
mCbEXITTHREAD(&exitThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll) override
|
void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll) override
|
||||||
{
|
{
|
||||||
if (mCbLOADDLL)
|
if(mCbLOADDLL)
|
||||||
mCbLOADDLL(&loadDll);
|
mCbLOADDLL(&loadDll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll) override
|
void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll) override
|
||||||
{
|
{
|
||||||
if (mCbUNLOADDLL)
|
if(mCbUNLOADDLL)
|
||||||
mCbUNLOADDLL(&unloadDll);
|
mCbUNLOADDLL(&unloadDll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) override
|
void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) override
|
||||||
{
|
{
|
||||||
if (mCbUNHANDLEDEXCEPTION)
|
if(mCbUNHANDLEDEXCEPTION)
|
||||||
mCbUNHANDLEDEXCEPTION(&mDebugEvent.u.Exception);
|
mCbUNHANDLEDEXCEPTION(&mDebugEvent.u.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
|
void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
|
||||||
{
|
{
|
||||||
if (mCbOUTPUTDEBUGSTRING)
|
if(mCbOUTPUTDEBUGSTRING)
|
||||||
mCbOUTPUTDEBUGSTRING(&debugString);
|
mCbOUTPUTDEBUGSTRING(&debugString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbPreDebugEvent(const DEBUG_EVENT & debugEvent) override
|
void cbPreDebugEvent(const DEBUG_EVENT & debugEvent) override
|
||||||
{
|
{
|
||||||
if (mCbDEBUGEVENT)
|
if(mCbDEBUGEVENT)
|
||||||
mCbDEBUGEVENT(&debugEvent);
|
mCbDEBUGEVENT(&debugEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -930,60 +931,103 @@ protected:
|
||||||
|
|
||||||
void cbSystemBreakpoint() override
|
void cbSystemBreakpoint() override
|
||||||
{
|
{
|
||||||
if (mCbSYSTEMBREAKPOINT)
|
if(mCbSYSTEMBREAKPOINT)
|
||||||
mCbSYSTEMBREAKPOINT(&mDebugEvent.u.Exception);
|
mCbSYSTEMBREAKPOINT(&mDebugEvent.u.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
private: //functions
|
private: //functions
|
||||||
inline Registers::R registerFromDword(DWORD IndexOfRegister)
|
inline Registers::R registerFromDword(DWORD IndexOfRegister)
|
||||||
{
|
{
|
||||||
switch (IndexOfRegister)
|
switch(IndexOfRegister)
|
||||||
{
|
{
|
||||||
case UE_EAX: return Registers::R::EAX;
|
case UE_EAX:
|
||||||
case UE_EBX: return Registers::R::EBX;
|
return Registers::R::EAX;
|
||||||
case UE_ECX: return Registers::R::ECX;
|
case UE_EBX:
|
||||||
case UE_EDX: return Registers::R::EDX;
|
return Registers::R::EBX;
|
||||||
case UE_EDI: return Registers::R::EDI;
|
case UE_ECX:
|
||||||
case UE_ESI: return Registers::R::ESI;
|
return Registers::R::ECX;
|
||||||
case UE_EBP: return Registers::R::EBP;
|
case UE_EDX:
|
||||||
case UE_ESP: return Registers::R::ESP;
|
return Registers::R::EDX;
|
||||||
case UE_EIP: return Registers::R::EIP;
|
case UE_EDI:
|
||||||
case UE_EFLAGS: return Registers::R::EFlags;
|
return Registers::R::EDI;
|
||||||
case UE_DR0: return Registers::R::DR0;
|
case UE_ESI:
|
||||||
case UE_DR1: return Registers::R::DR1;
|
return Registers::R::ESI;
|
||||||
case UE_DR2: return Registers::R::DR2;
|
case UE_EBP:
|
||||||
case UE_DR3: return Registers::R::DR3;
|
return Registers::R::EBP;
|
||||||
case UE_DR6: return Registers::R::DR6;
|
case UE_ESP:
|
||||||
case UE_DR7: return Registers::R::DR7;
|
return Registers::R::ESP;
|
||||||
|
case UE_EIP:
|
||||||
|
return Registers::R::EIP;
|
||||||
|
case UE_EFLAGS:
|
||||||
|
return Registers::R::EFlags;
|
||||||
|
case UE_DR0:
|
||||||
|
return Registers::R::DR0;
|
||||||
|
case UE_DR1:
|
||||||
|
return Registers::R::DR1;
|
||||||
|
case UE_DR2:
|
||||||
|
return Registers::R::DR2;
|
||||||
|
case UE_DR3:
|
||||||
|
return Registers::R::DR3;
|
||||||
|
case UE_DR6:
|
||||||
|
return Registers::R::DR6;
|
||||||
|
case UE_DR7:
|
||||||
|
return Registers::R::DR7;
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
case UE_RAX: return Registers::R::RAX;
|
case UE_RAX:
|
||||||
case UE_RBX: return Registers::R::RBX;
|
return Registers::R::RAX;
|
||||||
case UE_RCX: return Registers::R::RCX;
|
case UE_RBX:
|
||||||
case UE_RDX: return Registers::R::RDX;
|
return Registers::R::RBX;
|
||||||
case UE_RDI: return Registers::R::RDI;
|
case UE_RCX:
|
||||||
case UE_RSI: return Registers::R::RSI;
|
return Registers::R::RCX;
|
||||||
case UE_RBP: return Registers::R::RBP;
|
case UE_RDX:
|
||||||
case UE_RSP: return Registers::R::RSP;
|
return Registers::R::RDX;
|
||||||
case UE_RIP: return Registers::R::RIP;
|
case UE_RDI:
|
||||||
case UE_RFLAGS: return Registers::R::EFlags;
|
return Registers::R::RDI;
|
||||||
case UE_R8: return Registers::R::R8;
|
case UE_RSI:
|
||||||
case UE_R9: return Registers::R::R9;
|
return Registers::R::RSI;
|
||||||
case UE_R10: return Registers::R::R10;
|
case UE_RBP:
|
||||||
case UE_R11: return Registers::R::R11;
|
return Registers::R::RBP;
|
||||||
case UE_R12: return Registers::R::R12;
|
case UE_RSP:
|
||||||
case UE_R13: return Registers::R::R13;
|
return Registers::R::RSP;
|
||||||
case UE_R14: return Registers::R::R14;
|
case UE_RIP:
|
||||||
case UE_R15: return Registers::R::R15;
|
return Registers::R::RIP;
|
||||||
|
case UE_RFLAGS:
|
||||||
|
return Registers::R::EFlags;
|
||||||
|
case UE_R8:
|
||||||
|
return Registers::R::R8;
|
||||||
|
case UE_R9:
|
||||||
|
return Registers::R::R9;
|
||||||
|
case UE_R10:
|
||||||
|
return Registers::R::R10;
|
||||||
|
case UE_R11:
|
||||||
|
return Registers::R::R11;
|
||||||
|
case UE_R12:
|
||||||
|
return Registers::R::R12;
|
||||||
|
case UE_R13:
|
||||||
|
return Registers::R::R13;
|
||||||
|
case UE_R14:
|
||||||
|
return Registers::R::R14;
|
||||||
|
case UE_R15:
|
||||||
|
return Registers::R::R15;
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
case UE_CIP: return Registers::R::GIP;
|
case UE_CIP:
|
||||||
case UE_CSP: return Registers::R::GSP;
|
return Registers::R::GIP;
|
||||||
case UE_SEG_GS: return Registers::R::GS;
|
case UE_CSP:
|
||||||
case UE_SEG_FS: return Registers::R::FS;
|
return Registers::R::GSP;
|
||||||
case UE_SEG_ES: return Registers::R::ES;
|
case UE_SEG_GS:
|
||||||
case UE_SEG_DS: return Registers::R::DS;
|
return Registers::R::GS;
|
||||||
case UE_SEG_CS: return Registers::R::CS;
|
case UE_SEG_FS:
|
||||||
case UE_SEG_SS: return Registers::R::SS;
|
return Registers::R::FS;
|
||||||
default: return Registers::R::Invalid;
|
case UE_SEG_ES:
|
||||||
|
return Registers::R::ES;
|
||||||
|
case UE_SEG_DS:
|
||||||
|
return Registers::R::DS;
|
||||||
|
case UE_SEG_CS:
|
||||||
|
return Registers::R::CS;
|
||||||
|
case UE_SEG_SS:
|
||||||
|
return Registers::R::SS;
|
||||||
|
default:
|
||||||
|
return Registers::R::Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1037,7 +1081,7 @@ private: //functions
|
||||||
|
|
||||||
static HardwareType hwtypeFromTitan(DWORD type)
|
static HardwareType hwtypeFromTitan(DWORD type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case UE_HARDWARE_EXECUTE:
|
case UE_HARDWARE_EXECUTE:
|
||||||
return HardwareType::Execute;
|
return HardwareType::Execute;
|
||||||
|
|
@ -1052,7 +1096,7 @@ private: //functions
|
||||||
|
|
||||||
static HardwareSize hwsizeFromTitan(DWORD size)
|
static HardwareSize hwsizeFromTitan(DWORD size)
|
||||||
{
|
{
|
||||||
switch (size)
|
switch(size)
|
||||||
{
|
{
|
||||||
case UE_HARDWARE_SIZE_1:
|
case UE_HARDWARE_SIZE_1:
|
||||||
return HardwareSize::SizeByte;
|
return HardwareSize::SizeByte;
|
||||||
|
|
@ -1071,7 +1115,7 @@ private: //functions
|
||||||
|
|
||||||
static MemoryType memtypeFromTitan(DWORD type)
|
static MemoryType memtypeFromTitan(DWORD type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case UE_MEMORY:
|
case UE_MEMORY:
|
||||||
return MemoryType::Access;
|
return MemoryType::Access;
|
||||||
|
|
@ -1209,18 +1253,18 @@ private: //functions
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
HRSRC hResource = FindResourceA(engineHandle, (LPCSTR)szResourceName, "BINARY");
|
HRSRC hResource = FindResourceA(engineHandle, (LPCSTR)szResourceName, "BINARY");
|
||||||
if (hResource != NULL)
|
if(hResource != NULL)
|
||||||
{
|
{
|
||||||
HGLOBAL hResourceGlobal = LoadResource(engineHandle, hResource);
|
HGLOBAL hResourceGlobal = LoadResource(engineHandle, hResource);
|
||||||
if (hResourceGlobal != NULL)
|
if(hResourceGlobal != NULL)
|
||||||
{
|
{
|
||||||
DWORD ResourceSize = SizeofResource(engineHandle, hResource);
|
DWORD ResourceSize = SizeofResource(engineHandle, hResource);
|
||||||
LPVOID ResourceData = LockResource(hResourceGlobal);
|
LPVOID ResourceData = LockResource(hResourceGlobal);
|
||||||
HANDLE hFile = CreateFileW(szExtractedFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
HANDLE hFile = CreateFileW(szExtractedFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (hFile != INVALID_HANDLE_VALUE)
|
if(hFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
DWORD NumberOfBytesWritten;
|
DWORD NumberOfBytesWritten;
|
||||||
if (WriteFile(hFile, ResourceData, ResourceSize, &NumberOfBytesWritten, NULL))
|
if(WriteFile(hFile, ResourceData, ResourceSize, &NumberOfBytesWritten, NULL))
|
||||||
result = true;
|
result = true;
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
}
|
}
|
||||||
|
|
@ -1232,7 +1276,7 @@ private: //functions
|
||||||
bool TryExtractDllLoader(bool failedBefore = false)
|
bool TryExtractDllLoader(bool failedBefore = false)
|
||||||
{
|
{
|
||||||
wchar_t* szPath = wcsrchr(szDebuggeeName, L'\\');
|
wchar_t* szPath = wcsrchr(szDebuggeeName, L'\\');
|
||||||
if (szPath)
|
if(szPath)
|
||||||
szPath[1] = '\0';
|
szPath[1] = '\0';
|
||||||
wchar_t DLLLoaderName[64] = L"";
|
wchar_t DLLLoaderName[64] = L"";
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
|
@ -1242,14 +1286,14 @@ private: //functions
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
wcscat_s(szDebuggeeName, DLLLoaderName);
|
wcscat_s(szDebuggeeName, DLLLoaderName);
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (EngineExtractResource("LOADERX64", szDebuggeeName))
|
if(EngineExtractResource("LOADERX64", szDebuggeeName))
|
||||||
#else
|
#else
|
||||||
if (EngineExtractResource("LOADERX86", szDebuggeeName))
|
if(EngineExtractResource("LOADERX86", szDebuggeeName))
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
return true;
|
return true;
|
||||||
return !failedBefore &&
|
return !failedBefore &&
|
||||||
GetModuleFileNameW(engineHandle, szDebuggeeName, _countof(szDebuggeeName)) &&
|
GetModuleFileNameW(engineHandle, szDebuggeeName, _countof(szDebuggeeName)) &&
|
||||||
TryExtractDllLoader(true);
|
TryExtractDllLoader(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private: //variables
|
private: //variables
|
||||||
|
|
|
||||||
|
|
@ -145,43 +145,43 @@ SETXSTATEFEATURESMASK _SetXStateFeaturesMask = NULL;
|
||||||
|
|
||||||
static bool SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
|
static bool SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
|
||||||
{
|
{
|
||||||
if (InitXState() == false)
|
if(InitXState() == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD64 FeatureMask = _GetEnabledXStateFeatures();
|
DWORD64 FeatureMask = _GetEnabledXStateFeatures();
|
||||||
if ((FeatureMask & XSTATE_MASK_AVX) == 0)
|
if((FeatureMask & XSTATE_MASK_AVX) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD ContextSize = 0;
|
DWORD ContextSize = 0;
|
||||||
BOOL Success = _InitializeContext(NULL,
|
BOOL Success = _InitializeContext(NULL,
|
||||||
CONTEXT_ALL | CONTEXT_XSTATE,
|
CONTEXT_ALL | CONTEXT_XSTATE,
|
||||||
NULL,
|
NULL,
|
||||||
&ContextSize);
|
&ContextSize);
|
||||||
|
|
||||||
if ((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
|
if((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<unsigned char> dataBuffer;
|
std::vector<unsigned char> dataBuffer;
|
||||||
dataBuffer.resize(ContextSize);
|
dataBuffer.resize(ContextSize);
|
||||||
PVOID Buffer = dataBuffer.data();
|
PVOID Buffer = dataBuffer.data();
|
||||||
if (Buffer == NULL)
|
if(Buffer == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PCONTEXT Context;
|
PCONTEXT Context;
|
||||||
Success = _InitializeContext(Buffer,
|
Success = _InitializeContext(Buffer,
|
||||||
CONTEXT_ALL | CONTEXT_XSTATE,
|
CONTEXT_ALL | CONTEXT_XSTATE,
|
||||||
&Context,
|
&Context,
|
||||||
&ContextSize);
|
&ContextSize);
|
||||||
if (Success == FALSE)
|
if(Success == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX) == FALSE)
|
if(_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (GetThreadContext(hActiveThread, Context) == FALSE)
|
if(GetThreadContext(hActiveThread, Context) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE)
|
if(_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD FeatureLength;
|
DWORD FeatureLength;
|
||||||
|
|
@ -189,15 +189,15 @@ static bool SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titconte
|
||||||
XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, NULL);
|
XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, NULL);
|
||||||
int NumberOfRegisters = FeatureLength / sizeof(Sse[0]);
|
int NumberOfRegisters = FeatureLength / sizeof(Sse[0]);
|
||||||
|
|
||||||
if (Sse != NULL) //If the feature is unsupported by the processor it will return NULL
|
if(Sse != NULL) //If the feature is unsupported by the processor it will return NULL
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumberOfRegisters; i++)
|
for(int i = 0; i < NumberOfRegisters; i++)
|
||||||
Sse[i] = titcontext->YmmRegisters[i].Low;
|
Sse[i] = titcontext->YmmRegisters[i].Low;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Avx != NULL) //If the feature is unsupported by the processor it will return NULL
|
if(Avx != NULL) //If the feature is unsupported by the processor it will return NULL
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumberOfRegisters; i++)
|
for(int i = 0; i < NumberOfRegisters; i++)
|
||||||
Avx[i] = titcontext->YmmRegisters[i].High;
|
Avx[i] = titcontext->YmmRegisters[i].High;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,43 +206,43 @@ static bool SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titconte
|
||||||
|
|
||||||
static bool GetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
|
static bool GetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
|
||||||
{
|
{
|
||||||
if (InitXState() == false)
|
if(InitXState() == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD64 FeatureMask = _GetEnabledXStateFeatures();
|
DWORD64 FeatureMask = _GetEnabledXStateFeatures();
|
||||||
if ((FeatureMask & XSTATE_MASK_AVX) == 0)
|
if((FeatureMask & XSTATE_MASK_AVX) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD ContextSize = 0;
|
DWORD ContextSize = 0;
|
||||||
BOOL Success = _InitializeContext(NULL,
|
BOOL Success = _InitializeContext(NULL,
|
||||||
CONTEXT_ALL | CONTEXT_XSTATE,
|
CONTEXT_ALL | CONTEXT_XSTATE,
|
||||||
NULL,
|
NULL,
|
||||||
&ContextSize);
|
&ContextSize);
|
||||||
|
|
||||||
if ((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
|
if((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<unsigned char> dataBuffer;
|
std::vector<unsigned char> dataBuffer;
|
||||||
dataBuffer.resize(ContextSize);
|
dataBuffer.resize(ContextSize);
|
||||||
PVOID Buffer = dataBuffer.data();
|
PVOID Buffer = dataBuffer.data();
|
||||||
if (Buffer == NULL)
|
if(Buffer == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PCONTEXT Context;
|
PCONTEXT Context;
|
||||||
Success = _InitializeContext(Buffer,
|
Success = _InitializeContext(Buffer,
|
||||||
CONTEXT_ALL | CONTEXT_XSTATE,
|
CONTEXT_ALL | CONTEXT_XSTATE,
|
||||||
&Context,
|
&Context,
|
||||||
&ContextSize);
|
&ContextSize);
|
||||||
if (Success == FALSE)
|
if(Success == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX) == FALSE)
|
if(_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (GetThreadContext(hActiveThread, Context) == FALSE)
|
if(GetThreadContext(hActiveThread, Context) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE)
|
if(_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD FeatureLength;
|
DWORD FeatureLength;
|
||||||
|
|
@ -250,15 +250,15 @@ static bool GetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titconte
|
||||||
XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, NULL);
|
XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, NULL);
|
||||||
int NumberOfRegisters = FeatureLength / sizeof(Sse[0]);
|
int NumberOfRegisters = FeatureLength / sizeof(Sse[0]);
|
||||||
|
|
||||||
if (Sse != NULL) //If the feature is unsupported by the processor it will return NULL
|
if(Sse != NULL) //If the feature is unsupported by the processor it will return NULL
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumberOfRegisters; i++)
|
for(int i = 0; i < NumberOfRegisters; i++)
|
||||||
titcontext->YmmRegisters[i].Low = Sse[i];
|
titcontext->YmmRegisters[i].Low = Sse[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Avx != NULL) //If the feature is unsupported by the processor it will return NULL
|
if(Avx != NULL) //If the feature is unsupported by the processor it will return NULL
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumberOfRegisters; i++)
|
for(int i = 0; i < NumberOfRegisters; i++)
|
||||||
titcontext->YmmRegisters[i].High = Avx[i];
|
titcontext->YmmRegisters[i].High = Avx[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,7 +272,7 @@ bool _SetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcont
|
||||||
|
|
||||||
DBGContext.ContextFlags = CONTEXT_ALL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
|
DBGContext.ContextFlags = CONTEXT_ALL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
|
||||||
|
|
||||||
if (!GetThreadContext(hActiveThread, &DBGContext))
|
if(!GetThreadContext(hActiveThread, &DBGContext))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DBGContext.EFlags = (DWORD)titcontext->eflags;
|
DBGContext.EFlags = (DWORD)titcontext->eflags;
|
||||||
|
|
@ -356,7 +356,7 @@ bool _SetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcont
|
||||||
|
|
||||||
bool returnf = !!SetThreadContext(hActiveThread, &DBGContext);
|
bool returnf = !!SetThreadContext(hActiveThread, &DBGContext);
|
||||||
|
|
||||||
if (AVX_PRIORITY)
|
if(AVX_PRIORITY)
|
||||||
SetAVXContext(hActiveThread, titcontext);
|
SetAVXContext(hActiveThread, titcontext);
|
||||||
|
|
||||||
return returnf;
|
return returnf;
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServiceP
|
||||||
{
|
{
|
||||||
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
|
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
|
||||||
DWORDLONG const dwlConditionMask = VerSetConditionMask(
|
DWORDLONG const dwlConditionMask = VerSetConditionMask(
|
||||||
VerSetConditionMask(
|
VerSetConditionMask(
|
||||||
VerSetConditionMask(
|
VerSetConditionMask(
|
||||||
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
|
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
|
||||||
VER_MINORVERSION, VER_GREATER_EQUAL),
|
VER_MINORVERSION, VER_GREATER_EQUAL),
|
||||||
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||||
|
|
||||||
osvi.dwMajorVersion = wMajorVersion;
|
osvi.dwMajorVersion = wMajorVersion;
|
||||||
osvi.dwMinorVersion = wMinorVersion;
|
osvi.dwMinorVersion = wMinorVersion;
|
||||||
|
|
@ -41,163 +41,163 @@ IsWindowsVistaOrGreater()
|
||||||
|
|
||||||
static int getHeapFlagsOffset(bool x64)
|
static int getHeapFlagsOffset(bool x64)
|
||||||
{
|
{
|
||||||
if (x64) //x64 offsets
|
if(x64) //x64 offsets
|
||||||
{
|
{
|
||||||
if (IsWindowsVistaOrGreater())
|
if(IsWindowsVistaOrGreater())
|
||||||
{
|
{
|
||||||
return 0x70;
|
return 0x70;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0x14;
|
return 0x14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //x86 offsets
|
else //x86 offsets
|
||||||
{
|
{
|
||||||
if (IsWindowsVistaOrGreater())
|
if(IsWindowsVistaOrGreater())
|
||||||
{
|
{
|
||||||
return 0x40;
|
return 0x40;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0x0C;
|
return 0x0C;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getHeapForceFlagsOffset(bool x64)
|
static int getHeapForceFlagsOffset(bool x64)
|
||||||
{
|
{
|
||||||
if (x64) //x64 offsets
|
if(x64) //x64 offsets
|
||||||
{
|
{
|
||||||
if (IsWindowsVistaOrGreater())
|
if(IsWindowsVistaOrGreater())
|
||||||
{
|
{
|
||||||
return 0x74;
|
return 0x74;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0x18;
|
return 0x18;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //x86 offsets
|
else //x86 offsets
|
||||||
{
|
{
|
||||||
if (IsWindowsVistaOrGreater())
|
if(IsWindowsVistaOrGreater())
|
||||||
{
|
{
|
||||||
return 0x44;
|
return 0x44;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0x10;
|
return 0x10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* GetPEBLocation_(HANDLE hProcess)
|
static void* GetPEBLocation_(HANDLE hProcess)
|
||||||
{
|
{
|
||||||
ULONG RequiredLen = 0;
|
ULONG RequiredLen = 0;
|
||||||
void* PebAddress = 0;
|
void* PebAddress = 0;
|
||||||
PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };
|
PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };
|
||||||
|
|
||||||
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == 0)
|
if(NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == 0)
|
||||||
{
|
{
|
||||||
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
|
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == 0)
|
if(NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == 0)
|
||||||
{
|
{
|
||||||
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
|
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PebAddress;
|
return PebAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool PebPatchHeapFlags(PEB_CURRENT* peb, HANDLE hProcess)
|
static bool PebPatchHeapFlags(PEB_CURRENT* peb, HANDLE hProcess)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
const auto is_x64 = true;
|
const auto is_x64 = true;
|
||||||
#else
|
#else
|
||||||
const auto is_x64 = false;
|
const auto is_x64 = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<PVOID> heaps;
|
std::vector<PVOID> heaps;
|
||||||
heaps.resize(peb->NumberOfHeaps);
|
heaps.resize(peb->NumberOfHeaps);
|
||||||
|
|
||||||
if (ReadProcessMemory(hProcess, (PVOID)peb->ProcessHeaps, (PVOID)heaps.data(), heaps.size() * sizeof(PVOID), nullptr) == FALSE)
|
if(ReadProcessMemory(hProcess, (PVOID)peb->ProcessHeaps, (PVOID)heaps.data(), heaps.size() * sizeof(PVOID), nullptr) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::basic_string<uint8_t> heap;
|
std::basic_string<uint8_t> heap;
|
||||||
heap.resize(0x100); // hacky
|
heap.resize(0x100); // hacky
|
||||||
for (DWORD i = 0; i < peb->NumberOfHeaps; i++)
|
for(DWORD i = 0; i < peb->NumberOfHeaps; i++)
|
||||||
{
|
{
|
||||||
if (ReadProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
|
if(ReadProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto flags = (DWORD *)(heap.data() + getHeapFlagsOffset(is_x64));
|
auto flags = (DWORD*)(heap.data() + getHeapFlagsOffset(is_x64));
|
||||||
auto force_flags = (DWORD *)(heap.data() + getHeapForceFlagsOffset(is_x64));
|
auto force_flags = (DWORD*)(heap.data() + getHeapForceFlagsOffset(is_x64));
|
||||||
|
|
||||||
if (i == 0)
|
if(i == 0)
|
||||||
{
|
{
|
||||||
// Default heap.
|
// Default heap.
|
||||||
*flags &= HEAP_GROWABLE;
|
*flags &= HEAP_GROWABLE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Flags from RtlCreateHeap/HeapCreate.
|
// Flags from RtlCreateHeap/HeapCreate.
|
||||||
*flags &= (HEAP_GROWABLE | HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_CREATE_ENABLE_EXECUTE);
|
*flags &= (HEAP_GROWABLE | HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_CREATE_ENABLE_EXECUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
*force_flags = 0;
|
*force_flags = 0;
|
||||||
|
|
||||||
if (WriteProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
|
if(WriteProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool FixPebInProcess(HANDLE hProcess)
|
static bool FixPebInProcess(HANDLE hProcess)
|
||||||
{
|
{
|
||||||
PEB_CURRENT myPEB = { 0 };
|
PEB_CURRENT myPEB = { 0 };
|
||||||
SIZE_T ueNumberOfBytesRead = 0;
|
SIZE_T ueNumberOfBytesRead = 0;
|
||||||
void* heapFlagsAddress = 0;
|
void* heapFlagsAddress = 0;
|
||||||
DWORD heapFlags = 0;
|
DWORD heapFlags = 0;
|
||||||
void* heapForceFlagsAddress = 0;
|
void* heapForceFlagsAddress = 0;
|
||||||
DWORD heapForceFlags = 0;
|
DWORD heapForceFlags = 0;
|
||||||
|
|
||||||
void* AddressOfPEB = GetPEBLocation(hProcess);
|
void* AddressOfPEB = GetPEBLocation(hProcess);
|
||||||
|
|
||||||
if (!AddressOfPEB)
|
if(!AddressOfPEB)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ReadProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
|
if(ReadProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
|
||||||
{
|
{
|
||||||
myPEB.BeingDebugged = FALSE;
|
myPEB.BeingDebugged = FALSE;
|
||||||
myPEB.NtGlobalFlag &= ~0x70;
|
myPEB.NtGlobalFlag &= ~0x70;
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(true));
|
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(true));
|
||||||
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(true));
|
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(true));
|
||||||
#else
|
#else
|
||||||
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(false));
|
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(false));
|
||||||
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(false));
|
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(false));
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
|
|
||||||
ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
|
ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
|
||||||
ReadProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
|
ReadProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
|
||||||
|
|
||||||
heapFlags &= HEAP_GROWABLE;
|
heapFlags &= HEAP_GROWABLE;
|
||||||
heapForceFlags = 0;
|
heapForceFlags = 0;
|
||||||
|
|
||||||
WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
|
WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
|
||||||
WriteProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
|
WriteProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
|
||||||
|
|
||||||
PebPatchHeapFlags(&myPEB, hProcess);
|
PebPatchHeapFlags(&myPEB, hProcess);
|
||||||
|
|
||||||
if (WriteProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
|
if(WriteProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -23,12 +23,12 @@ static HANDLE WINAPI ProcessIdToHandle(IN DWORD dwProcessId)
|
||||||
ClientId.UniqueProcess = UlongToHandle(dwProcessId);
|
ClientId.UniqueProcess = UlongToHandle(dwProcessId);
|
||||||
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
|
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
|
||||||
Status = NtOpenProcess(&Handle,
|
Status = NtOpenProcess(&Handle,
|
||||||
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
|
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
|
||||||
PROCESS_VM_WRITE | PROCESS_VM_READ |
|
PROCESS_VM_WRITE | PROCESS_VM_READ |
|
||||||
PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION,
|
PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION,
|
||||||
&ObjectAttributes,
|
&ObjectAttributes,
|
||||||
&ClientId);
|
&ClientId);
|
||||||
if (!NT_SUCCESS(Status))
|
if(!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* Fail */
|
/* Fail */
|
||||||
BaseSetLastNTError(Status);
|
BaseSetLastNTError(Status);
|
||||||
|
|
@ -51,7 +51,7 @@ static NTSTATUS CreateThreadSkipAttach(IN HANDLE ProcessHandle, IN PUSER_THREAD_
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
|
|
||||||
typedef NTSTATUS(NTAPI *t_NtCreateThreadEx)(
|
typedef NTSTATUS(NTAPI * t_NtCreateThreadEx)(
|
||||||
PHANDLE /* ThreadHandle */,
|
PHANDLE /* ThreadHandle */,
|
||||||
ACCESS_MASK /* DesiredAccess */,
|
ACCESS_MASK /* DesiredAccess */,
|
||||||
POBJECT_ATTRIBUTES /* ObjectAttributes */,
|
POBJECT_ATTRIBUTES /* ObjectAttributes */,
|
||||||
|
|
@ -63,40 +63,40 @@ static NTSTATUS CreateThreadSkipAttach(IN HANDLE ProcessHandle, IN PUSER_THREAD_
|
||||||
SIZE_T /* StackSize */,
|
SIZE_T /* StackSize */,
|
||||||
SIZE_T /* MaximumStackSize */,
|
SIZE_T /* MaximumStackSize */,
|
||||||
PPS_ATTRIBUTE_LIST /* AttributeList */
|
PPS_ATTRIBUTE_LIST /* AttributeList */
|
||||||
);
|
);
|
||||||
|
|
||||||
auto p_NtCreateThreadEx = (t_NtCreateThreadEx)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtCreateThreadEx");
|
auto p_NtCreateThreadEx = (t_NtCreateThreadEx)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtCreateThreadEx");
|
||||||
if (p_NtCreateThreadEx)
|
if(p_NtCreateThreadEx)
|
||||||
{
|
{
|
||||||
// Based on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/339263/16/client/crashpad_client_win.cc#697
|
// Based on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/339263/16/client/crashpad_client_win.cc#697
|
||||||
Status = p_NtCreateThreadEx(&hThread,
|
Status = p_NtCreateThreadEx(&hThread,
|
||||||
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
|
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
|
||||||
nullptr,
|
nullptr,
|
||||||
ProcessHandle,
|
ProcessHandle,
|
||||||
StartRoutine,
|
StartRoutine,
|
||||||
Argument,
|
Argument,
|
||||||
THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH,
|
THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH,
|
||||||
0,
|
0,
|
||||||
0x4000 /* PAGE_SIZE * 4 */,
|
0x4000 /* PAGE_SIZE * 4 */,
|
||||||
0x4000,
|
0x4000,
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CLIENT_ID ClientId;
|
CLIENT_ID ClientId;
|
||||||
Status = RtlCreateUserThread(ProcessHandle,
|
Status = RtlCreateUserThread(ProcessHandle,
|
||||||
NULL,
|
NULL,
|
||||||
FALSE,
|
FALSE,
|
||||||
0,
|
0,
|
||||||
0x4000,
|
0x4000,
|
||||||
0x4000 /* PAGE_SIZE * 4 */,
|
0x4000 /* PAGE_SIZE * 4 */,
|
||||||
StartRoutine,
|
StartRoutine,
|
||||||
Argument,
|
Argument,
|
||||||
&hThread,
|
&hThread,
|
||||||
&ClientId);
|
&ClientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NT_SUCCESS(Status))
|
if(NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
NtClose(hThread);
|
NtClose(hThread);
|
||||||
}
|
}
|
||||||
|
|
@ -108,11 +108,11 @@ static NTSTATUS NTAPI DbgUiIssueRemoteBreakin_(IN HANDLE Process)
|
||||||
{
|
{
|
||||||
PUSER_THREAD_START_ROUTINE RemoteBreakFunction = (PUSER_THREAD_START_ROUTINE)DbgUiRemoteBreakin;
|
PUSER_THREAD_START_ROUTINE RemoteBreakFunction = (PUSER_THREAD_START_ROUTINE)DbgUiRemoteBreakin;
|
||||||
LPVOID RemoteMemory = VirtualAllocEx(Process, 0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READ);
|
LPVOID RemoteMemory = VirtualAllocEx(Process, 0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READ);
|
||||||
if (RemoteMemory)
|
if(RemoteMemory)
|
||||||
{
|
{
|
||||||
SIZE_T written = 0;
|
SIZE_T written = 0;
|
||||||
unsigned char payload[] = { 0xCC, 0xC3 };
|
unsigned char payload[] = { 0xCC, 0xC3 };
|
||||||
if (WriteProcessMemory(Process, RemoteMemory, payload, sizeof(payload), &written))
|
if(WriteProcessMemory(Process, RemoteMemory, payload, sizeof(payload), &written))
|
||||||
{
|
{
|
||||||
RemoteBreakFunction = (PUSER_THREAD_START_ROUTINE)RemoteMemory;
|
RemoteBreakFunction = (PUSER_THREAD_START_ROUTINE)RemoteMemory;
|
||||||
}
|
}
|
||||||
|
|
@ -133,11 +133,11 @@ static NTSTATUS NTAPI DbgUiDebugActiveProcess_(IN HANDLE Process)
|
||||||
return Status;
|
return Status;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (NT_SUCCESS(Status))
|
if(NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* Now break-in the process */
|
/* Now break-in the process */
|
||||||
Status = DbgUiIssueRemoteBreakin_(Process);
|
Status = DbgUiIssueRemoteBreakin_(Process);
|
||||||
if (!NT_SUCCESS(Status))
|
if(!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* We couldn't break-in, cancel debugging */
|
/* We couldn't break-in, cancel debugging */
|
||||||
DbgUiStopDebugging(Process);
|
DbgUiStopDebugging(Process);
|
||||||
|
|
@ -151,7 +151,7 @@ static NTSTATUS NTAPI DbgUiDebugActiveProcess_(IN HANDLE Process)
|
||||||
|
|
||||||
static NTSTATUS NTAPI DbgUiConnectToDbg_()
|
static NTSTATUS NTAPI DbgUiConnectToDbg_()
|
||||||
{
|
{
|
||||||
if (NtCurrentTeb()->DbgSsReserved[1] != NULL)
|
if(NtCurrentTeb()->DbgSsReserved[1] != NULL)
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
|
@ -164,7 +164,7 @@ BOOL WINAPI DebugActiveProcess_(IN DWORD dwProcessId)
|
||||||
{
|
{
|
||||||
/* Connect to the debugger */
|
/* Connect to the debugger */
|
||||||
NTSTATUS Status = DbgUiConnectToDbg_();
|
NTSTATUS Status = DbgUiConnectToDbg_();
|
||||||
if (!NT_SUCCESS(Status))
|
if(!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
BaseSetLastNTError(Status);
|
BaseSetLastNTError(Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -172,7 +172,7 @@ BOOL WINAPI DebugActiveProcess_(IN DWORD dwProcessId)
|
||||||
|
|
||||||
/* Get the process handle */
|
/* Get the process handle */
|
||||||
HANDLE Handle = ProcessIdToHandle(dwProcessId);
|
HANDLE Handle = ProcessIdToHandle(dwProcessId);
|
||||||
if (!Handle)
|
if(!Handle)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +184,7 @@ BOOL WINAPI DebugActiveProcess_(IN DWORD dwProcessId)
|
||||||
NtClose(Handle);
|
NtClose(Handle);
|
||||||
|
|
||||||
/* Check if debugging worked */
|
/* Check if debugging worked */
|
||||||
if (!NT_SUCCESS(Status))
|
if(!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* Fail */
|
/* Fail */
|
||||||
BaseSetLastNTError(Status);
|
BaseSetLastNTError(Status);
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,7 @@ BOOL WINAPI DllMain(
|
||||||
_In_ LPVOID lpvReserved
|
_In_ LPVOID lpvReserved
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
if(fdwReason == DLL_PROCESS_ATTACH)
|
||||||
emu.engineHandle = hinstDLL;
|
emu.engineHandle = hinstDLL;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
||||||
#ifdef APSTUDIO_INVOKED
|
#ifdef APSTUDIO_INVOKED
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 106
|
#define _APS_NEXT_RESOURCE_VALUE 106
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,16 @@
|
||||||
#else
|
#else
|
||||||
# ifndef ZYDIS_EXPORT
|
# ifndef ZYDIS_EXPORT
|
||||||
# ifdef Zydis_EXPORTS
|
# ifdef Zydis_EXPORTS
|
||||||
/* We are building this library */
|
/* We are building this library */
|
||||||
# define ZYDIS_EXPORT
|
# define ZYDIS_EXPORT
|
||||||
# else
|
# else
|
||||||
/* We are using this library */
|
/* We are using this library */
|
||||||
# define ZYDIS_EXPORT
|
# define ZYDIS_EXPORT
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifndef ZYDIS_NO_EXPORT
|
# ifndef ZYDIS_NO_EXPORT
|
||||||
# define ZYDIS_NO_EXPORT
|
# define ZYDIS_NO_EXPORT
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue