mirror of https://github.com/x64dbg/TitanEngine
998 lines
39 KiB
C++
998 lines
39 KiB
C++
#include "stdafx.h"
|
|
#include "definitions.h"
|
|
#include "Global.Breakpoints.h"
|
|
#include "Global.Debugger.h"
|
|
#include "Global.Engine.h"
|
|
#include "Global.Engine.Threading.h"
|
|
#include "Global.Engine.Importer.h"
|
|
#include "Global.Threader.h"
|
|
|
|
static long engineDefaultBreakPointType = UE_BREAKPOINT_INT3;
|
|
static BYTE UD2BreakPoint[2] = {0x0F, 0x0B};
|
|
static BYTE INT3BreakPoint = 0xCC;
|
|
static BYTE INT3LongBreakPoint[2] = {0xCD, 0x03};
|
|
|
|
__declspec(dllexport) void TITCALL SetBPXOptions(long DefaultBreakPointType)
|
|
{
|
|
if(DefaultBreakPointType == UE_BREAKPOINT_INT3 || DefaultBreakPointType == UE_BREAKPOINT_LONG_INT3 || DefaultBreakPointType == UE_BREAKPOINT_UD2)
|
|
engineDefaultBreakPointType = DefaultBreakPointType;
|
|
else if(DefaultBreakPointType == UE_BREAKPOINT_TYPE_INT3)
|
|
engineDefaultBreakPointType = UE_BREAKPOINT_INT3;
|
|
else if(DefaultBreakPointType == UE_BREAKPOINT_TYPE_LONG_INT3)
|
|
engineDefaultBreakPointType = UE_BREAKPOINT_LONG_INT3;
|
|
else if(DefaultBreakPointType == UE_BREAKPOINT_TYPE_UD2)
|
|
engineDefaultBreakPointType = UE_BREAKPOINT_UD2;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL IsBPXEnabled(ULONG_PTR bpxAddress)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
ULONG_PTR NumberOfBytesReadWritten = 0;
|
|
DWORD MaximumBreakPoints = 0;
|
|
BYTE ReadData[10] = {};
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
const bool isSoftwareBpx = BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT || BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT;
|
|
if(isSoftwareBpx && BreakPointBuffer.at(i).BreakPointAddress == bpxAddress)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointActive != UE_BPXINACTIVE)
|
|
{
|
|
if(ReadProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &ReadData[0], UE_MAX_BREAKPOINT_SIZE, &NumberOfBytesReadWritten))
|
|
{
|
|
if(BreakPointBuffer.at(i).AdvancedBreakPointType == UE_BREAKPOINT_INT3 && ReadData[0] == INT3BreakPoint)
|
|
return true;
|
|
else if(BreakPointBuffer.at(i).AdvancedBreakPointType == UE_BREAKPOINT_LONG_INT3 && ReadData[0] == INT3LongBreakPoint[0] && ReadData[1] == INT3LongBreakPoint[1])
|
|
return true;
|
|
else if(BreakPointBuffer.at(i).AdvancedBreakPointType == UE_BREAKPOINT_UD2 && ReadData[0] == UD2BreakPoint[0] && ReadData[1] == UD2BreakPoint[1])
|
|
return true;
|
|
else //TODO: delete breakpoint from list?
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL EnableBPX(ULONG_PTR bpxAddress)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
MEMORY_BASIC_INFORMATION MemInfo;
|
|
ULONG_PTR NumberOfBytesReadWritten = 0;
|
|
DWORD MaximumBreakPoints = 0;
|
|
bool testWrite = false;
|
|
DWORD OldProtect;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointAddress == bpxAddress)
|
|
{
|
|
VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION);
|
|
OldProtect = MemInfo.Protect;
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
if(BreakPointBuffer.at(i).BreakPointActive == UE_BPXINACTIVE && (BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT))
|
|
{
|
|
//re-read original byte(s)
|
|
if(ReadProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).OriginalByte, BreakPointBuffer.at(i).BreakPointSize, 0))
|
|
{
|
|
if(BreakPointBuffer.at(i).AdvancedBreakPointType == UE_BREAKPOINT_INT3)
|
|
{
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &INT3BreakPoint, 1, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
testWrite = true;
|
|
}
|
|
}
|
|
else if(BreakPointBuffer.at(i).AdvancedBreakPointType == UE_BREAKPOINT_LONG_INT3)
|
|
{
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &INT3LongBreakPoint, 2, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
testWrite = true;
|
|
}
|
|
}
|
|
else if(BreakPointBuffer.at(i).AdvancedBreakPointType == UE_BREAKPOINT_UD2)
|
|
{
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &UD2BreakPoint, 2, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
testWrite = true;
|
|
}
|
|
}
|
|
if(testWrite)
|
|
{
|
|
BreakPointBuffer.at(i).BreakPointActive = UE_BPXACTIVE;
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL DisableBPX(ULONG_PTR bpxAddress)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
MEMORY_BASIC_INFORMATION MemInfo;
|
|
ULONG_PTR NumberOfBytesReadWritten = 0;
|
|
DWORD MaximumBreakPoints = 0;
|
|
DWORD OldProtect;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointAddress == bpxAddress)
|
|
{
|
|
VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION);
|
|
OldProtect = MemInfo.Protect;
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
if(BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE && (BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT))
|
|
{
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &BreakPointBuffer.at(i).OriginalByte[0], BreakPointBuffer.at(i).BreakPointSize, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
BreakPointBuffer.at(i).BreakPointActive = UE_BPXINACTIVE;
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(i).BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SetBPX(ULONG_PTR bpxAddress, DWORD bpxType, LPVOID bpxCallBack)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
void* bpxDataPrt;
|
|
PMEMORY_COMPARE_HANDLER bpxDataCmpPtr;
|
|
ULONG_PTR NumberOfBytesReadWritten = 0;
|
|
BYTE SelectedBreakPointType;
|
|
DWORD checkBpxType;
|
|
DWORD OldProtect;
|
|
|
|
if(bpxCallBack == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
//search for breakpoint
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointAddress == bpxAddress && BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE && (BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT || BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT))
|
|
return false;
|
|
else if(BreakPointBuffer.at(i).BreakPointAddress == bpxAddress && BreakPointBuffer.at(i).BreakPointActive == UE_BPXINACTIVE && (BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT || BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT))
|
|
{
|
|
lock.unlock();
|
|
return EnableBPX(bpxAddress);
|
|
}
|
|
}
|
|
//setup new breakpoint structure
|
|
BreakPointDetail NewBreakPoint;
|
|
memset(&NewBreakPoint, 0, sizeof(BreakPointDetail));
|
|
if(bpxType < UE_BREAKPOINT_TYPE_INT3)
|
|
{
|
|
if(engineDefaultBreakPointType == UE_BREAKPOINT_LONG_INT3)
|
|
{
|
|
SelectedBreakPointType = UE_BREAKPOINT_LONG_INT3;
|
|
NewBreakPoint.BreakPointSize = 2;
|
|
bpxDataPrt = &INT3LongBreakPoint;
|
|
}
|
|
else if(engineDefaultBreakPointType == UE_BREAKPOINT_UD2)
|
|
{
|
|
SelectedBreakPointType = UE_BREAKPOINT_UD2;
|
|
NewBreakPoint.BreakPointSize = 2;
|
|
bpxDataPrt = &UD2BreakPoint;
|
|
}
|
|
else //default
|
|
{
|
|
SelectedBreakPointType = UE_BREAKPOINT_INT3;
|
|
NewBreakPoint.BreakPointSize = 1;
|
|
bpxDataPrt = &INT3BreakPoint;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
checkBpxType = bpxType >> 24;
|
|
checkBpxType = checkBpxType << 24;
|
|
if(checkBpxType == UE_BREAKPOINT_TYPE_INT3)
|
|
{
|
|
SelectedBreakPointType = UE_BREAKPOINT_INT3;
|
|
NewBreakPoint.BreakPointSize = 1;
|
|
bpxDataPrt = &INT3BreakPoint;
|
|
}
|
|
else if(checkBpxType == UE_BREAKPOINT_TYPE_LONG_INT3)
|
|
{
|
|
SelectedBreakPointType = UE_BREAKPOINT_LONG_INT3;
|
|
NewBreakPoint.BreakPointSize = 2;
|
|
bpxDataPrt = &INT3LongBreakPoint;
|
|
}
|
|
else if(checkBpxType == UE_BREAKPOINT_TYPE_UD2)
|
|
{
|
|
SelectedBreakPointType = UE_BREAKPOINT_UD2;
|
|
NewBreakPoint.BreakPointSize = 2;
|
|
bpxDataPrt = &UD2BreakPoint;
|
|
}
|
|
}
|
|
//set breakpoint in process
|
|
bpxDataCmpPtr = (PMEMORY_COMPARE_HANDLER)bpxDataPrt;
|
|
if(!VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, NewBreakPoint.BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect))
|
|
return false;
|
|
if(ReadProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &NewBreakPoint.OriginalByte[0], NewBreakPoint.BreakPointSize, &NumberOfBytesReadWritten))
|
|
{
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, bpxDataPrt, NewBreakPoint.BreakPointSize, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
//add new breakpoint to the list
|
|
NewBreakPoint.AdvancedBreakPointType = SelectedBreakPointType & 0xFF;
|
|
NewBreakPoint.BreakPointActive = UE_BPXACTIVE;
|
|
NewBreakPoint.BreakPointAddress = bpxAddress;
|
|
NewBreakPoint.BreakPointType = bpxType & 0xFF;
|
|
NewBreakPoint.ExecuteCallBack = (ULONG_PTR)bpxCallBack;
|
|
BreakPointBuffer.push_back(NewBreakPoint);
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, NewBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, NewBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, NewBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL DeleteBPX(ULONG_PTR bpxAddress)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
ULONG_PTR NumberOfBytesReadWritten = 0;
|
|
DWORD OldProtect;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
int found = -1;
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointAddress == bpxAddress && (BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT || BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT))
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
if(found == -1) //not found
|
|
return false;
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(found).BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
if(IsBPXEnabled(bpxAddress))
|
|
{
|
|
if(!WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &BreakPointBuffer.at(found).OriginalByte[0], BreakPointBuffer.at(found).BreakPointSize, &NumberOfBytesReadWritten))
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(found).BreakPointSize, OldProtect, &OldProtect);
|
|
return false;
|
|
}
|
|
}
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer.at(found).BreakPointSize, OldProtect, &OldProtect);
|
|
BreakPointBuffer.erase(BreakPointBuffer.begin() + found);
|
|
return true;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SafeDeleteBPX(ULONG_PTR bpxAddress)
|
|
{
|
|
//TODO: remove?
|
|
return DeleteBPX(bpxAddress);
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SetAPIBreakPoint(const char* szDLLName, const char* szAPIName, DWORD bpxType, DWORD bpxPlace, LPVOID bpxCallBack)
|
|
{
|
|
ULONG_PTR APIAddress = NULL;
|
|
if(szDLLName && szAPIName)
|
|
{
|
|
APIAddress = EngineGetProcAddressRemote(0, szDLLName, szAPIName); //get remote proc address
|
|
if(APIAddress)
|
|
{
|
|
if(bpxPlace == UE_APIEND)
|
|
{
|
|
int i = 0;
|
|
int len = 0;
|
|
unsigned char CmdBuffer[MAXIMUM_INSTRUCTION_SIZE];
|
|
if(!_stricmp(szDLLName, "kernel32.dll"))
|
|
{
|
|
ULONG_PTR APIAddress_ = EngineGetProcAddressRemote(0, "kernelbase.dll", szAPIName);
|
|
if(APIAddress_)
|
|
{
|
|
bool KernelBase = true;
|
|
do //search for forwarding indicators
|
|
{
|
|
i += len;
|
|
if(!MemoryReadSafe(dbgProcessInformation.hProcess, (void*)(APIAddress + i), CmdBuffer, sizeof(CmdBuffer), 0))
|
|
return false;
|
|
if(CmdBuffer[0] == 0xCC || CmdBuffer[0] == 0x90) //padding
|
|
{
|
|
KernelBase = false; //failed to find forward indicator
|
|
break;
|
|
}
|
|
len = StaticLengthDisassemble(CmdBuffer);
|
|
}
|
|
#ifdef _WIN64
|
|
while(!(CmdBuffer[0] == 0x48 && CmdBuffer[1] == 0xFF && CmdBuffer[2] == 0x25));
|
|
#else
|
|
while(!(CmdBuffer[0] == 0xFF && CmdBuffer[1] == 0x25));
|
|
#endif //_WIN64
|
|
if(KernelBase)
|
|
APIAddress = APIAddress_;
|
|
i = 0;
|
|
len = 0;
|
|
}
|
|
}
|
|
do //search for RET
|
|
{
|
|
i += len;
|
|
if(!MemoryReadSafe(dbgProcessInformation.hProcess, (void*)(APIAddress + i), CmdBuffer, sizeof(CmdBuffer), 0))
|
|
return false;
|
|
len = StaticLengthDisassemble(CmdBuffer);
|
|
}
|
|
while(CmdBuffer[0] != 0xC3 && CmdBuffer[0] != 0xC2);
|
|
APIAddress += i;
|
|
}
|
|
return SetBPX(APIAddress, bpxType, bpxCallBack);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL DeleteAPIBreakPoint(const char* szDLLName, const char* szAPIName, DWORD bpxPlace)
|
|
{
|
|
ULONG_PTR APIAddress = NULL;
|
|
if(szDLLName && szAPIName)
|
|
{
|
|
APIAddress = EngineGetProcAddressRemote(0, szDLLName, szAPIName); //get remote proc address
|
|
if(APIAddress)
|
|
{
|
|
if(bpxPlace == UE_APIEND)
|
|
{
|
|
int i = 0;
|
|
int len = 0;
|
|
unsigned char CmdBuffer[MAXIMUM_INSTRUCTION_SIZE];
|
|
if(!_stricmp(szDLLName, "kernel32.dll"))
|
|
{
|
|
ULONG_PTR APIAddress_ = EngineGetProcAddressRemote(0, "kernelbase.dll", szAPIName);
|
|
if(APIAddress_)
|
|
{
|
|
bool KernelBase = true;
|
|
do //search for forwarding indicators
|
|
{
|
|
i += len;
|
|
if(!MemoryReadSafe(dbgProcessInformation.hProcess, (void*)(APIAddress + i), CmdBuffer, sizeof(CmdBuffer), 0))
|
|
return false;
|
|
if(CmdBuffer[0] == 0xCC || CmdBuffer[0] == 0x90) //padding
|
|
{
|
|
KernelBase = false; //failed to find forward indicator
|
|
break;
|
|
}
|
|
len = StaticLengthDisassemble(CmdBuffer);
|
|
}
|
|
#ifdef _WIN64
|
|
while(!(CmdBuffer[0] == 0x48 && CmdBuffer[1] == 0xFF && CmdBuffer[2] == 0x25));
|
|
#else
|
|
while(!(CmdBuffer[0] == 0xFF && CmdBuffer[1] == 0x25));
|
|
#endif //_WIN64
|
|
if(KernelBase)
|
|
APIAddress = APIAddress_;
|
|
i = 0;
|
|
len = 0;
|
|
}
|
|
}
|
|
do //search for RET
|
|
{
|
|
i += len;
|
|
if(!MemoryReadSafe(dbgProcessInformation.hProcess, (void*)(APIAddress + i), CmdBuffer, sizeof(CmdBuffer), 0))
|
|
return false;
|
|
len = StaticLengthDisassemble(CmdBuffer);
|
|
}
|
|
while(CmdBuffer[0] != 0xC3 && CmdBuffer[0] != 0xC2);
|
|
APIAddress += i;
|
|
}
|
|
return DeleteBPX(APIAddress);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SafeDeleteAPIBreakPoint(const char* szDLLName, const char* szAPIName, DWORD bpxPlace)
|
|
{
|
|
//TODO: remove?
|
|
return DeleteAPIBreakPoint(szDLLName, szAPIName, bpxPlace);
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SetMemoryBPX(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory, LPVOID bpxCallBack)
|
|
{
|
|
return SetMemoryBPXEx(MemoryStart, SizeOfMemory, UE_MEMORY, false, bpxCallBack);
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SetMemoryBPXEx(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory, DWORD BreakPointType, bool RestoreOnHit, LPVOID bpxCallBack)
|
|
{
|
|
struct TempMemoryBreakpointDetails
|
|
{
|
|
ULONG_PTR addr;
|
|
DWORD currentPageProtect;
|
|
MemoryBreakpointPageDetail data;
|
|
};
|
|
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
bool isSuccess = true;
|
|
DWORD oldProtect;
|
|
|
|
// Note: memory breakpoints cannot intersect.
|
|
// Check that there are no other MemBPs in the address range [MemoryStart, MemoryStart+SizeOfMemory)
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
auto bpAddr = BreakPointBuffer.at(i).BreakPointAddress;
|
|
auto bpSize = BreakPointBuffer.at(i).BreakPointSize;
|
|
auto bpType = BreakPointBuffer.at(i).BreakPointType;
|
|
bool isMem = bpType == UE_MEMORY || bpType == UE_MEMORY_READ || bpType == UE_MEMORY_WRITE || bpType == UE_MEMORY_EXECUTE;
|
|
|
|
if (isMem && bpAddr < (MemoryStart + SizeOfMemory) && bpAddr + bpSize > MemoryStart)
|
|
{
|
|
return false; // the place is taken
|
|
}
|
|
}
|
|
|
|
// Set a proper protection (e.g. PAGE_GUARD) for all pages in the range
|
|
std::vector<TempMemoryBreakpointDetails> breakpointInfos;
|
|
MemoryBreakpointPageDetail pageData;
|
|
|
|
auto pageStart = ALIGN_DOWN_BY(MemoryStart, TITANENGINE_PAGESIZE);
|
|
auto pageEnd = ALIGN_UP_BY(MemoryStart + SizeOfMemory, TITANENGINE_PAGESIZE);
|
|
for(ULONG_PTR page = pageStart; page < pageEnd; page += TITANENGINE_PAGESIZE)
|
|
{
|
|
// Save the current page protection in case of a failure
|
|
MEMORY_BASIC_INFORMATION memInfo;
|
|
if(!VirtualQueryEx(dbgProcessInformation.hProcess, (LPCVOID)page, &memInfo, sizeof(memInfo)))
|
|
{
|
|
isSuccess = false;
|
|
break;
|
|
}
|
|
|
|
// Update page data and increment a BP counter
|
|
auto found = MemoryBreakpointPages.find(page);
|
|
if(found == MemoryBreakpointPages.end())
|
|
{
|
|
// It's the first memory BP on this page
|
|
pageData.origProtect = memInfo.Protect;
|
|
pageData.accessBps = pageData.readBps = pageData.writeBps = pageData.executeBps = 0;
|
|
}
|
|
else
|
|
{
|
|
// There are other memory BPs on this page
|
|
pageData = found->second; // original protection stays the same
|
|
}
|
|
|
|
switch(BreakPointType)
|
|
{
|
|
case UE_MEMORY: // READ + WRITE + EXECUTE
|
|
pageData.accessBps += 1;
|
|
break;
|
|
case UE_MEMORY_READ:
|
|
pageData.readBps += 1;
|
|
break;
|
|
case UE_MEMORY_WRITE:
|
|
pageData.writeBps += 1;
|
|
break;
|
|
case UE_MEMORY_EXECUTE:
|
|
pageData.executeBps += 1;
|
|
break;
|
|
default: // unreachable
|
|
break;
|
|
}
|
|
|
|
// Get a proper MemBp page protection option and apply it
|
|
pageData.newProtect = GetPageProtectionForMemoryBreakpoint(pageData);
|
|
if(!VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)page, TITANENGINE_PAGESIZE, pageData.newProtect, &oldProtect))
|
|
{
|
|
isSuccess = false;
|
|
break;
|
|
}
|
|
|
|
TempMemoryBreakpointDetails tempInfo;
|
|
tempInfo.addr = page;
|
|
tempInfo.currentPageProtect = memInfo.Protect;
|
|
tempInfo.data = pageData;
|
|
breakpointInfos.push_back(tempInfo);
|
|
}
|
|
|
|
// If changing the page protections failed, attempt to revert the applied protections back
|
|
if(!isSuccess)
|
|
{
|
|
for(const auto & page : breakpointInfos)
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)page.addr, TITANENGINE_PAGESIZE, page.currentPageProtect, &oldProtect);
|
|
return false;
|
|
}
|
|
|
|
// Save the page data
|
|
for(const auto & page : breakpointInfos)
|
|
MemoryBreakpointPages[page.addr] = page.data;
|
|
|
|
// Add a new breakpoint
|
|
BreakPointDetail NewBreakPoint;
|
|
memset(&NewBreakPoint, 0, sizeof(BreakPointDetail));
|
|
NewBreakPoint.BreakPointActive = UE_BPXACTIVE;
|
|
NewBreakPoint.BreakPointAddress = MemoryStart;
|
|
NewBreakPoint.BreakPointSize = SizeOfMemory;
|
|
NewBreakPoint.BreakPointType = BreakPointType;
|
|
NewBreakPoint.MemoryBpxRestoreOnHit = (BYTE)RestoreOnHit;
|
|
NewBreakPoint.ExecuteCallBack = (ULONG_PTR)bpxCallBack;
|
|
BreakPointBuffer.push_back(NewBreakPoint);
|
|
return true;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL RemoveMemoryBPX(ULONG_PTR MemoryStart, SIZE_T SizeOfMemory)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
bool isSuccess = true;
|
|
|
|
// find the breakpoint
|
|
int nFoundBp = -1;
|
|
size_t bpcount = BreakPointBuffer.size();
|
|
for(size_t i = 0; i < bpcount; i++)
|
|
{
|
|
auto bpAddr = BreakPointBuffer.at(i).BreakPointAddress;
|
|
auto bpType = BreakPointBuffer.at(i).BreakPointType;
|
|
bool isMem = bpType == UE_MEMORY || bpType == UE_MEMORY_READ || bpType == UE_MEMORY_WRITE || bpType == UE_MEMORY_EXECUTE;
|
|
|
|
if(isMem && bpAddr == MemoryStart)
|
|
{
|
|
nFoundBp = (int)i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(nFoundBp == -1)
|
|
return false; // not found
|
|
|
|
int memBpType = BreakPointBuffer.at(nFoundBp).BreakPointType;
|
|
SizeOfMemory = BreakPointBuffer.at(nFoundBp).BreakPointSize; // ignore the given size, x64dbg may be lying
|
|
|
|
//delete the memory breakpoint from the pages
|
|
auto pageStart = ALIGN_DOWN_BY(MemoryStart, TITANENGINE_PAGESIZE);
|
|
auto pageEnd = ALIGN_UP_BY(MemoryStart + SizeOfMemory, TITANENGINE_PAGESIZE);
|
|
for(ULONG_PTR pageAddr = pageStart; pageAddr < pageEnd; pageAddr += TITANENGINE_PAGESIZE)
|
|
{
|
|
auto foundPageData = MemoryBreakpointPages.find(pageAddr);
|
|
if(foundPageData == MemoryBreakpointPages.end())
|
|
continue; // should not happen
|
|
|
|
// Decrement a BP counter
|
|
auto & pageData = foundPageData->second;
|
|
switch(memBpType)
|
|
{
|
|
case UE_MEMORY: // READ + WRITE + EXECUTE
|
|
pageData.accessBps -= 1;
|
|
break;
|
|
case UE_MEMORY_READ:
|
|
pageData.readBps -= 1;
|
|
break;
|
|
case UE_MEMORY_WRITE:
|
|
pageData.writeBps -= 1;
|
|
break;
|
|
case UE_MEMORY_EXECUTE:
|
|
pageData.executeBps -= 1;
|
|
break;
|
|
default: // unreachable
|
|
break;
|
|
}
|
|
|
|
DWORD newProtect;
|
|
const bool noMoreBps = 0 == (pageData.accessBps + pageData.readBps + pageData.writeBps + pageData.executeBps);
|
|
if(noMoreBps)
|
|
{
|
|
// There are no more BPs on this page. Remove the page data.
|
|
newProtect = pageData.origProtect;
|
|
MemoryBreakpointPages.erase(foundPageData);
|
|
}
|
|
else
|
|
{
|
|
// Some BPs are still here. According to their types, reapply page protection.
|
|
pageData.newProtect = GetPageProtectionForMemoryBreakpoint(pageData);
|
|
newProtect = pageData.newProtect;
|
|
}
|
|
|
|
DWORD oldProtect;
|
|
if(!VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)pageAddr, TITANENGINE_PAGESIZE, newProtect, &oldProtect))
|
|
isSuccess = false;
|
|
}
|
|
|
|
//remove breakpoint from list
|
|
BreakPointBuffer.erase(BreakPointBuffer.begin() + nFoundBp);
|
|
|
|
return isSuccess;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL GetUnusedHardwareBreakPointRegister(LPDWORD RegisterIndex)
|
|
{
|
|
return EngineIsThereFreeHardwareBreakSlot(RegisterIndex);
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SetHardwareBreakPoint(ULONG_PTR bpxAddress, DWORD IndexOfRegister, DWORD bpxType, DWORD bpxSize, LPVOID bpxCallBack)
|
|
{
|
|
HWBP_SIZE hwbpSize;
|
|
HWBP_MODE hwbpMode;
|
|
HWBP_TYPE hwbpType;
|
|
int hwbpIndex = -1;
|
|
DR7 dr7;
|
|
|
|
switch(bpxSize)
|
|
{
|
|
case UE_HARDWARE_SIZE_1:
|
|
hwbpSize = SIZE_1;
|
|
break;
|
|
case UE_HARDWARE_SIZE_2:
|
|
hwbpSize = SIZE_2;
|
|
if((bpxAddress % 2) != 0)
|
|
return false;
|
|
break;
|
|
case UE_HARDWARE_SIZE_4:
|
|
hwbpSize = SIZE_4;
|
|
if((bpxAddress % 4) != 0)
|
|
return false;
|
|
break;
|
|
case UE_HARDWARE_SIZE_8:
|
|
hwbpSize = SIZE_8;
|
|
if((bpxAddress % 8) != 0)
|
|
return false;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if(!IndexOfRegister)
|
|
{
|
|
if(!DebugRegister[0].DrxEnabled)
|
|
IndexOfRegister = UE_DR0;
|
|
else if(!DebugRegister[1].DrxEnabled)
|
|
IndexOfRegister = UE_DR1;
|
|
else if(!DebugRegister[2].DrxEnabled)
|
|
IndexOfRegister = UE_DR2;
|
|
else if(!DebugRegister[3].DrxEnabled)
|
|
IndexOfRegister = UE_DR3;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
switch(IndexOfRegister)
|
|
{
|
|
case UE_DR0:
|
|
hwbpIndex = 0;
|
|
break;
|
|
case UE_DR1:
|
|
hwbpIndex = 1;
|
|
break;
|
|
case UE_DR2:
|
|
hwbpIndex = 2;
|
|
break;
|
|
case UE_DR3:
|
|
hwbpIndex = 3;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
uintdr7((ULONG_PTR)GetContextData(UE_DR7), &dr7);
|
|
|
|
DebugRegister[hwbpIndex].DrxExecution = false;
|
|
|
|
switch(bpxType)
|
|
{
|
|
case UE_HARDWARE_EXECUTE:
|
|
hwbpSize = SIZE_1;
|
|
hwbpType = TYPE_EXECUTE;
|
|
DebugRegister[hwbpIndex].DrxExecution = true;
|
|
break;
|
|
case UE_HARDWARE_WRITE:
|
|
hwbpType = TYPE_WRITE;
|
|
break;
|
|
case UE_HARDWARE_READWRITE:
|
|
hwbpType = TYPE_READWRITE;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
hwbpMode = MODE_LOCAL;
|
|
|
|
dr7.HWBP_MODE[hwbpIndex] = hwbpMode;
|
|
dr7.HWBP_SIZE[hwbpIndex] = hwbpSize;
|
|
dr7.HWBP_TYPE[hwbpIndex] = hwbpType;
|
|
|
|
for(unsigned int i = 0; i < hListThread.size(); i++)
|
|
{
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR7, dr7uint(&dr7)); //NOTE: MUST SET THIS FIRST FOR X64!
|
|
SetContextDataEx(hListThread.at(i).hThread, IndexOfRegister, bpxAddress);
|
|
}
|
|
|
|
DebugRegister[hwbpIndex].DrxBreakPointType = bpxType;
|
|
DebugRegister[hwbpIndex].DrxBreakPointSize = bpxSize;
|
|
DebugRegister[hwbpIndex].DrxEnabled = true;
|
|
DebugRegister[hwbpIndex].DrxBreakAddress = (ULONG_PTR)bpxAddress;
|
|
DebugRegister[hwbpIndex].DrxCallBack = (ULONG_PTR)bpxCallBack;
|
|
|
|
return true;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL SetHardwareBreakPointEx(HANDLE hActiveThread, ULONG_PTR bpxAddress, DWORD IndexOfRegister, DWORD bpxType, DWORD bpxSize, LPVOID bpxCallBack, LPDWORD IndexOfSelectedRegister)
|
|
{
|
|
HWBP_SIZE hwbpSize;
|
|
HWBP_MODE hwbpMode;
|
|
HWBP_TYPE hwbpType;
|
|
int hwbpIndex = -1;
|
|
DR7 dr7;
|
|
|
|
switch(bpxSize)
|
|
{
|
|
case UE_HARDWARE_SIZE_1:
|
|
hwbpSize = SIZE_1;
|
|
break;
|
|
case UE_HARDWARE_SIZE_2:
|
|
hwbpSize = SIZE_2;
|
|
if((bpxAddress % 2) != 0)
|
|
return false;
|
|
break;
|
|
case UE_HARDWARE_SIZE_4:
|
|
hwbpSize = SIZE_4;
|
|
if((bpxAddress % 4) != 0)
|
|
return false;
|
|
break;
|
|
case UE_HARDWARE_SIZE_8:
|
|
hwbpSize = SIZE_8;
|
|
if((bpxAddress % 8) != 0)
|
|
return false;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if(!IndexOfRegister)
|
|
{
|
|
if(!DebugRegister[0].DrxEnabled)
|
|
IndexOfRegister = UE_DR0;
|
|
else if(!DebugRegister[1].DrxEnabled)
|
|
IndexOfRegister = UE_DR1;
|
|
else if(!DebugRegister[2].DrxEnabled)
|
|
IndexOfRegister = UE_DR2;
|
|
else if(!DebugRegister[3].DrxEnabled)
|
|
IndexOfRegister = UE_DR3;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
if(IndexOfSelectedRegister)
|
|
*IndexOfSelectedRegister = IndexOfRegister;
|
|
|
|
switch(IndexOfRegister)
|
|
{
|
|
case UE_DR0:
|
|
hwbpIndex = 0;
|
|
break;
|
|
case UE_DR1:
|
|
hwbpIndex = 1;
|
|
break;
|
|
case UE_DR2:
|
|
hwbpIndex = 2;
|
|
break;
|
|
case UE_DR3:
|
|
hwbpIndex = 3;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
uintdr7((ULONG_PTR)GetContextDataEx(hActiveThread, UE_DR7), &dr7);
|
|
|
|
DebugRegister[hwbpIndex].DrxExecution = false;
|
|
|
|
switch(bpxType)
|
|
{
|
|
case UE_HARDWARE_EXECUTE:
|
|
hwbpSize = SIZE_1;
|
|
hwbpType = TYPE_EXECUTE;
|
|
DebugRegister[hwbpIndex].DrxExecution = true;
|
|
break;
|
|
case UE_HARDWARE_WRITE:
|
|
hwbpType = TYPE_WRITE;
|
|
break;
|
|
case UE_HARDWARE_READWRITE:
|
|
hwbpType = TYPE_READWRITE;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
hwbpMode = MODE_LOCAL;
|
|
|
|
dr7.HWBP_MODE[hwbpIndex] = hwbpMode;
|
|
dr7.HWBP_SIZE[hwbpIndex] = hwbpSize;
|
|
dr7.HWBP_TYPE[hwbpIndex] = hwbpType;
|
|
|
|
SetContextDataEx(hActiveThread, UE_DR7, dr7uint(&dr7));
|
|
SetContextDataEx(hActiveThread, IndexOfRegister, (ULONG_PTR)bpxAddress);
|
|
|
|
DebugRegister[hwbpIndex].DrxBreakPointType = bpxType;
|
|
DebugRegister[hwbpIndex].DrxBreakPointSize = bpxSize;
|
|
DebugRegister[hwbpIndex].DrxEnabled = true;
|
|
DebugRegister[hwbpIndex].DrxBreakAddress = (ULONG_PTR)bpxAddress;
|
|
DebugRegister[hwbpIndex].DrxCallBack = (ULONG_PTR)bpxCallBack;
|
|
|
|
return true;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL DeleteHardwareBreakPoint(DWORD IndexOfRegister)
|
|
{
|
|
ULONG_PTR HardwareBPX = NULL;
|
|
ULONG_PTR bpxAddress = NULL;
|
|
|
|
if(IndexOfRegister == UE_DR0)
|
|
{
|
|
HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7);
|
|
HardwareBPX = HardwareBPX & ~(1 << 0);
|
|
HardwareBPX = HardwareBPX & ~(1 << 1);
|
|
for(unsigned int i = 0; i < hListThread.size(); i++)
|
|
{
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR0, bpxAddress);
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR7, HardwareBPX);
|
|
}
|
|
DebugRegister[0].DrxEnabled = false;
|
|
DebugRegister[0].DrxBreakAddress = NULL;
|
|
DebugRegister[0].DrxCallBack = NULL;
|
|
return true;
|
|
}
|
|
else if(IndexOfRegister == UE_DR1)
|
|
{
|
|
HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7);
|
|
HardwareBPX = HardwareBPX & ~(1 << 2);
|
|
HardwareBPX = HardwareBPX & ~(1 << 3);
|
|
for(unsigned int i = 0; i < hListThread.size(); i++)
|
|
{
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR1, bpxAddress);
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR7, HardwareBPX);
|
|
}
|
|
DebugRegister[1].DrxEnabled = false;
|
|
DebugRegister[1].DrxBreakAddress = NULL;
|
|
DebugRegister[1].DrxCallBack = NULL;
|
|
return true;
|
|
}
|
|
else if(IndexOfRegister == UE_DR2)
|
|
{
|
|
HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7);
|
|
HardwareBPX = HardwareBPX & ~(1 << 4);
|
|
HardwareBPX = HardwareBPX & ~(1 << 5);
|
|
for(unsigned int i = 0; i < hListThread.size(); i++)
|
|
{
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR2, bpxAddress);
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR7, HardwareBPX);
|
|
}
|
|
DebugRegister[2].DrxEnabled = false;
|
|
DebugRegister[2].DrxBreakAddress = NULL;
|
|
DebugRegister[2].DrxCallBack = NULL;
|
|
return true;
|
|
}
|
|
else if(IndexOfRegister == UE_DR3)
|
|
{
|
|
HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7);
|
|
HardwareBPX = HardwareBPX & ~(1 << 6);
|
|
HardwareBPX = HardwareBPX & ~(1 << 7);
|
|
for(unsigned int i = 0; i < hListThread.size(); i++)
|
|
{
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR3, bpxAddress);
|
|
SetContextDataEx(hListThread.at(i).hThread, UE_DR7, HardwareBPX);
|
|
}
|
|
DebugRegister[3].DrxEnabled = false;
|
|
DebugRegister[3].DrxBreakAddress = NULL;
|
|
DebugRegister[3].DrxCallBack = NULL;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(dllexport) bool TITCALL RemoveAllBreakPoints(DWORD RemoveOption)
|
|
{
|
|
CriticalSectionLocker lock(LockBreakPointBuffer);
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
if(RemoveOption == UE_OPTION_REMOVEALL)
|
|
{
|
|
for(int i = bpcount - 1; i > -1; i--)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT)
|
|
{
|
|
DeleteBPX((ULONG_PTR)BreakPointBuffer.at(i).BreakPointAddress);
|
|
}
|
|
else if(BreakPointBuffer.at(i).BreakPointType == UE_MEMORY ||
|
|
BreakPointBuffer.at(i).BreakPointType == UE_MEMORY_READ ||
|
|
BreakPointBuffer.at(i).BreakPointType == UE_MEMORY_WRITE ||
|
|
BreakPointBuffer.at(i).BreakPointType == UE_MEMORY_EXECUTE)
|
|
{
|
|
RemoveMemoryBPX((ULONG_PTR)BreakPointBuffer.at(i).BreakPointAddress, BreakPointBuffer.at(i).BreakPointSize);
|
|
}
|
|
}
|
|
DeleteHardwareBreakPoint(UE_DR0);
|
|
DeleteHardwareBreakPoint(UE_DR1);
|
|
DeleteHardwareBreakPoint(UE_DR2);
|
|
DeleteHardwareBreakPoint(UE_DR3);
|
|
return true;
|
|
}
|
|
else if(RemoveOption == UE_OPTION_DISABLEALL)
|
|
{
|
|
for(int i = bpcount - 1; i > -1; i--)
|
|
{
|
|
if((BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT) && BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
DisableBPX((ULONG_PTR)BreakPointBuffer.at(i).BreakPointAddress);
|
|
}
|
|
else if(BreakPointBuffer.at(i).BreakPointType == UE_MEMORY ||
|
|
BreakPointBuffer.at(i).BreakPointType == UE_MEMORY_READ ||
|
|
BreakPointBuffer.at(i).BreakPointType == UE_MEMORY_WRITE ||
|
|
BreakPointBuffer.at(i).BreakPointType == UE_MEMORY_EXECUTE)
|
|
{
|
|
RemoveMemoryBPX((ULONG_PTR)BreakPointBuffer.at(i).BreakPointAddress, BreakPointBuffer.at(i).BreakPointSize);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if(RemoveOption == UE_OPTION_REMOVEALLDISABLED)
|
|
{
|
|
for(int i = bpcount - 1; i > -1; i--)
|
|
{
|
|
if((BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT) && BreakPointBuffer.at(i).BreakPointActive == UE_BPXINACTIVE)
|
|
{
|
|
DeleteBPX((ULONG_PTR)BreakPointBuffer.at(i).BreakPointAddress);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if(RemoveOption == UE_OPTION_REMOVEALLENABLED)
|
|
{
|
|
for(int i = bpcount - 1; i > -1; i--)
|
|
{
|
|
if((BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT) && BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
DeleteBPX((ULONG_PTR)BreakPointBuffer.at(i).BreakPointAddress);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|