mirror of https://github.com/x64dbg/TitanEngine
1408 lines
71 KiB
C++
1408 lines
71 KiB
C++
#include "stdafx.h"
|
|
#include "definitions.h"
|
|
#include "Global.Debugger.h"
|
|
#include "Global.Handle.h"
|
|
#include "Global.Engine.h"
|
|
#include "Global.Engine.Extension.h"
|
|
#include "Global.Breakpoints.h"
|
|
#include "Global.Threader.h"
|
|
#include "Global.Librarian.h"
|
|
#include "Global.TLS.h"
|
|
|
|
#define UE_MODULEx86 0x2000;
|
|
#define UE_MODULEx64 0x2000;
|
|
|
|
__declspec(dllexport) void TITCALL DebugLoop()
|
|
{
|
|
bool FirstBPX = true;
|
|
bool ResetBPX = false;
|
|
bool PushfBPX = false;
|
|
bool BreakDBG = false;
|
|
bool ResetHwBPX = false;
|
|
bool ResetMemBPX = false;
|
|
bool SecondChance = false;
|
|
bool hListProcessFirst = true;
|
|
bool hListThreadFirst = true;
|
|
bool hListLibraryFirst = true;
|
|
bool MemoryBpxFound = false;
|
|
PLIBRARY_ITEM_DATAW hLoadedLibData = NULL;
|
|
PLIBRARY_BREAK_DATA ptrLibrarianData = NULL;
|
|
typedef void(TITCALL * fCustomBreakPoint)(void);
|
|
typedef void(TITCALL * fCustomHandler)(void* SpecialDBG);
|
|
typedef void(TITCALL * fFindOEPHandler)(LPPROCESS_INFORMATION fProcessInfo, LPVOID fCallBack);
|
|
fCustomHandler myCustomHandler;
|
|
fCustomBreakPoint myCustomBreakPoint;
|
|
ULONG_PTR MemoryBpxCallBack = 0;
|
|
SIZE_T ResetBPXSize = 0;
|
|
ULONG_PTR ResetBPXAddressTo = 0;
|
|
ULONG_PTR ResetMemBPXAddress = 0;
|
|
SIZE_T ResetMemBPXSize = 0;
|
|
ULONG_PTR NumberOfBytesReadWritten = 0;
|
|
MEMORY_BASIC_INFORMATION MemInfo;
|
|
HANDLE hActiveThread;
|
|
CONTEXT myDBGContext;
|
|
DWORD OldProtect;
|
|
DWORD NewProtect;
|
|
DWORD DebugRegisterXId = NULL;
|
|
HARDWARE_DATA DebugRegisterX;
|
|
wchar_t DLLDebugFileName[512];
|
|
char szAnsiLibraryName[MAX_PATH];
|
|
ULONG_PTR DLLPatchAddress;
|
|
LPVOID DBGEntryPoint;
|
|
|
|
wchar_t* szTranslatedNativeName;
|
|
|
|
DBGFileHandle = NULL;
|
|
DBGCode = DBG_CONTINUE;
|
|
engineFakeDLLHandle = NULL;
|
|
DebugRegister[0].DrxEnabled = false;
|
|
DebugRegister[1].DrxEnabled = false;
|
|
DebugRegister[2].DrxEnabled = false;
|
|
DebugRegister[3].DrxEnabled = false;
|
|
engineProcessIsNowDetached = false;
|
|
engineResumeProcessIfNoThreadIsActive = false;
|
|
memset(&DBGEvent, 0, sizeof(DEBUG_EVENT));
|
|
memset(&TerminateDBGEvent, 0, sizeof(DEBUG_EVENT));
|
|
memset(&DLLDebugFileName, 0, sizeof(DLLDebugFileName));
|
|
ExtensionManagerPluginResetCallBack();
|
|
engineFileIsBeingDebugged = true;
|
|
if(engineExecutePluginCallBack)
|
|
{
|
|
ExtensionManagerPluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_PREDEBUG);
|
|
}
|
|
|
|
while(!BreakDBG) //actual debug loop
|
|
{
|
|
// Fix based on work by https://github.com/number201724
|
|
if(!WaitForDebugEvent(&DBGEvent, 100))
|
|
{
|
|
if(engineProcessIsNowDetached)
|
|
{
|
|
DebugActiveProcessStop(dbgProcessInformation.dwProcessId);
|
|
DebugAttachedToProcess = false;
|
|
break;
|
|
}
|
|
if(WaitForSingleObject(dbgProcessInformation.hProcess, 0) == WAIT_OBJECT_0)
|
|
{
|
|
DBGEvent.dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
|
|
DBGEvent.dwProcessId = dbgProcessInformation.dwProcessId;
|
|
DBGEvent.dwThreadId = dbgProcessInformation.dwThreadId;
|
|
if(!GetExitCodeProcess(dbgProcessInformation.hProcess, &DBGEvent.u.ExitProcess.dwExitCode))
|
|
DBGEvent.u.ExitProcess.dwExitCode = 0xFFFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
// Regular timeout, wait again
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if(engineExecutePluginCallBack)
|
|
{
|
|
ExtensionManagerPluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_EXCEPTION);
|
|
}
|
|
|
|
//Debug event custom handler
|
|
if(DBGCustomHandler->chDebugEvent != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chDebugEvent);
|
|
myCustomHandler(&DBGEvent);
|
|
}
|
|
|
|
//Debug event
|
|
switch(DBGEvent.dwDebugEventCode)
|
|
{
|
|
case CREATE_PROCESS_DEBUG_EVENT:
|
|
{
|
|
bool attachBreakpoint = false;
|
|
if(DBGFileHandle == NULL) //we didn't set the handle yet (initial process)
|
|
{
|
|
DBGEntryPoint = DBGEvent.u.CreateProcessInfo.lpStartAddress;
|
|
DBGFileHandle = DBGEvent.u.CreateProcessInfo.hFile;
|
|
DebugDebuggingMainModuleBase = (ULONG_PTR) DBGEvent.u.CreateProcessInfo.lpBaseOfImage;
|
|
if(DebugAttachedToProcess) //we attached, set information
|
|
{
|
|
dbgProcessInformation.hProcess = DBGEvent.u.CreateProcessInfo.hProcess;
|
|
dbgProcessInformation.hThread = DBGEvent.u.CreateProcessInfo.hThread;
|
|
dbgProcessInformation.dwThreadId = NULL;
|
|
if(engineAttachedProcessDebugInfo != NULL)
|
|
{
|
|
RtlMoveMemory(engineAttachedProcessDebugInfo, &dbgProcessInformation, sizeof PROCESS_INFORMATION);
|
|
}
|
|
attachBreakpoint = true;
|
|
}
|
|
if(DebugDebuggingDLL) //the DLL loader just started, set DLL names
|
|
{
|
|
#if defined(_WIN64)
|
|
DLLPatchAddress = (ULONG_PTR)DBGEvent.u.CreateProcessInfo.lpBaseOfImage;
|
|
DLLPatchAddress = (ULONG_PTR)DLLPatchAddress + UE_MODULEx64;
|
|
#else
|
|
DLLPatchAddress = (ULONG_PTR)DBGEvent.u.CreateProcessInfo.lpBaseOfImage;
|
|
DLLPatchAddress = (ULONG_PTR)DLLPatchAddress + UE_MODULEx86;
|
|
#endif
|
|
if(DebugReserveModuleBase) //reserve original image base
|
|
{
|
|
VirtualAllocEx(dbgProcessInformation.hProcess, (void*)DebugReserveModuleBase, 0x1000, MEM_RESERVE, PAGE_READWRITE); //return value nt used, yea just ignore. return value doesnt matter and there is no possible fix when failed :D this is only used to make sure DLL loads on another image base
|
|
}
|
|
}
|
|
if(hListProcessFirst) //clear process list
|
|
ClearProcessList();
|
|
hListProcessFirst = false;
|
|
|
|
if(hListThreadFirst) //clear thread list
|
|
ClearThreadList();
|
|
hListThreadFirst = false;
|
|
//update thread list
|
|
THREAD_ITEM_DATA NewThreadData;
|
|
memset(&NewThreadData, 0, sizeof(THREAD_ITEM_DATA));
|
|
NewThreadData.dwThreadId = DBGEvent.dwThreadId;
|
|
NewThreadData.hThread = DBGEvent.u.CreateProcessInfo.hThread;
|
|
NewThreadData.ThreadStartAddress = (void*)DBGEvent.u.CreateProcessInfo.lpStartAddress;
|
|
NewThreadData.ThreadLocalBase = (void*)DBGEvent.u.CreateProcessInfo.lpThreadLocalBase;
|
|
hListThread.push_back(NewThreadData);
|
|
}
|
|
//update process list
|
|
PROCESS_ITEM_DATA NewProcessItem;
|
|
memset(&NewProcessItem, 0, sizeof(PROCESS_ITEM_DATA));
|
|
NewProcessItem.hFile = DBGEvent.u.CreateProcessInfo.hFile;
|
|
NewProcessItem.hProcess = DBGEvent.u.CreateProcessInfo.hProcess;
|
|
NewProcessItem.hThread = DBGEvent.u.CreateProcessInfo.hThread;
|
|
NewProcessItem.dwProcessId = DBGEvent.dwProcessId;
|
|
NewProcessItem.dwThreadId = DBGEvent.dwThreadId;
|
|
NewProcessItem.BaseOfImage = (void*)DBGEvent.u.CreateProcessInfo.lpBaseOfImage;
|
|
NewProcessItem.ThreadStartAddress = (void*)DBGEvent.u.CreateProcessInfo.lpStartAddress;
|
|
NewProcessItem.ThreadLocalBase = (void*)DBGEvent.u.CreateProcessInfo.lpThreadLocalBase;
|
|
hListProcess.push_back(NewProcessItem);
|
|
|
|
//process created callback
|
|
if(DBGCustomHandler->chCreateProcess != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chCreateProcess);
|
|
myCustomHandler(&DBGEvent.u.CreateProcessInfo);
|
|
}
|
|
|
|
if(DBGFileHandle)
|
|
EngineCloseHandle(DBGFileHandle); //close file handle
|
|
|
|
// Call the attach breakpoint
|
|
if(attachBreakpoint)
|
|
{
|
|
myCustomBreakPoint = (fCustomBreakPoint)(DebugAttachedProcessCallBack);
|
|
myCustomBreakPoint();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EXIT_PROCESS_DEBUG_EVENT:
|
|
{
|
|
ProcessExitCode = DBGEvent.u.ExitProcess.dwExitCode;
|
|
DBGCode = DBG_CONTINUE;
|
|
if(DBGEvent.dwProcessId == dbgProcessInformation.dwProcessId) //main process closed
|
|
BreakDBG = true;
|
|
|
|
//exit process handler
|
|
if(DBGCustomHandler->chExitProcess != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chExitProcess);
|
|
myCustomHandler(&DBGEvent.u.ExitProcess);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CREATE_THREAD_DEBUG_EVENT:
|
|
{
|
|
//maintain thread list
|
|
THREAD_ITEM_DATA NewThreadData;
|
|
memset(&NewThreadData, 0, sizeof(THREAD_ITEM_DATA));
|
|
NewThreadData.dwThreadId = DBGEvent.dwThreadId;
|
|
NewThreadData.hThread = DBGEvent.u.CreateThread.hThread;
|
|
NewThreadData.ThreadStartAddress = (void*)DBGEvent.u.CreateThread.lpStartAddress;
|
|
NewThreadData.ThreadLocalBase = (void*)DBGEvent.u.CreateThread.lpThreadLocalBase;
|
|
hListThread.push_back(NewThreadData);
|
|
|
|
//Set hardware breakpoints to all threads
|
|
HANDLE hThread = NewThreadData.hThread;
|
|
if(DebugRegister[0].DrxEnabled)
|
|
SetHardwareBreakPointEx(hThread, DebugRegister[0].DrxBreakAddress, UE_DR0, DebugRegister[0].DrxBreakPointType, DebugRegister[0].DrxBreakPointSize, (void*)DebugRegister[0].DrxCallBack, 0);
|
|
if(DebugRegister[1].DrxEnabled)
|
|
SetHardwareBreakPointEx(hThread, DebugRegister[1].DrxBreakAddress, UE_DR1, DebugRegister[1].DrxBreakPointType, DebugRegister[1].DrxBreakPointSize, (void*)DebugRegister[1].DrxCallBack, 0);
|
|
if(DebugRegister[2].DrxEnabled)
|
|
SetHardwareBreakPointEx(hThread, DebugRegister[2].DrxBreakAddress, UE_DR2, DebugRegister[2].DrxBreakPointType, DebugRegister[2].DrxBreakPointSize, (void*)DebugRegister[2].DrxCallBack, 0);
|
|
if(DebugRegister[3].DrxEnabled)
|
|
SetHardwareBreakPointEx(hThread, DebugRegister[3].DrxBreakAddress, UE_DR3, DebugRegister[3].DrxBreakPointType, DebugRegister[3].DrxBreakPointSize, (void*)DebugRegister[3].DrxCallBack, 0);
|
|
if(ResetHwBPX)
|
|
{
|
|
SetHardwareBreakPoint(DebugRegisterX.DrxBreakAddress, DebugRegisterXId, DebugRegisterX.DrxBreakPointType, DebugRegisterX.DrxBreakPointSize, (void*)DebugRegisterX.DrxCallBack);
|
|
ResetHwBPX = false;
|
|
}
|
|
|
|
//custom handler
|
|
if(DBGCustomHandler->chCreateThread != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chCreateThread);
|
|
myCustomHandler(&DBGEvent.u.CreateThread);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EXIT_THREAD_DEBUG_EVENT:
|
|
{
|
|
//custom handler
|
|
if(DBGCustomHandler->chExitThread != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chExitThread);
|
|
myCustomHandler(&DBGEvent.u.ExitThread);
|
|
}
|
|
if(engineExitThreadOneShootCallBack != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)(engineExitThreadOneShootCallBack);
|
|
myCustomHandler(&DBGEvent.u.ExitThread);
|
|
engineExitThreadOneShootCallBack = NULL;
|
|
}
|
|
|
|
//maintain thread list
|
|
for(unsigned int i = 0; i < hListThread.size(); i++)
|
|
{
|
|
if(hListThread.at(i).dwThreadId == DBGEvent.dwThreadId) //found the thread to remove
|
|
{
|
|
hListThread.erase(hListThread.begin() + i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LOAD_DLL_DEBUG_EVENT:
|
|
{
|
|
//maintain library list
|
|
if(hListLibraryFirst)
|
|
ClearLibraryList();
|
|
hListLibraryFirst = false;
|
|
LIBRARY_ITEM_DATAW NewLibraryData;
|
|
memset(&NewLibraryData, 0, sizeof(LIBRARY_ITEM_DATAW));
|
|
NewLibraryData.BaseOfDll = DBGEvent.u.LoadDll.lpBaseOfDll;
|
|
|
|
// Query remote DLL path
|
|
if(GetMappedFileNameW(dbgProcessInformation.hProcess, DBGEvent.u.LoadDll.lpBaseOfDll, DLLDebugFileName, sizeof(DLLDebugFileName) / sizeof(wchar_t)))
|
|
{
|
|
int i = lstrlenW(DLLDebugFileName);
|
|
while(DLLDebugFileName[i] != '\\' && i)
|
|
i--;
|
|
if(DebugDebuggingDLL)
|
|
{
|
|
if(lstrcmpiW(&DLLDebugFileName[i + 1], DebugDebuggingDLLFileName) == NULL)
|
|
{
|
|
CloseHandle(DebugDLLFileMapping); //close file mapping handle
|
|
SetBPX(DebugModuleEntryPoint + (ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll, UE_SINGLESHOOT, DebugModuleEntryPointCallBack);
|
|
DebugDebuggingDLLBase = (ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll;
|
|
}
|
|
/*else if(lstrcmpiW(&DLLDebugFileName[i+1], DebugDebuggingDLLReserveFileName) == NULL)
|
|
{
|
|
if((ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll != DebugModuleImageBase)
|
|
{
|
|
VirtualAllocEx(dbgProcessInformation.hProcess, (void*)DebugModuleImageBase, 0x1000, MEM_RESERVE, PAGE_READWRITE);
|
|
}
|
|
}*/
|
|
}
|
|
if(engineFakeDLLHandle == NULL)
|
|
{
|
|
if(_wcsicmp(&DLLDebugFileName[i + 1], L"kernel32.dll") == NULL)
|
|
{
|
|
engineFakeDLLHandle = (ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll;
|
|
}
|
|
}
|
|
lstrcpyW(NewLibraryData.szLibraryName, &DLLDebugFileName[i + 1]);
|
|
szTranslatedNativeName = (wchar_t*)TranslateNativeNameW(DLLDebugFileName);
|
|
if(szTranslatedNativeName != nullptr)
|
|
{
|
|
lstrcpyW(NewLibraryData.szLibraryPath, szTranslatedNativeName);
|
|
VirtualFree((void*)szTranslatedNativeName, NULL, MEM_RELEASE);
|
|
}
|
|
RtlZeroMemory(szAnsiLibraryName, sizeof(szAnsiLibraryName));
|
|
WideCharToMultiByte(CP_ACP, NULL, NewLibraryData.szLibraryName, -1, szAnsiLibraryName, sizeof szAnsiLibraryName, NULL, NULL);
|
|
|
|
//library breakpoint
|
|
for(int i = (int)LibrarianData.size() - 1; i >= 0; i--)
|
|
{
|
|
ptrLibrarianData = &LibrarianData.at(i);
|
|
if(!_stricmp(ptrLibrarianData->szLibraryName, szAnsiLibraryName))
|
|
{
|
|
if(ptrLibrarianData->bpxType == UE_ON_LIB_LOAD || ptrLibrarianData->bpxType == UE_ON_LIB_ALL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)(ptrLibrarianData->bpxCallBack);
|
|
myCustomHandler(&DBGEvent.u.LoadDll);
|
|
if(ptrLibrarianData->bpxSingleShoot)
|
|
{
|
|
LibrarianRemoveBreakPoint(ptrLibrarianData->szLibraryName, ptrLibrarianData->bpxType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//maintain library list
|
|
hListLibrary.push_back(NewLibraryData);
|
|
|
|
//loadDLL callback
|
|
if(DBGCustomHandler->chLoadDll != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chLoadDll);
|
|
myCustomHandler(&DBGEvent.u.LoadDll);
|
|
}
|
|
|
|
if(DBGEvent.u.LoadDll.hFile)
|
|
EngineCloseHandle(DBGEvent.u.LoadDll.hFile); //close file handle
|
|
}
|
|
break;
|
|
|
|
case UNLOAD_DLL_DEBUG_EVENT:
|
|
{
|
|
//unload DLL callback
|
|
if(DBGCustomHandler->chUnloadDll != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chUnloadDll);
|
|
myCustomHandler(&DBGEvent.u.UnloadDll);
|
|
}
|
|
|
|
//library breakpoint
|
|
hLoadedLibData = (PLIBRARY_ITEM_DATAW)LibrarianGetLibraryInfoEx(DBGEvent.u.UnloadDll.lpBaseOfDll);
|
|
if(hLoadedLibData)
|
|
{
|
|
RtlZeroMemory(szAnsiLibraryName, sizeof(szAnsiLibraryName));
|
|
WideCharToMultiByte(CP_ACP, NULL, hLoadedLibData->szLibraryName, -1, szAnsiLibraryName, sizeof szAnsiLibraryName, NULL, NULL);
|
|
|
|
for(int i = (int)LibrarianData.size() - 1; i >= 0; i--)
|
|
{
|
|
ptrLibrarianData = &LibrarianData.at(i);
|
|
if(!_stricmp(ptrLibrarianData->szLibraryName, szAnsiLibraryName))
|
|
{
|
|
if(ptrLibrarianData->bpxType == UE_ON_LIB_UNLOAD || ptrLibrarianData->bpxType == UE_ON_LIB_ALL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)(ptrLibrarianData->bpxCallBack);
|
|
myCustomHandler(&DBGEvent.u.UnloadDll);
|
|
if(ptrLibrarianData->bpxSingleShoot)
|
|
{
|
|
LibrarianRemoveBreakPoint(ptrLibrarianData->szLibraryName, ptrLibrarianData->bpxType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//maintain library list
|
|
for(unsigned int i = 0; i < hListLibrary.size(); i++)
|
|
{
|
|
if(hListLibrary.at(i).BaseOfDll == DBGEvent.u.UnloadDll.lpBaseOfDll)
|
|
{
|
|
if(hListLibrary.at(i).hFileMappingView != NULL)
|
|
{
|
|
UnmapViewOfFile(hListLibrary.at(i).hFileMappingView);
|
|
EngineCloseHandle(hListLibrary.at(i).hFileMapping);
|
|
}
|
|
hListLibrary.erase(hListLibrary.begin() + i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OUTPUT_DEBUG_STRING_EVENT:
|
|
{
|
|
//http://maximumcrack.wordpress.com/2009/06/22/outputdebugstring-awesomeness/ (the final advice is incorrect, but still helpful)
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED; //pass exception to debuggee
|
|
if(engineExecutePluginCallBack)
|
|
{
|
|
ExtensionManagerPluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_UNHANDLEDEXCEPTION);
|
|
}
|
|
//debug string callback
|
|
if(DBGCustomHandler->chOutputDebugString != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chOutputDebugString);
|
|
myCustomHandler(&DBGEvent.u.DebugString);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EXCEPTION_DEBUG_EVENT:
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED; //let the debuggee handle exceptions per default
|
|
|
|
if(DBGCustomHandler->chEverythingElse != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chEverythingElse);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
if(DBGEvent.u.Exception.dwFirstChance == FALSE) //second chance exception
|
|
{
|
|
//NOTE: unclear behavious of ->Pass<- all exceptions (not to debuggee, but to debugger)
|
|
if(!enginePassAllExceptions)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
}
|
|
else
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED; //let debuggee handle the exception
|
|
}
|
|
RtlMoveMemory(&TerminateDBGEvent, &DBGEvent, sizeof DEBUG_EVENT);
|
|
}
|
|
|
|
//handle different exception codes
|
|
switch(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode)
|
|
{
|
|
case STATUS_BREAKPOINT:
|
|
{
|
|
bool bFoundBreakPoint = false;
|
|
BreakPointDetail FoundBreakPoint;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointAddress == (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress - (BreakPointBuffer.at(i).BreakPointSize - 1) &&
|
|
(BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT) &&
|
|
BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
FoundBreakPoint = BreakPointBuffer.at(i);
|
|
bFoundBreakPoint = true;
|
|
break;
|
|
}
|
|
}
|
|
if(bFoundBreakPoint) //breakpoint found
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, &FoundBreakPoint.OriginalByte[0], FoundBreakPoint.BreakPointSize, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
DBGCode = DBG_CONTINUE;
|
|
hActiveThread = EngineOpenThread(THREAD_GETSETSUSPEND, false, DBGEvent.dwThreadId);
|
|
myDBGContext.ContextFlags = CONTEXT_CONTROL;
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
if(FoundBreakPoint.BreakPointType != UE_SINGLESHOOT)
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
#if defined(_WIN64)
|
|
myDBGContext.Rip = myDBGContext.Rip - FoundBreakPoint.BreakPointSize;
|
|
#else
|
|
myDBGContext.Eip = myDBGContext.Eip - FoundBreakPoint.BreakPointSize;
|
|
#endif
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
EngineCloseHandle(hActiveThread);
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
ULONG_PTR ueCurrentPosition = FoundBreakPoint.BreakPointAddress;
|
|
unsigned char instr[16];
|
|
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
|
|
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
|
|
if(strstr(DisassembledString, "PUSHF"))
|
|
PushfBPX = true;
|
|
|
|
if(FoundBreakPoint.BreakPointType == UE_SINGLESHOOT)
|
|
{
|
|
DeleteBPX((ULONG_PTR)FoundBreakPoint.BreakPointAddress);
|
|
ResetBPXSize = FoundBreakPoint.BreakPointSize - 1;
|
|
ResetBPXAddressTo = NULL;
|
|
ResetBPX = false;
|
|
}
|
|
|
|
//execute callback
|
|
myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)FoundBreakPoint.ExecuteCallBack);
|
|
myCustomBreakPoint();
|
|
|
|
if(FoundBreakPoint.BreakPointType != UE_SINGLESHOOT)
|
|
{
|
|
DisableBPX((ULONG_PTR)FoundBreakPoint.BreakPointAddress);
|
|
ResetBPXSize = FoundBreakPoint.BreakPointSize - 1;
|
|
ResetBPXAddressTo = (ULONG_PTR)FoundBreakPoint.BreakPointAddress;
|
|
ResetBPX = true;
|
|
}
|
|
}
|
|
else
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
}
|
|
else //breakpoint not in list
|
|
{
|
|
if(DebugAttachedToProcess || !FirstBPX) //program generated a breakpoint exception
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
if(DBGCustomHandler->chBreakPoint != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chBreakPoint);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
else //system breakpoint
|
|
{
|
|
FirstBPX = false;
|
|
DBGCode = DBG_CONTINUE;
|
|
if(engineAutoHideFromDebugger)
|
|
{
|
|
HideDebugger(dbgProcessInformation.hProcess, UE_HIDE_PEBONLY);
|
|
}
|
|
if(DebugExeFileEntryPointCallBack != NULL) //set entry breakpoint
|
|
{
|
|
SetBPX((ULONG_PTR)DBGEntryPoint, UE_SINGLESHOOT, DebugExeFileEntryPointCallBack);
|
|
}
|
|
if(engineTLSBreakOnCallBack) //set TLS callback breakpoints
|
|
{
|
|
for(unsigned int i = 0; i < tlsCallBackList.size(); i++)
|
|
SetBPX(tlsCallBackList.at(i), UE_SINGLESHOOT, (LPVOID)engineTLSBreakOnCallBackAddress);
|
|
ClearTlsCallBackList();
|
|
engineTLSBreakOnCallBackAddress = NULL;
|
|
engineTLSBreakOnCallBack = false;
|
|
}
|
|
|
|
//system breakpoint callback
|
|
if(DBGCustomHandler->chSystemBreakpoint != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chSystemBreakpoint);
|
|
myCustomHandler(&DBGEvent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_SINGLE_STEP:
|
|
{
|
|
if(ResetBPX == true || ResetHwBPX == true || ResetMemBPX == true) //restore breakpoints (internal step)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
if(PushfBPX) //remove trap flag from stack
|
|
{
|
|
PushfBPX = false;
|
|
void* csp = (void*)GetContextData(UE_CSP);
|
|
ULONG_PTR data = 0;
|
|
ReadProcessMemory(dbgProcessInformation.hProcess, csp, &data, sizeof(ULONG_PTR), 0);
|
|
data &= ~UE_TRAP_FLAG;
|
|
WriteProcessMemory(dbgProcessInformation.hProcess, csp, &data, sizeof(ULONG_PTR), 0);
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
}
|
|
if(ResetBPX) //restore 'normal' breakpoint
|
|
{
|
|
if(ResetBPXAddressTo + ResetBPXSize != (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress)
|
|
{
|
|
EnableBPX(ResetBPXAddressTo);
|
|
ResetBPXAddressTo = NULL;
|
|
ResetBPX = false;
|
|
if(engineStepActive)
|
|
{
|
|
if(engineStepCount == 0)
|
|
{
|
|
myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack);
|
|
engineStepActive = false;
|
|
engineStepCallBack = NULL;
|
|
myCustomBreakPoint();
|
|
}
|
|
else
|
|
{
|
|
SingleStep(engineStepCount, engineStepCallBack);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hActiveThread = EngineOpenThread(THREAD_GETSETSUSPEND, false, DBGEvent.dwThreadId);
|
|
myDBGContext.ContextFlags = CONTEXT_CONTROL;
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
EngineCloseHandle(hActiveThread);
|
|
}
|
|
}
|
|
if(ResetHwBPX) //restore hardware breakpoint
|
|
{
|
|
ResetHwBPX = false;
|
|
SetHardwareBreakPoint(DebugRegisterX.DrxBreakAddress, DebugRegisterXId, DebugRegisterX.DrxBreakPointType, DebugRegisterX.DrxBreakPointSize, (LPVOID)DebugRegisterX.DrxCallBack);
|
|
if(engineStepActive)
|
|
{
|
|
if(engineStepCount == 0)
|
|
{
|
|
myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack);
|
|
engineStepActive = false;
|
|
engineStepCallBack = NULL;
|
|
myCustomBreakPoint();
|
|
}
|
|
else
|
|
{
|
|
SingleStep(engineStepCount, engineStepCallBack);
|
|
}
|
|
}
|
|
}
|
|
if(ResetMemBPX) //restore memory breakpoint
|
|
{
|
|
ResetMemBPX = false;
|
|
|
|
// Check if the alternative memory breakpoint method should be used
|
|
if (engineMembpAlt)
|
|
{
|
|
// Check if the breakpoint is still enabled/present and has not been removed
|
|
for(int i = 0; i < BreakPointBuffer.size(); i++)
|
|
{
|
|
if (BreakPointBuffer.at(i).BreakPointAddress == ResetMemBPXAddress &&
|
|
(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) &&
|
|
BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
// Restore the breakpoint
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)ResetMemBPXAddress,
|
|
ResetMemBPXSize, PAGE_NOACCESS, &OldProtect);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VirtualQueryEx(dbgProcessInformation.hProcess, (LPCVOID)ResetMemBPXAddress, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION));
|
|
OldProtect = MemInfo.Protect;
|
|
NewProtect = OldProtect | PAGE_GUARD; //guard page protection
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)ResetMemBPXAddress, ResetMemBPXSize, NewProtect, &OldProtect);
|
|
}
|
|
|
|
if(engineStepActive)
|
|
{
|
|
if(engineStepCount == 0)
|
|
{
|
|
myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack);
|
|
engineStepActive = false;
|
|
engineStepCallBack = NULL;
|
|
myCustomBreakPoint();
|
|
}
|
|
else
|
|
{
|
|
SingleStep(engineStepCount, engineStepCallBack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else //no resetting needed (debugger reached hardware breakpoint or the user stepped)
|
|
{
|
|
//handle hardware breakpoints
|
|
hActiveThread = EngineOpenThread(THREAD_GETSETSUSPEND, false, DBGEvent.dwThreadId);
|
|
myDBGContext.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL;
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr0 || (myDBGContext.Dr6 & 0x1))
|
|
{
|
|
if(DebugRegister[0].DrxEnabled)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
myCustomHandler = (fCustomHandler)(DebugRegister[0].DrxCallBack);
|
|
myCustomHandler((void*)myDBGContext.Dr0);
|
|
if(DebugRegister[0].DrxEnabled)
|
|
{
|
|
memcpy(&DebugRegisterX, &DebugRegister[0], sizeof(HARDWARE_DATA));
|
|
DebugRegisterXId = UE_DR0;
|
|
DeleteHardwareBreakPoint(UE_DR0);
|
|
ResetHwBPX = true;
|
|
}
|
|
else
|
|
{
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
myDBGContext.EFlags &= ~UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
}
|
|
else if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr1 || (myDBGContext.Dr6 & 0x2))
|
|
{
|
|
if(DebugRegister[1].DrxEnabled)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
myCustomHandler = (fCustomHandler)(DebugRegister[1].DrxCallBack);
|
|
myCustomHandler((void*)myDBGContext.Dr1);
|
|
if(DebugRegister[1].DrxEnabled)
|
|
{
|
|
memcpy(&DebugRegisterX, &DebugRegister[1], sizeof(HARDWARE_DATA));
|
|
DebugRegisterXId = UE_DR1;
|
|
DeleteHardwareBreakPoint(UE_DR1);
|
|
ResetHwBPX = true;
|
|
}
|
|
else
|
|
{
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
myDBGContext.EFlags &= ~UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
}
|
|
else if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr2 || (myDBGContext.Dr6 & 0x4))
|
|
{
|
|
if(DebugRegister[2].DrxEnabled)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
myCustomHandler = (fCustomHandler)(DebugRegister[2].DrxCallBack);
|
|
myCustomHandler((void*)myDBGContext.Dr2);
|
|
if(DebugRegister[2].DrxEnabled)
|
|
{
|
|
memcpy(&DebugRegisterX, &DebugRegister[2], sizeof(HARDWARE_DATA));
|
|
DebugRegisterXId = UE_DR2;
|
|
DeleteHardwareBreakPoint(UE_DR2);
|
|
ResetHwBPX = true;
|
|
}
|
|
else
|
|
{
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
myDBGContext.EFlags &= ~UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
}
|
|
else if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr3 || (myDBGContext.Dr6 & 0x8))
|
|
{
|
|
if(DebugRegister[3].DrxEnabled)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
myCustomHandler = (fCustomHandler)(DebugRegister[3].DrxCallBack);
|
|
myCustomHandler((void*)myDBGContext.Dr3);
|
|
if(DebugRegister[3].DrxEnabled)
|
|
{
|
|
memcpy(&DebugRegisterX, &DebugRegister[3], sizeof(HARDWARE_DATA));
|
|
DebugRegisterXId = UE_DR3;
|
|
DeleteHardwareBreakPoint(UE_DR3);
|
|
ResetHwBPX = true;
|
|
}
|
|
else
|
|
{
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
myDBGContext.EFlags &= ~UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
}
|
|
else //debuggee generated exception
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
EngineCloseHandle(hActiveThread);
|
|
if(ResetHwBPX) //a hardware breakpoint was reached
|
|
{
|
|
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
|
|
unsigned char instr[16];
|
|
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
|
|
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
|
|
if(strstr(DisassembledString, "PUSHF"))
|
|
PushfBPX = true;
|
|
}
|
|
if(engineStepActive)
|
|
{
|
|
DBGCode = DBG_CONTINUE;
|
|
if(engineStepCount == 0)
|
|
{
|
|
myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack);
|
|
engineStepActive = false;
|
|
engineStepCallBack = NULL;
|
|
myCustomBreakPoint();
|
|
}
|
|
else
|
|
{
|
|
SingleStep(engineStepCount, engineStepCallBack);
|
|
}
|
|
}
|
|
}
|
|
if(DBGCode == DBG_EXCEPTION_NOT_HANDLED) //NOTE: only call the chSingleStep callback when the debuggee generated the exception
|
|
{
|
|
if(DBGCustomHandler->chSingleStep != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chSingleStep);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_GUARD_PAGE_VIOLATION:
|
|
{
|
|
ULONG_PTR bpaddr;
|
|
bool bFoundBreakPoint = false;
|
|
BreakPointDetail FoundBreakPoint;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
ULONG_PTR addr = BreakPointBuffer.at(i).BreakPointAddress;
|
|
bpaddr = (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[1]; //page accessed
|
|
if(bpaddr >= addr && bpaddr < (addr + BreakPointBuffer.at(i).BreakPointSize) &&
|
|
(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) &&
|
|
BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
FoundBreakPoint = BreakPointBuffer.at(i);
|
|
bFoundBreakPoint = true;
|
|
break;
|
|
}
|
|
}
|
|
if(bFoundBreakPoint) //found memory breakpoint
|
|
{
|
|
hActiveThread = EngineOpenThread(THREAD_GETSETSUSPEND, false, DBGEvent.dwThreadId);
|
|
myDBGContext.ContextFlags = CONTEXT_CONTROL;
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
DBGCode = DBG_CONTINUE; //debugger handled the exception
|
|
MemoryBpxCallBack = FoundBreakPoint.ExecuteCallBack;
|
|
if(FoundBreakPoint.BreakPointType == UE_MEMORY) //READ|WRITE|EXECUTE
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1)
|
|
{
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
myCustomHandler = (fCustomHandler)(MemoryBpxCallBack);
|
|
myCustomHandler((void*)bpaddr);
|
|
}
|
|
else if(FoundBreakPoint.BreakPointType == UE_MEMORY_READ) //READ
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1) //do not restore the memory breakpoint
|
|
{
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) //read operation
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else //restore the memory breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) //read operation
|
|
{
|
|
myCustomHandler = (fCustomHandler)(MemoryBpxCallBack);
|
|
myCustomHandler((void*)bpaddr);
|
|
}
|
|
else //no read operation, restore breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
}
|
|
else if(FoundBreakPoint.BreakPointType == UE_MEMORY_WRITE) //WRITE
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1) //remove breakpoint
|
|
{
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 1) //write operation
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else //restore breakpoint after trap flag
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 1) //write operation
|
|
{
|
|
myCustomHandler = (fCustomHandler)(MemoryBpxCallBack);
|
|
myCustomHandler((void*)bpaddr);
|
|
}
|
|
else //no write operation, restore breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
}
|
|
else if(FoundBreakPoint.BreakPointType == UE_MEMORY_EXECUTE) //EXECUTE
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1)
|
|
{
|
|
if((DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 8 || DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) && //data execution prevention (DEP) violation
|
|
(ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[1]) //exception address == read address
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
if((DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 8 || DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) && //data execution prevention (DEP) violation
|
|
(ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[1]) //exception address == read address
|
|
{
|
|
myCustomHandler = (fCustomHandler)(MemoryBpxCallBack);
|
|
myCustomHandler((void*)bpaddr);
|
|
}
|
|
else //no execute operation, restore breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
}
|
|
EngineCloseHandle(hActiveThread);
|
|
}
|
|
else //no memory breakpoint found
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
if(ResetMemBPX) //memory breakpoint hit
|
|
{
|
|
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
|
|
unsigned char instr[16];
|
|
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
|
|
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
|
|
if(strstr(DisassembledString, "PUSHF"))
|
|
PushfBPX = true;
|
|
}
|
|
|
|
//debuggee generated GUARD_PAGE exception
|
|
if(DBGCode == DBG_EXCEPTION_NOT_HANDLED)
|
|
{
|
|
//TODO: restore memory breakpoint?
|
|
if(DBGCustomHandler->chPageGuard != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chPageGuard);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_ACCESS_VIOLATION:
|
|
{
|
|
ULONG_PTR bpaddr;
|
|
bool bFoundBreakPoint = false;
|
|
bool bCallCustomHandler = false;
|
|
BreakPointDetail FoundBreakPoint;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
ULONG_PTR addr = BreakPointBuffer.at(i).BreakPointAddress;
|
|
bpaddr = (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[1]; //page accessed
|
|
if(bpaddr >= addr && bpaddr < (addr + BreakPointBuffer.at(i).BreakPointSize) &&
|
|
(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) &&
|
|
BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
FoundBreakPoint = BreakPointBuffer.at(i);
|
|
bFoundBreakPoint = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Most of the logic has been copied from the STATUS_GUARD_PAGE_VIOLATION handler
|
|
|
|
if(bFoundBreakPoint && engineMembpAlt) //found memory breakpoint
|
|
{
|
|
hActiveThread = EngineOpenThread(THREAD_GETSETSUSPEND, false, DBGEvent.dwThreadId);
|
|
myDBGContext.ContextFlags = CONTEXT_CONTROL;
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
DBGCode = DBG_CONTINUE; //debugger handled the exception
|
|
MemoryBpxCallBack = FoundBreakPoint.ExecuteCallBack;
|
|
|
|
if(FoundBreakPoint.BreakPointType == UE_MEMORY) //READ|WRITE|EXECUTE
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1)
|
|
{
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
|
|
bCallCustomHandler = true;
|
|
}
|
|
else if(FoundBreakPoint.BreakPointType == UE_MEMORY_READ) //READ
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1) //do not restore the memory breakpoint
|
|
{
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) //read operation
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else //restore the memory breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) //read operation
|
|
{
|
|
bCallCustomHandler = true;
|
|
}
|
|
else //no read operation, restore breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
}
|
|
else if(FoundBreakPoint.BreakPointType == UE_MEMORY_WRITE) //WRITE
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1) //remove breakpoint
|
|
{
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 1) //write operation
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else //restore breakpoint after trap flag
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 1) //write operation
|
|
{
|
|
bCallCustomHandler = true;
|
|
}
|
|
else //no write operation, restore breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
}
|
|
else if(FoundBreakPoint.BreakPointType == UE_MEMORY_EXECUTE) //EXECUTE
|
|
{
|
|
if(FoundBreakPoint.MemoryBpxRestoreOnHit != 1)
|
|
{
|
|
if((DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 8 || DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) && //data execution prevention (DEP) violation
|
|
(ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[1]) //exception address == read address
|
|
RemoveMemoryBPX(FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize);
|
|
}
|
|
else
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
if((DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 8 || DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) && //data execution prevention (DEP) violation
|
|
(ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[1]) //exception address == read address
|
|
{
|
|
bCallCustomHandler = true;
|
|
}
|
|
else //no execute operation, restore breakpoint
|
|
{
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
ResetMemBPXAddress = FoundBreakPoint.BreakPointAddress;
|
|
ResetMemBPXSize = FoundBreakPoint.BreakPointSize;
|
|
ResetMemBPX = true;
|
|
}
|
|
}
|
|
|
|
// If the breakpoint has to be restored...
|
|
if (ResetMemBPX)
|
|
{
|
|
// ...temporarily revert the PAGE_NOACCESS permission
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)ResetMemBPXAddress,
|
|
ResetMemBPXSize, FoundBreakPoint.OldProtect, &OldProtect);
|
|
}
|
|
|
|
// Call the custom memory breakpoint handler
|
|
if (bCallCustomHandler)
|
|
{
|
|
myCustomHandler = (fCustomHandler)(MemoryBpxCallBack);
|
|
myCustomHandler((void*)bpaddr);
|
|
}
|
|
|
|
EngineCloseHandle(hActiveThread);
|
|
}
|
|
else //no memory breakpoint found
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
}
|
|
if(ResetMemBPX) //memory breakpoint hit
|
|
{
|
|
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
|
|
unsigned char instr[16];
|
|
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
|
|
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
|
|
if(strstr(DisassembledString, "PUSHF"))
|
|
PushfBPX = true;
|
|
}
|
|
|
|
// Debuggee generated access violation exception
|
|
if(DBGCode == DBG_EXCEPTION_NOT_HANDLED)
|
|
{
|
|
if(DBGCustomHandler->chAccessViolation != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chAccessViolation);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_ILLEGAL_INSTRUCTION:
|
|
{
|
|
//UD2 breakpoint
|
|
bool bFoundBreakPoint = false;
|
|
BreakPointDetail FoundBreakPoint;
|
|
int bpcount = (int)BreakPointBuffer.size();
|
|
for(int i = 0; i < bpcount; i++)
|
|
{
|
|
if(BreakPointBuffer.at(i).BreakPointAddress == (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress &&
|
|
(BreakPointBuffer.at(i).BreakPointType == UE_BREAKPOINT || BreakPointBuffer.at(i).BreakPointType == UE_SINGLESHOOT) &&
|
|
BreakPointBuffer.at(i).BreakPointActive == UE_BPXACTIVE)
|
|
{
|
|
FoundBreakPoint = BreakPointBuffer.at(i);
|
|
bFoundBreakPoint = true;
|
|
break;
|
|
}
|
|
}
|
|
if(bFoundBreakPoint) //found ud2 breakpoint
|
|
{
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, &FoundBreakPoint.OriginalByte[0], FoundBreakPoint.BreakPointSize, &NumberOfBytesReadWritten))
|
|
{
|
|
FlushInstructionCache(dbgProcessInformation.hProcess, NULL, 0);
|
|
DBGCode = DBG_CONTINUE;
|
|
hActiveThread = EngineOpenThread(THREAD_GETSETSUSPEND, false, DBGEvent.dwThreadId);
|
|
myDBGContext.ContextFlags = CONTEXT_CONTROL;
|
|
GetThreadContext(hActiveThread, &myDBGContext);
|
|
if(FoundBreakPoint.BreakPointType != UE_SINGLESHOOT)
|
|
myDBGContext.EFlags |= UE_TRAP_FLAG;
|
|
SetThreadContext(hActiveThread, &myDBGContext);
|
|
EngineCloseHandle(hActiveThread);
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
|
|
if(FoundBreakPoint.BreakPointType == UE_SINGLESHOOT)
|
|
{
|
|
DeleteBPX((ULONG_PTR)FoundBreakPoint.BreakPointAddress);
|
|
ResetBPXSize = FoundBreakPoint.BreakPointSize - 1;
|
|
ResetBPXAddressTo = NULL;
|
|
ResetBPX = false;
|
|
}
|
|
|
|
//execute callback
|
|
myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)FoundBreakPoint.ExecuteCallBack);
|
|
myCustomBreakPoint();
|
|
|
|
if(FoundBreakPoint.BreakPointType != UE_SINGLESHOOT)
|
|
{
|
|
DisableBPX((ULONG_PTR)FoundBreakPoint.BreakPointAddress);
|
|
ResetBPXSize = FoundBreakPoint.BreakPointSize - 1;
|
|
ResetBPXAddressTo = (ULONG_PTR)FoundBreakPoint.BreakPointAddress;
|
|
ResetBPX = true;
|
|
}
|
|
}
|
|
else
|
|
VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)FoundBreakPoint.BreakPointAddress, FoundBreakPoint.BreakPointSize, OldProtect, &OldProtect);
|
|
}
|
|
else
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED;
|
|
|
|
//application-generated exception
|
|
if(DBGCode == DBG_EXCEPTION_NOT_HANDLED)
|
|
{
|
|
if(DBGCustomHandler->chIllegalInstruction != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chIllegalInstruction);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_NONCONTINUABLE_EXCEPTION:
|
|
{
|
|
if(DBGCustomHandler->chNonContinuableException != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chNonContinuableException);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_ARRAY_BOUNDS_EXCEEDED:
|
|
{
|
|
if(DBGCustomHandler->chArrayBoundsException != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chArrayBoundsException);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_FLOAT_DENORMAL_OPERAND:
|
|
{
|
|
if(DBGCustomHandler->chFloatDenormalOperand != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chFloatDenormalOperand);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_FLOAT_DIVIDE_BY_ZERO:
|
|
{
|
|
if(DBGCustomHandler->chFloatDevideByZero != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chFloatDevideByZero);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_INTEGER_DIVIDE_BY_ZERO:
|
|
{
|
|
if(DBGCustomHandler->chIntegerDevideByZero != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chIntegerDevideByZero);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_INTEGER_OVERFLOW:
|
|
{
|
|
if(DBGCustomHandler->chIntegerOverflow != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chIntegerOverflow);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_PRIVILEGED_INSTRUCTION:
|
|
{
|
|
if(DBGCustomHandler->chPrivilegedInstruction != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chPrivilegedInstruction);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
//general unhandled exception callback
|
|
if(DBGCode == DBG_EXCEPTION_NOT_HANDLED)
|
|
{
|
|
if(engineExecutePluginCallBack)
|
|
{
|
|
ExtensionManagerPluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_UNHANDLEDEXCEPTION);
|
|
}
|
|
if(DBGCustomHandler->chUnhandledException != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chUnhandledException);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
|
|
//general after-exception callback (includes debugger exceptions)
|
|
if(DBGCustomHandler->chAfterException != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chAfterException);
|
|
myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RIP_EVENT:
|
|
{
|
|
DBGCode = DBG_EXCEPTION_NOT_HANDLED; //fix an anti-debug trick
|
|
if(engineExecutePluginCallBack)
|
|
{
|
|
ExtensionManagerPluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_UNHANDLEDEXCEPTION);
|
|
}
|
|
//rip event callback
|
|
if(DBGCustomHandler->chRipEvent != NULL)
|
|
{
|
|
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chRipEvent);
|
|
myCustomHandler(&DBGEvent);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(engineResumeProcessIfNoThreadIsActive)
|
|
{
|
|
if(!ThreaderIsAnyThreadActive())
|
|
{
|
|
ThreaderResumeProcess();
|
|
}
|
|
}
|
|
if(!ContinueDebugEvent(DBGEvent.dwProcessId, DBGEvent.dwThreadId, DBGCode)) //continue debugging
|
|
{
|
|
break;
|
|
}
|
|
if(engineProcessIsNowDetached)
|
|
{
|
|
DebugActiveProcessStop(dbgProcessInformation.dwProcessId);
|
|
DebugAttachedToProcess = false;
|
|
break;
|
|
}
|
|
if(!ThreaderGetThreadInfo(0, DBGEvent.dwThreadId)) //switch thread
|
|
DBGEvent.dwThreadId = dbgProcessInformation.dwThreadId;
|
|
}
|
|
|
|
if(!SecondChance) //debugger didn't close with a second chance exception (normal exit)
|
|
{
|
|
RtlMoveMemory(&TerminateDBGEvent, &DBGEvent, sizeof DEBUG_EVENT);
|
|
}
|
|
ForceClose();
|
|
engineFileIsBeingDebugged = false;
|
|
if(engineExecutePluginCallBack)
|
|
{
|
|
ExtensionManagerPluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_POSTDEBUG);
|
|
}
|
|
DebuggerReset();
|
|
}
|
|
|
|
__declspec(dllexport) void TITCALL DebugLoopEx(DWORD TimeOut)
|
|
{
|
|
SetDebugLoopTimeOut(TimeOut);
|
|
DebugLoop();
|
|
SetDebugLoopTimeOut(INFINITE);
|
|
}
|
|
|
|
__declspec(dllexport) void TITCALL SetDebugLoopTimeOut(DWORD TimeOut)
|
|
{
|
|
__debugbreak();
|
|
}
|