mirror of https://github.com/x64dbg/GleeBug
commit
69be313fac
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);
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -240,47 +240,46 @@ namespace GleeBug
|
||||||
//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;
|
if(bpxPage == mProcess->memoryBreakpointPages.end())
|
||||||
auto pageProperties = bpxPage->second;
|
|
||||||
|
|
||||||
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);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto pageAddr = bpxPage->first;
|
||||||
|
auto pageProperties = bpxPage->second;
|
||||||
|
|
||||||
//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,7 +295,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +313,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 +322,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);
|
||||||
|
|
@ -345,14 +344,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 +370,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 +383,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);
|
||||||
|
|
@ -400,7 +399,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 +416,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);
|
||||||
|
|
@ -432,7 +431,7 @@ namespace GleeBug
|
||||||
//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 +448,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 +469,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 +478,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);
|
||||||
|
|
@ -501,14 +500,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 +525,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 +542,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,48 +369,48 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//delete the breakpoint from the maps
|
//delete the breakpoint from the maps
|
||||||
breakpoints.erase(found);
|
breakpoints.erase(found);
|
||||||
breakpointCallbacks.erase({ BreakpointType::Hardware, address });
|
breakpointCallbacks.erase({ BreakpointType::Memory, address });
|
||||||
memoryBreakpointRanges.erase(Range(address, address));
|
memoryBreakpointRanges.erase(Range(address, address));
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ namespace GleeBug
|
||||||
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.
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -7,10 +7,10 @@
|
||||||
#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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
@echo off
|
||||||
|
AStyleHelper\AStyleHelper.exe Silent
|
||||||
Loading…
Reference in New Issue