mirror of https://github.com/x64dbg/GleeBug
massive cleanup + fixed various code problems
This commit is contained in:
parent
3ce2a318ca
commit
2481e33abd
|
|
@ -3,3 +3,4 @@ Release/
|
||||||
*.suo
|
*.suo
|
||||||
*.sdf
|
*.sdf
|
||||||
*.opensdf
|
*.opensdf
|
||||||
|
*.orig
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
DllInfo::DllInfo()
|
DllInfo::DllInfo()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
DllInfo::DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint)
|
DllInfo::DllInfo(LPVOID lpBaseOfDll, ULONG_PTR sizeOfImage, LPVOID entryPoint)
|
||||||
{
|
{
|
||||||
this->lpBaseOfDll = (ULONG_PTR)lpBaseOfDll;
|
this->lpBaseOfDll = reinterpret_cast<ULONG_PTR>(lpBaseOfDll);
|
||||||
this->sizeOfImage = sizeOfImage;
|
this->sizeOfImage = sizeOfImage;
|
||||||
this->entryPoint = (ULONG_PTR)entryPoint;
|
this->entryPoint = reinterpret_cast<ULONG_PTR>(entryPoint);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -5,29 +5,29 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
\brief DLL information structure.
|
\brief DLL information structure.
|
||||||
*/
|
*/
|
||||||
class DllInfo
|
class DllInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ULONG_PTR lpBaseOfDll;
|
ULONG_PTR lpBaseOfDll;
|
||||||
DWORD sizeOfImage;
|
ULONG_PTR sizeOfImage;
|
||||||
ULONG_PTR entryPoint;
|
ULONG_PTR entryPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Default constructor.
|
\brief Default constructor.
|
||||||
*/
|
*/
|
||||||
DllInfo();
|
DllInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Constructor.
|
\brief Constructor.
|
||||||
\param lpBaseOfDll The base of DLL.
|
\param lpBaseOfDll The base of DLL.
|
||||||
\param sizeOfImage Size of the image.
|
\param sizeOfImage Size of the image.
|
||||||
\param entryPoint The entry point.
|
\param entryPoint The entry point.
|
||||||
*/
|
*/
|
||||||
DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint);
|
DllInfo(LPVOID lpBaseOfDll, ULONG_PTR sizeOfImage, LPVOID entryPoint);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_DEBUGGER_DLL_H
|
#endif //_DEBUGGER_DLL_H
|
||||||
|
|
@ -14,35 +14,35 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
typedef std::pair<ULONG_PTR, ULONG_PTR> Range;
|
typedef std::pair<ULONG_PTR, ULONG_PTR> Range;
|
||||||
|
|
||||||
struct RangeCompare
|
struct RangeCompare
|
||||||
{
|
{
|
||||||
inline bool operator()(const Range & a, const Range & b) const //a before b?
|
inline bool operator()(const Range & a, const Range & b) const //a before b?
|
||||||
{
|
{
|
||||||
return a.second < b.first;
|
return a.second < b.first;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//forward declarations
|
//forward declarations
|
||||||
class Debugger;
|
class Debugger;
|
||||||
class ProcessInfo;
|
class ProcessInfo;
|
||||||
class DllInfo;
|
class DllInfo;
|
||||||
class ThreadInfo;
|
class ThreadInfo;
|
||||||
|
|
||||||
//map typedefs
|
//map typedefs
|
||||||
typedef std::map<DWORD, ProcessInfo> ProcessMap;
|
typedef std::map<DWORD, ProcessInfo> ProcessMap;
|
||||||
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
|
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
|
||||||
typedef std::map<DWORD, ThreadInfo> ThreadMap;
|
typedef std::map<DWORD, ThreadInfo> ThreadMap;
|
||||||
|
|
||||||
//callback function typedefs
|
|
||||||
typedef std::function<void()> StepCallback;
|
|
||||||
|
|
||||||
//vector typedefs
|
//callback function typedefs
|
||||||
typedef std::vector<StepCallback> StepCallbackVector;
|
typedef std::function<void()> StepCallback;
|
||||||
|
|
||||||
//macros
|
//vector typedefs
|
||||||
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
|
typedef std::vector<StepCallback> StepCallbackVector;
|
||||||
|
|
||||||
|
//macros
|
||||||
|
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_DEBUGGER_GLOBAL_H
|
#endif //_DEBUGGER_GLOBAL_H
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
|
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
|
||||||
{
|
{
|
||||||
//prevent anti-debug trick (debug string events are actually exceptions)
|
//prevent anti-debug trick (debug string events are actually exceptions)
|
||||||
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbDebugStringEvent(debugString);
|
cbDebugStringEvent(debugString);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,37 +2,37 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
|
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
|
||||||
{
|
{
|
||||||
//DLL housekeeping
|
//DLL housekeeping
|
||||||
MODULEINFO modinfo;
|
MODULEINFO modinfo;
|
||||||
memset(&modinfo, 0, sizeof(MODULEINFO));
|
memset(&modinfo, 0, sizeof(MODULEINFO));
|
||||||
GetModuleInformation(_process->hProcess,
|
GetModuleInformation(_process->hProcess,
|
||||||
(HMODULE)loadDll.lpBaseOfDll,
|
reinterpret_cast<HMODULE>(loadDll.lpBaseOfDll),
|
||||||
&modinfo,
|
&modinfo,
|
||||||
sizeof(MODULEINFO));
|
sizeof(MODULEINFO));
|
||||||
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
|
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
|
||||||
_process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
|
_process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbLoadDllEvent(loadDll, dll);
|
cbLoadDllEvent(loadDll, dll);
|
||||||
|
|
||||||
//close the file handle
|
//close the file handle
|
||||||
CloseHandle(loadDll.hFile);
|
CloseHandle(loadDll.hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
|
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
|
||||||
{
|
{
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll;
|
ULONG_PTR lpBaseOfDll = reinterpret_cast<ULONG_PTR>(unloadDll.lpBaseOfDll);
|
||||||
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
|
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
|
||||||
if (dll != _process->dlls.end())
|
if (dll != _process->dlls.end())
|
||||||
cbUnloadDllEvent(unloadDll, dll->second);
|
cbUnloadDllEvent(unloadDll, dll->second);
|
||||||
else
|
else
|
||||||
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0));
|
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, nullptr));
|
||||||
|
|
||||||
//DLL housekeeping
|
//DLL housekeeping
|
||||||
if (dll != _process->dlls.end())
|
if (dll != _process->dlls.end())
|
||||||
_process->dlls.erase(dll);
|
_process->dlls.erase(dll);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,64 +2,61 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
||||||
{
|
{
|
||||||
if (!_process->systemBreakpoint) //handle system breakpoint
|
if (!_process->systemBreakpoint) //handle system breakpoint
|
||||||
{
|
{
|
||||||
_process->systemBreakpoint = true;
|
_process->systemBreakpoint = true;
|
||||||
_continueStatus = DBG_CONTINUE;
|
_continueStatus = DBG_CONTINUE;
|
||||||
|
|
||||||
//call the callback
|
//call the callback
|
||||||
cbSystemBreakpoint();
|
cbSystemBreakpoint();
|
||||||
}
|
}
|
||||||
else //handle other breakpoint exceptions
|
}
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
||||||
{
|
{
|
||||||
if (_thread->isSingleStepping) //handle single step
|
if (_thread->isSingleStepping) //handle single step
|
||||||
{
|
{
|
||||||
_thread->isSingleStepping = false;
|
_thread->isSingleStepping = false;
|
||||||
_continueStatus = DBG_CONTINUE;
|
_continueStatus = DBG_CONTINUE;
|
||||||
|
|
||||||
//call the callbacks
|
//call the callbacks
|
||||||
StepCallbackVector cbStepCopy = _thread->stepCallbacks;
|
StepCallbackVector cbStepCopy = _thread->stepCallbacks;
|
||||||
_thread->stepCallbacks.clear();
|
_thread->stepCallbacks.clear();
|
||||||
for (auto cbStep : cbStepCopy)
|
for (auto cbStep : cbStepCopy)
|
||||||
cbStep();
|
cbStep();
|
||||||
cbStep();
|
cbStep();
|
||||||
}
|
}
|
||||||
else //handle other single step exceptions
|
else //handle other single step exceptions
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||||
{
|
{
|
||||||
//let the debuggee handle exceptions per default
|
//let the debuggee handle exceptions per default
|
||||||
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
|
|
||||||
const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord;
|
const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord;
|
||||||
const bool firstChance = exceptionInfo.dwFirstChance == 1;
|
const bool firstChance = exceptionInfo.dwFirstChance == 1;
|
||||||
|
|
||||||
//dispatch the exception
|
//dispatch the exception
|
||||||
switch (exceptionInfo.ExceptionRecord.ExceptionCode)
|
switch (exceptionInfo.ExceptionRecord.ExceptionCode)
|
||||||
{
|
{
|
||||||
case STATUS_BREAKPOINT:
|
case STATUS_BREAKPOINT:
|
||||||
exceptionBreakpoint(exceptionRecord, firstChance);
|
exceptionBreakpoint(exceptionRecord, firstChance);
|
||||||
break;
|
break;
|
||||||
case STATUS_SINGLE_STEP:
|
case STATUS_SINGLE_STEP:
|
||||||
exceptionSingleStep(exceptionRecord, firstChance);
|
exceptionSingleStep(exceptionRecord, firstChance);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//call the unhandled exception callback
|
//call the unhandled exception callback
|
||||||
if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED)
|
if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED)
|
||||||
cbUnhandledException(exceptionRecord, firstChance);
|
cbUnhandledException(exceptionRecord, firstChance);
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbExceptionEvent(exceptionInfo);
|
cbExceptionEvent(exceptionInfo);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,47 +2,47 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
|
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
|
||||||
{
|
{
|
||||||
//process housekeeping
|
//process housekeeping
|
||||||
ProcessInfo process(_debugEvent.dwProcessId,
|
ProcessInfo process(_debugEvent.dwProcessId,
|
||||||
createProcess.hProcess,
|
createProcess.hProcess,
|
||||||
_debugEvent.dwThreadId);
|
_debugEvent.dwThreadId);
|
||||||
_processes.insert({ process.dwProcessId, process });
|
_processes.insert({ process.dwProcessId, process });
|
||||||
_process = &_processes.find(process.dwProcessId)->second;
|
_process = &_processes.find(process.dwProcessId)->second;
|
||||||
|
|
||||||
//thread housekeeping (main thread is created implicitly)
|
//thread housekeeping (main thread is created implicitly)
|
||||||
ThreadInfo thread(_debugEvent.dwThreadId,
|
ThreadInfo thread(_debugEvent.dwThreadId,
|
||||||
createProcess.hThread,
|
createProcess.hThread,
|
||||||
createProcess.lpThreadLocalBase,
|
createProcess.lpThreadLocalBase,
|
||||||
createProcess.lpStartAddress);
|
createProcess.lpStartAddress);
|
||||||
_process->threads.insert({ thread.dwThreadId, thread });
|
_process->threads.insert({ thread.dwThreadId, thread });
|
||||||
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
|
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
|
||||||
|
|
||||||
//read thread context from main thread
|
//read thread context from main thread
|
||||||
if (!_thread->RegReadContext())
|
if (!_thread->RegReadContext())
|
||||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbCreateProcessEvent(createProcess, *_process);
|
cbCreateProcessEvent(createProcess, *_process);
|
||||||
|
|
||||||
//close the file handle
|
//close the file handle
|
||||||
CloseHandle(createProcess.hFile);
|
CloseHandle(createProcess.hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
|
if (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
|
||||||
_breakDebugger = true;
|
_breakDebugger = true;
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbExitProcessEvent(exitProcess, *_process);
|
cbExitProcessEvent(exitProcess, *_process);
|
||||||
|
|
||||||
//process housekeeping
|
//process housekeeping
|
||||||
_processes.erase(_debugEvent.dwProcessId);
|
_processes.erase(_debugEvent.dwProcessId);
|
||||||
|
|
||||||
//set the current process
|
//set the current process
|
||||||
_process = nullptr;
|
_process = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::ripEvent(const RIP_INFO & rip)
|
void Debugger::ripEvent(const RIP_INFO & rip)
|
||||||
{
|
{
|
||||||
//prevent anti-debug trick (RIP events are actually exceptions)
|
//prevent anti-debug trick (RIP events are actually exceptions)
|
||||||
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbRipEvent(rip);
|
cbRipEvent(rip);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,30 +2,30 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
|
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
|
||||||
{
|
{
|
||||||
//thread housekeeping
|
//thread housekeeping
|
||||||
_process->threads.insert({ _debugEvent.dwThreadId,
|
_process->threads.insert({ _debugEvent.dwThreadId,
|
||||||
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
|
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
|
||||||
|
|
||||||
//set the current thread
|
//set the current thread
|
||||||
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
|
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
|
||||||
if (!_thread->RegReadContext())
|
if (!_thread->RegReadContext())
|
||||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
||||||
|
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbCreateThreadEvent(createThread, *_thread);
|
cbCreateThreadEvent(createThread, *_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
|
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
|
||||||
{
|
{
|
||||||
//call the debug event callback
|
//call the debug event callback
|
||||||
cbExitThreadEvent(exitThread, *_thread);
|
cbExitThreadEvent(exitThread, *_thread);
|
||||||
|
|
||||||
//thread housekeeping
|
//thread housekeeping
|
||||||
_process->threads.erase(_debugEvent.dwThreadId);
|
_process->threads.erase(_debugEvent.dwThreadId);
|
||||||
|
|
||||||
//set the current thread
|
//set the current thread
|
||||||
_thread = _process->thread = nullptr;
|
_thread = _process->thread = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,84 +2,84 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
void Debugger::Start()
|
void Debugger::Start()
|
||||||
{
|
{
|
||||||
//initialize loop variables
|
//initialize loop variables
|
||||||
_breakDebugger = false;
|
_breakDebugger = false;
|
||||||
|
|
||||||
while (!_breakDebugger)
|
while (!_breakDebugger)
|
||||||
{
|
{
|
||||||
//wait for a debug event
|
//wait for a debug event
|
||||||
_isRunning = true;
|
_isRunning = true;
|
||||||
if (!WaitForDebugEvent(&_debugEvent, INFINITE))
|
if (!WaitForDebugEvent(&_debugEvent, INFINITE))
|
||||||
break;
|
break;
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
|
|
||||||
//set default continue status
|
//set default continue status
|
||||||
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
|
|
||||||
//set the current process and thread
|
//set the current process and thread
|
||||||
if (_processes.count(_debugEvent.dwProcessId))
|
if (_processes.count(_debugEvent.dwProcessId))
|
||||||
{
|
{
|
||||||
_process = &_processes[_debugEvent.dwProcessId];
|
_process = &_processes[_debugEvent.dwProcessId];
|
||||||
if (_process->threads.count(_debugEvent.dwThreadId))
|
if (_process->threads.count(_debugEvent.dwThreadId))
|
||||||
{
|
{
|
||||||
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
|
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
|
||||||
if (!_thread->RegReadContext())
|
if (!_thread->RegReadContext())
|
||||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_thread = _process->thread = nullptr;
|
_thread = _process->thread = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_process = nullptr;
|
_process = nullptr;
|
||||||
|
|
||||||
//dispatch the debug event
|
//dispatch the debug event
|
||||||
switch (_debugEvent.dwDebugEventCode)
|
switch (_debugEvent.dwDebugEventCode)
|
||||||
{
|
{
|
||||||
case CREATE_PROCESS_DEBUG_EVENT:
|
case CREATE_PROCESS_DEBUG_EVENT:
|
||||||
createProcessEvent(_debugEvent.u.CreateProcessInfo);
|
createProcessEvent(_debugEvent.u.CreateProcessInfo);
|
||||||
break;
|
break;
|
||||||
case EXIT_PROCESS_DEBUG_EVENT:
|
case EXIT_PROCESS_DEBUG_EVENT:
|
||||||
exitProcessEvent(_debugEvent.u.ExitProcess);
|
exitProcessEvent(_debugEvent.u.ExitProcess);
|
||||||
break;
|
break;
|
||||||
case CREATE_THREAD_DEBUG_EVENT:
|
case CREATE_THREAD_DEBUG_EVENT:
|
||||||
createThreadEvent(_debugEvent.u.CreateThread);
|
createThreadEvent(_debugEvent.u.CreateThread);
|
||||||
break;
|
break;
|
||||||
case EXIT_THREAD_DEBUG_EVENT:
|
case EXIT_THREAD_DEBUG_EVENT:
|
||||||
exitThreadEvent(_debugEvent.u.ExitThread);
|
exitThreadEvent(_debugEvent.u.ExitThread);
|
||||||
break;
|
break;
|
||||||
case LOAD_DLL_DEBUG_EVENT:
|
case LOAD_DLL_DEBUG_EVENT:
|
||||||
loadDllEvent(_debugEvent.u.LoadDll);
|
loadDllEvent(_debugEvent.u.LoadDll);
|
||||||
break;
|
break;
|
||||||
case UNLOAD_DLL_DEBUG_EVENT:
|
case UNLOAD_DLL_DEBUG_EVENT:
|
||||||
unloadDllEvent(_debugEvent.u.UnloadDll);
|
unloadDllEvent(_debugEvent.u.UnloadDll);
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_DEBUG_EVENT:
|
case EXCEPTION_DEBUG_EVENT:
|
||||||
exceptionEvent(_debugEvent.u.Exception);
|
exceptionEvent(_debugEvent.u.Exception);
|
||||||
break;
|
break;
|
||||||
case OUTPUT_DEBUG_STRING_EVENT:
|
case OUTPUT_DEBUG_STRING_EVENT:
|
||||||
debugStringEvent(_debugEvent.u.DebugString);
|
debugStringEvent(_debugEvent.u.DebugString);
|
||||||
break;
|
break;
|
||||||
case RIP_EVENT:
|
case RIP_EVENT:
|
||||||
ripEvent(_debugEvent.u.RipInfo);
|
ripEvent(_debugEvent.u.RipInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//write the register context
|
//write the register context
|
||||||
if (_thread)
|
if (_thread)
|
||||||
{
|
{
|
||||||
if (!_thread->RegWriteContext())
|
if (!_thread->RegWriteContext())
|
||||||
cbInternalError("ThreadInfo::RegWriteContext() failed!");
|
cbInternalError("ThreadInfo::RegWriteContext() failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
//continue the debug event
|
//continue the debug event
|
||||||
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
|
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
_processes.clear();
|
_processes.clear();
|
||||||
_process = nullptr;
|
_process = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -2,28 +2,28 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
ProcessInfo::ProcessInfo()
|
ProcessInfo::ProcessInfo()
|
||||||
{
|
{
|
||||||
this->thread = nullptr;
|
this->thread = nullptr;
|
||||||
this->systemBreakpoint = false;
|
this->systemBreakpoint = false;
|
||||||
this->hProcess = INVALID_HANDLE_VALUE;
|
this->hProcess = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId)
|
ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId)
|
||||||
{
|
{
|
||||||
this->systemBreakpoint = false;
|
this->systemBreakpoint = false;
|
||||||
this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
||||||
this->dwProcessId = dwProcessId;
|
this->dwProcessId = dwProcessId;
|
||||||
this->dwMainThreadId = dwMainThreadId;
|
this->dwMainThreadId = dwMainThreadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
|
bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
|
||||||
{
|
{
|
||||||
return !!ReadProcessMemory(this->hProcess, (const void*)address, buffer, size, NULL);
|
return !!ReadProcessMemory(this->hProcess, reinterpret_cast<const void*>(address), buffer, size, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer)
|
bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer)
|
||||||
{
|
{
|
||||||
return !!WriteProcessMemory(this->hProcess, (void*)address, buffer, size, NULL);
|
return !!WriteProcessMemory(this->hProcess, reinterpret_cast<void*>(address), buffer, size, nullptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -7,52 +7,52 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
\brief Process information structure.
|
\brief Process information structure.
|
||||||
*/
|
*/
|
||||||
class ProcessInfo
|
class ProcessInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HANDLE hProcess;
|
HANDLE hProcess;
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
DWORD dwMainThreadId;
|
DWORD dwMainThreadId;
|
||||||
|
|
||||||
ThreadInfo* thread;
|
ThreadInfo* thread;
|
||||||
bool systemBreakpoint;
|
bool systemBreakpoint;
|
||||||
|
|
||||||
ThreadMap threads;
|
ThreadMap threads;
|
||||||
DllMap dlls;
|
DllMap dlls;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Default constructor.
|
\brief Default constructor.
|
||||||
*/
|
*/
|
||||||
ProcessInfo();
|
ProcessInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Constructor.
|
\brief Constructor.
|
||||||
\param dwProcessId Identifier for the process.
|
\param dwProcessId Identifier for the process.
|
||||||
\param dwMainThreadId Identifier for the main thread.
|
\param dwMainThreadId Identifier for the main thread.
|
||||||
*/
|
*/
|
||||||
ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId);
|
ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Read memory from the process.
|
\brief Read memory from the process.
|
||||||
\param address The virtual address to read from.
|
\param address The virtual address to read from.
|
||||||
\param size The size to read.
|
\param size The size to read.
|
||||||
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
|
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
|
||||||
\return true if it succeeds, false if it fails.
|
\return true if it succeeds, false if it fails.
|
||||||
*/
|
*/
|
||||||
bool MemRead(ULONG_PTR address, const size_t size, void* buffer);
|
bool MemRead(ULONG_PTR address, const size_t size, void* buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Write memory to the process.
|
\brief Write memory to the process.
|
||||||
\param address The virtual address to write to.
|
\param address The virtual address to write to.
|
||||||
\param size The size to write.
|
\param size The size to write.
|
||||||
\param [in] buffer Source buffer. Cannot be null.
|
\param [in] buffer Source buffer. Cannot be null.
|
||||||
\return true if it succeeds, false if it fails.
|
\return true if it succeeds, false if it fails.
|
||||||
*/
|
*/
|
||||||
bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer);
|
bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_DEBUGGER_PROCESS_H
|
#endif //_DEBUGGER_PROCESS_H
|
||||||
|
|
@ -2,106 +2,106 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
RegistersInfo::RegistersInfo()
|
RegistersInfo::RegistersInfo()
|
||||||
{
|
{
|
||||||
memset(&this->_context, 0, sizeof(CONTEXT));
|
memset(&this->_context, 0, sizeof(CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONTEXT* RegistersInfo::GetContext()
|
const CONTEXT* RegistersInfo::GetContext()
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
_context.Rax = this->Rax;
|
_context.Rax = this->Rax;
|
||||||
_context.Rbx = this->Rbx;
|
_context.Rbx = this->Rbx;
|
||||||
_context.Rcx = this->Rcx;
|
_context.Rcx = this->Rcx;
|
||||||
_context.Rdx = this->Rdx;
|
_context.Rdx = this->Rdx;
|
||||||
_context.Rsi = this->Rsi;
|
_context.Rsi = this->Rsi;
|
||||||
_context.Rdi = this->Rdi;
|
_context.Rdi = this->Rdi;
|
||||||
_context.Rbp = this->Rbp;
|
_context.Rbp = this->Rbp;
|
||||||
_context.Rsp = this->Rsp;
|
_context.Rsp = this->Rsp;
|
||||||
_context.Rip = this->Rip;
|
_context.Rip = this->Rip;
|
||||||
_context.R8 = this->R8;
|
_context.R8 = this->R8;
|
||||||
_context.R9 = this->R9;
|
_context.R9 = this->R9;
|
||||||
_context.R10 = this->R10;
|
_context.R10 = this->R10;
|
||||||
_context.R11 = this->R11;
|
_context.R11 = this->R11;
|
||||||
_context.R12 = this->R12;
|
_context.R12 = this->R12;
|
||||||
_context.R13 = this->R13;
|
_context.R13 = this->R13;
|
||||||
_context.R14 = this->R14;
|
_context.R14 = this->R14;
|
||||||
_context.R15 = this->R15;
|
_context.R15 = this->R15;
|
||||||
_context.EFlags = this->EFlags;
|
_context.EFlags = this->EFlags;
|
||||||
#else //x86
|
#else //x86
|
||||||
_context.Eax = this->Eax;
|
_context.Eax = this->Eax;
|
||||||
_context.Ebx = this->Ebx;
|
_context.Ebx = this->Ebx;
|
||||||
_context.Ecx = this->Ecx;
|
_context.Ecx = this->Ecx;
|
||||||
_context.Edx = this->Edx;
|
_context.Edx = this->Edx;
|
||||||
_context.Esi = this->Esi;
|
_context.Esi = this->Esi;
|
||||||
_context.Edi = this->Edi;
|
_context.Edi = this->Edi;
|
||||||
_context.Ebp = this->Ebp;
|
_context.Ebp = this->Ebp;
|
||||||
_context.Esp = this->Esp;
|
_context.Esp = this->Esp;
|
||||||
_context.Eip = this->Eip;
|
_context.Eip = this->Eip;
|
||||||
_context.EFlags = this->EFlags;
|
_context.EFlags = this->EFlags;
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
return &_context;
|
return &_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegistersInfo::SetContext(const CONTEXT & context)
|
void RegistersInfo::SetContext(const CONTEXT & context)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
this->Rax = context.Rax;
|
this->Rax = context.Rax;
|
||||||
this->Rbx = context.Rbx;
|
this->Rbx = context.Rbx;
|
||||||
this->Rcx = context.Rcx;
|
this->Rcx = context.Rcx;
|
||||||
this->Rdx = context.Rdx;
|
this->Rdx = context.Rdx;
|
||||||
this->Rsi = context.Rsi;
|
this->Rsi = context.Rsi;
|
||||||
this->Rdi = context.Rdi;
|
this->Rdi = context.Rdi;
|
||||||
this->Rbp = context.Rbp;
|
this->Rbp = context.Rbp;
|
||||||
this->Rsp = context.Rsp;
|
this->Rsp = context.Rsp;
|
||||||
this->Rip = context.Rip;
|
this->Rip = context.Rip;
|
||||||
this->R8 = context.R8;
|
this->R8 = context.R8;
|
||||||
this->R9 = context.R9;
|
this->R9 = context.R9;
|
||||||
this->R10 = context.R10;
|
this->R10 = context.R10;
|
||||||
this->R11 = context.R11;
|
this->R11 = context.R11;
|
||||||
this->R12 = context.R12;
|
this->R12 = context.R12;
|
||||||
this->R13 = context.R13;
|
this->R13 = context.R13;
|
||||||
this->R14 = context.R14;
|
this->R14 = context.R14;
|
||||||
this->R15 = context.R15;
|
this->R15 = context.R15;
|
||||||
this->EFlags = context.EFlags;
|
this->EFlags = context.EFlags;
|
||||||
#else //x86
|
#else //x86
|
||||||
this->Eax = context.Eax;
|
this->Eax = context.Eax;
|
||||||
this->Ebx = context.Ebx;
|
this->Ebx = context.Ebx;
|
||||||
this->Ecx = context.Ecx;
|
this->Ecx = context.Ecx;
|
||||||
this->Edx = context.Edx;
|
this->Edx = context.Edx;
|
||||||
this->Esi = context.Esi;
|
this->Esi = context.Esi;
|
||||||
this->Edi = context.Edi;
|
this->Edi = context.Edi;
|
||||||
this->Ebp = context.Ebp;
|
this->Ebp = context.Ebp;
|
||||||
this->Esp = context.Esp;
|
this->Esp = context.Esp;
|
||||||
this->Eip = context.Eip;
|
this->Eip = context.Eip;
|
||||||
this->EFlags = context.EFlags;
|
this->EFlags = context.EFlags;
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
this->_context = context;
|
this->_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegistersInfo::SetTrapFlag(bool set)
|
void RegistersInfo::SetTrapFlag(bool set)
|
||||||
{
|
{
|
||||||
if (set)
|
if (set)
|
||||||
this->EFlags |= TRAP_FLAG;
|
this->EFlags |= TRAP_FLAG;
|
||||||
else
|
else
|
||||||
this->EFlags &= ~TRAP_FLAG;
|
this->EFlags &= ~TRAP_FLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegistersInfo::GetTrapFlag()
|
bool RegistersInfo::GetTrapFlag()
|
||||||
{
|
{
|
||||||
return (this->EFlags & TRAP_FLAG) == TRAP_FLAG;
|
return (this->EFlags & TRAP_FLAG) == TRAP_FLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegistersInfo::SetResumeFlag(bool set)
|
void RegistersInfo::SetResumeFlag(bool set)
|
||||||
{
|
{
|
||||||
if (set)
|
if (set)
|
||||||
this->EFlags |= RESUME_FLAG;
|
this->EFlags |= RESUME_FLAG;
|
||||||
else
|
else
|
||||||
this->EFlags &= ~RESUME_FLAG;
|
this->EFlags &= ~RESUME_FLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegistersInfo::GetResumeFlag()
|
bool RegistersInfo::GetResumeFlag()
|
||||||
{
|
{
|
||||||
return (this->EFlags & RESUME_FLAG) == RESUME_FLAG;
|
return (this->EFlags & RESUME_FLAG) == RESUME_FLAG;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -5,91 +5,91 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
CONTEXT;
|
CONTEXT;
|
||||||
/**
|
/**
|
||||||
\brief Thread register context.
|
\brief Thread register context.
|
||||||
*/
|
*/
|
||||||
class RegistersInfo
|
class RegistersInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
DWORD64 Rax;
|
DWORD64 Rax;
|
||||||
DWORD64 Rbx;
|
DWORD64 Rbx;
|
||||||
DWORD64 Rcx;
|
DWORD64 Rcx;
|
||||||
DWORD64 Rdx;
|
DWORD64 Rdx;
|
||||||
DWORD64 Rsi;
|
DWORD64 Rsi;
|
||||||
DWORD64 Rdi;
|
DWORD64 Rdi;
|
||||||
DWORD64 Rbp;
|
DWORD64 Rbp;
|
||||||
DWORD64 Rsp;
|
DWORD64 Rsp;
|
||||||
DWORD64 Rip;
|
DWORD64 Rip;
|
||||||
DWORD64 R8;
|
DWORD64 R8;
|
||||||
DWORD64 R9;
|
DWORD64 R9;
|
||||||
DWORD64 R10;
|
DWORD64 R10;
|
||||||
DWORD64 R11;
|
DWORD64 R11;
|
||||||
DWORD64 R12;
|
DWORD64 R12;
|
||||||
DWORD64 R13;
|
DWORD64 R13;
|
||||||
DWORD64 R14;
|
DWORD64 R14;
|
||||||
DWORD64 R15;
|
DWORD64 R15;
|
||||||
DWORD EFlags;
|
DWORD EFlags;
|
||||||
#else //x86
|
#else //x86
|
||||||
DWORD Eax;
|
DWORD Eax;
|
||||||
DWORD Ebx;
|
DWORD Ebx;
|
||||||
DWORD Ecx;
|
DWORD Ecx;
|
||||||
DWORD Edx;
|
DWORD Edx;
|
||||||
DWORD Esi;
|
DWORD Esi;
|
||||||
DWORD Edi;
|
DWORD Edi;
|
||||||
DWORD Ebp;
|
DWORD Ebp;
|
||||||
DWORD Esp;
|
DWORD Esp;
|
||||||
DWORD Eip;
|
DWORD Eip;
|
||||||
DWORD EFlags;
|
DWORD EFlags;
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Default constructor.
|
\brief Default constructor.
|
||||||
*/
|
*/
|
||||||
RegistersInfo();
|
RegistersInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Gets a pointer to the context object.
|
\brief Gets a pointer to the context object.
|
||||||
\return This function will never return a nullptr.
|
\return This function will never return a nullptr.
|
||||||
*/
|
*/
|
||||||
const CONTEXT* GetContext();
|
const CONTEXT* GetContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets the CONTEXT.
|
\brief Sets the CONTEXT.
|
||||||
\param context The context to set.
|
\param context The context to set.
|
||||||
*/
|
*/
|
||||||
void SetContext(const CONTEXT & context);
|
void SetContext(const CONTEXT & context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets trap flag.
|
\brief Sets trap flag.
|
||||||
\param set (Optional) true to set, false to unset.
|
\param set (Optional) true to set, false to unset.
|
||||||
*/
|
*/
|
||||||
void SetTrapFlag(bool set = true);
|
void SetTrapFlag(bool set = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Gets trap flag.
|
\brief Gets trap flag.
|
||||||
\return true if the flag is set, false otherwise.
|
\return true if the flag is set, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool GetTrapFlag();
|
bool GetTrapFlag();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Sets resume flag.
|
\brief Sets resume flag.
|
||||||
\param set (Optional) true to set, false to unset.
|
\param set (Optional) true to set, false to unset.
|
||||||
*/
|
*/
|
||||||
void SetResumeFlag(bool set = true);
|
void SetResumeFlag(bool set = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Gets resume flag.
|
\brief Gets resume flag.
|
||||||
\return true if the flag is set, false otherwise.
|
\return true if the flag is set, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool GetResumeFlag();
|
bool GetResumeFlag();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CONTEXT _context;
|
CONTEXT _context;
|
||||||
const int TRAP_FLAG = 0x100;
|
const int TRAP_FLAG = 0x100;
|
||||||
const int RESUME_FLAG = 0x10000;
|
const int RESUME_FLAG = 0x10000;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_DEBUGGER_THREAD_REGISTERS_H
|
#endif //_DEBUGGER_THREAD_REGISTERS_H
|
||||||
|
|
@ -2,55 +2,55 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
ThreadInfo::ThreadInfo()
|
ThreadInfo::ThreadInfo()
|
||||||
{
|
{
|
||||||
this->hThread = INVALID_HANDLE_VALUE;
|
this->hThread = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
|
ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
|
||||||
{
|
{
|
||||||
this->dwThreadId = dwThreadId;
|
this->dwThreadId = dwThreadId;
|
||||||
this->hThread = hThread;
|
this->hThread = hThread;
|
||||||
this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase;
|
this->lpThreadLocalBase = reinterpret_cast<ULONG_PTR>(lpThreadLocalBase);
|
||||||
this->lpStartAddress = (ULONG_PTR)lpStartAddress;
|
this->lpStartAddress = reinterpret_cast<ULONG_PTR>(lpStartAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadInfo::RegReadContext()
|
bool ThreadInfo::RegReadContext()
|
||||||
{
|
{
|
||||||
SuspendThread(this->hThread);
|
SuspendThread(this->hThread);
|
||||||
memset(&this->_oldContext, 0, sizeof(CONTEXT));
|
memset(&this->_oldContext, 0, sizeof(CONTEXT));
|
||||||
this->_oldContext.ContextFlags = CONTEXT_ALL;
|
this->_oldContext.ContextFlags = CONTEXT_ALL;
|
||||||
bool bReturn = false;
|
bool bReturn = false;
|
||||||
if (GetThreadContext(this->hThread, &this->_oldContext))
|
if (GetThreadContext(this->hThread, &this->_oldContext))
|
||||||
{
|
{
|
||||||
this->registers.SetContext(this->_oldContext);
|
this->registers.SetContext(this->_oldContext);
|
||||||
bReturn = true;
|
bReturn = true;
|
||||||
}
|
}
|
||||||
ResumeThread(this->hThread);
|
ResumeThread(this->hThread);
|
||||||
return bReturn;
|
return bReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadInfo::RegWriteContext()
|
bool ThreadInfo::RegWriteContext()
|
||||||
{
|
{
|
||||||
//check if something actually changed
|
//check if something actually changed
|
||||||
if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
|
if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
|
||||||
return true;
|
return true;
|
||||||
//update the context
|
//update the context
|
||||||
SuspendThread(this->hThread);
|
SuspendThread(this->hThread);
|
||||||
bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext());
|
bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext());
|
||||||
ResumeThread(this->hThread);
|
ResumeThread(this->hThread);
|
||||||
return bReturn;
|
return bReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadInfo::StepInto(StepCallback cbStep)
|
void ThreadInfo::StepInto(const StepCallback & cbStep)
|
||||||
{
|
{
|
||||||
StepInto();
|
StepInto();
|
||||||
stepCallbacks.push_back(cbStep);
|
stepCallbacks.push_back(cbStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadInfo::StepInto()
|
void ThreadInfo::StepInto()
|
||||||
{
|
{
|
||||||
registers.SetTrapFlag();
|
registers.SetTrapFlag();
|
||||||
isSingleStepping = true;
|
isSingleStepping = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -6,73 +6,73 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
\brief Thread information structure.
|
\brief Thread information structure.
|
||||||
*/
|
*/
|
||||||
class ThreadInfo
|
class ThreadInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DWORD dwThreadId;
|
DWORD dwThreadId;
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
ULONG_PTR lpThreadLocalBase;
|
ULONG_PTR lpThreadLocalBase;
|
||||||
ULONG_PTR lpStartAddress;
|
ULONG_PTR lpStartAddress;
|
||||||
|
|
||||||
RegistersInfo registers;
|
RegistersInfo registers;
|
||||||
StepCallbackVector stepCallbacks;
|
StepCallbackVector stepCallbacks;
|
||||||
bool isSingleStepping;
|
bool isSingleStepping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Default constructor.
|
\brief Default constructor.
|
||||||
*/
|
*/
|
||||||
ThreadInfo();
|
ThreadInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Constructor.
|
\brief Constructor.
|
||||||
\param dwThreadId Identifier for the thread.
|
\param dwThreadId Identifier for the thread.
|
||||||
\param lpThreadLocalBase The thread local base.
|
\param lpThreadLocalBase The thread local base.
|
||||||
\param lpStartAddress The start address.
|
\param lpStartAddress The start address.
|
||||||
*/
|
*/
|
||||||
ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
|
ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Read the register context from the thread. This fills the RegistersInfo member.
|
\brief Read the register context from the thread. This fills the RegistersInfo member.
|
||||||
\return true if it succeeds, false if it fails.
|
\return true if it succeeds, false if it fails.
|
||||||
*/
|
*/
|
||||||
bool RegReadContext();
|
bool RegReadContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Write the register context to the thread. This does nothing if the RegistersInfo member did not change.
|
\brief Write the register context to the thread. This does nothing if the RegistersInfo member did not change.
|
||||||
\return true if it succeeds, false if it fails.
|
\return true if it succeeds, false if it fails.
|
||||||
*/
|
*/
|
||||||
bool RegWriteContext();
|
bool RegWriteContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Step into.
|
\brief Step into.
|
||||||
*/
|
*/
|
||||||
void StepInto();
|
void StepInto();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Step into.
|
\brief Step into.
|
||||||
\param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb).
|
\param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb).
|
||||||
*/
|
*/
|
||||||
void StepInto(StepCallback cbStep);
|
void StepInto(const StepCallback & cbStep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Step into.
|
\brief Step into.
|
||||||
\tparam T Generic type parameter. Must be a subclass of Debugger.
|
\tparam T Generic type parameter. Must be a subclass of Debugger.
|
||||||
\param debugger This pointer to a subclass of Debugger.
|
\param debugger This pointer to a subclass of Debugger.
|
||||||
\param callback Pointer to the callback. Written like: &MyDebugger::cb
|
\param callback Pointer to the callback. Written like: &MyDebugger::cb
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void StepInto(T* debugger, void(T::*callback)())
|
void StepInto(T* debugger, void(T::*callback)())
|
||||||
{
|
{
|
||||||
static_cast<void>(static_cast<Debugger *>(debugger));
|
static_cast<void>(static_cast<Debugger *>(debugger));
|
||||||
StepInto(std::bind(callback, debugger));
|
StepInto(std::bind(callback, debugger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CONTEXT _oldContext;
|
CONTEXT _oldContext;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_DEBUGGER_THREADS_H
|
#endif //_DEBUGGER_THREADS_H
|
||||||
|
|
@ -2,51 +2,62 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
Debugger::Debugger()
|
Debugger::Debugger()
|
||||||
{
|
{
|
||||||
_processes.clear();
|
_processes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Debugger::Init(const wchar_t* szFilePath,
|
Debugger::~Debugger()
|
||||||
const wchar_t* szCommandLine,
|
{
|
||||||
const wchar_t* szCurrentDirectory)
|
}
|
||||||
{
|
|
||||||
STARTUPINFOW si;
|
|
||||||
memset(&si, 0, sizeof(si));
|
|
||||||
const wchar_t* szFileNameCreateProcess;
|
|
||||||
wchar_t* szCommandLineCreateProcess;
|
|
||||||
if (szCommandLine == NULL || !wcslen(szCommandLine))
|
|
||||||
{
|
|
||||||
szCommandLineCreateProcess = 0;
|
|
||||||
szFileNameCreateProcess = szFilePath;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wchar_t szCreateWithCmdLine[1024];
|
|
||||||
swprintf_s(szCreateWithCmdLine, L"\"%s\" %s", szFilePath, szCommandLine);
|
|
||||||
szCommandLineCreateProcess = szCreateWithCmdLine;
|
|
||||||
szFileNameCreateProcess = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!CreateProcessW(szFileNameCreateProcess,
|
bool Debugger::Init(const wchar_t* szFilePath,
|
||||||
szCommandLineCreateProcess,
|
const wchar_t* szCommandLine,
|
||||||
NULL,
|
const wchar_t* szCurrentDirectory)
|
||||||
NULL,
|
{
|
||||||
FALSE,
|
STARTUPINFOW si;
|
||||||
DEBUG_PROCESS | CREATE_NEW_CONSOLE,
|
memset(&si, 0, sizeof(si));
|
||||||
NULL,
|
const wchar_t* szFileNameCreateProcess;
|
||||||
szCurrentDirectory,
|
wchar_t* szCommandLineCreateProcess = nullptr;
|
||||||
&si,
|
wchar_t* szCreateWithCmdLine = nullptr;
|
||||||
&_mainProcess);
|
if (szCommandLine == nullptr || !wcslen(szCommandLine))
|
||||||
}
|
{
|
||||||
|
szCommandLineCreateProcess = nullptr;
|
||||||
|
szFileNameCreateProcess = szFilePath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto size = 1 + wcslen(szFilePath) + 2 + wcslen(szCommandLine) + 1;
|
||||||
|
szCreateWithCmdLine = new wchar_t[size];
|
||||||
|
swprintf_s(szCreateWithCmdLine, size, L"\"%s\" %s", szFilePath, szCommandLine);
|
||||||
|
szCommandLineCreateProcess = szCreateWithCmdLine;
|
||||||
|
szFileNameCreateProcess = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool Debugger::Stop()
|
bool result = !!CreateProcessW(szFileNameCreateProcess,
|
||||||
{
|
szCommandLineCreateProcess,
|
||||||
return !!TerminateProcess(_mainProcess.hProcess, 0);
|
nullptr,
|
||||||
}
|
nullptr,
|
||||||
|
FALSE,
|
||||||
|
DEBUG_PROCESS | CREATE_NEW_CONSOLE,
|
||||||
|
nullptr,
|
||||||
|
szCurrentDirectory,
|
||||||
|
&si,
|
||||||
|
&_mainProcess);
|
||||||
|
|
||||||
bool Debugger::Detach()
|
if (szCreateWithCmdLine)
|
||||||
{
|
delete[] szCreateWithCmdLine;
|
||||||
return !!DebugActiveProcessStop(_mainProcess.dwProcessId);
|
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Debugger::Stop()
|
||||||
|
{
|
||||||
|
return !!TerminateProcess(_mainProcess.hProcess, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Debugger::Detach()
|
||||||
|
{
|
||||||
|
return !!DebugActiveProcessStop(_mainProcess.dwProcessId);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -6,212 +6,217 @@
|
||||||
|
|
||||||
namespace GleeBug
|
namespace GleeBug
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
\brief A debugger class.
|
\brief A debugger class.
|
||||||
*/
|
*/
|
||||||
class Debugger
|
class Debugger
|
||||||
{
|
{
|
||||||
public: //public functionality
|
public: //public functionality
|
||||||
/**
|
/**
|
||||||
\brief Constructs the Debugger instance.
|
\brief Constructs the Debugger instance.
|
||||||
*/
|
*/
|
||||||
Debugger();
|
Debugger();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Start the debuggee.
|
\brief Destructs the Debugger instance.
|
||||||
\param szFilePath Full pathname of the file to debug.
|
*/
|
||||||
\param szCommandLine The command line to pass to the debuggee.
|
virtual ~Debugger();
|
||||||
\param szCurrentDirectory Pathname of the current directory.
|
|
||||||
\return true if the debuggee was started correctly, false otherwise.
|
|
||||||
*/
|
|
||||||
bool Init(const wchar_t* szFilePath,
|
|
||||||
const wchar_t* szCommandLine,
|
|
||||||
const wchar_t* szCurrentDirectory);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Stops the debuggee (terminate the process)
|
\brief Start the debuggee.
|
||||||
\return true if the debuggee was stopped correctly, false otherwise.
|
\param szFilePath Full pathname of the file to debug.
|
||||||
*/
|
\param szCommandLine The command line to pass to the debuggee.
|
||||||
bool Stop();
|
\param szCurrentDirectory Pathname of the current directory.
|
||||||
|
\return true if the debuggee was started correctly, false otherwise.
|
||||||
|
*/
|
||||||
|
bool Init(const wchar_t* szFilePath,
|
||||||
|
const wchar_t* szCommandLine,
|
||||||
|
const wchar_t* szCurrentDirectory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Detaches the debuggee.
|
\brief Stops the debuggee (terminate the process)
|
||||||
\return true if the debuggee was detached correctly, false otherwise.
|
\return true if the debuggee was stopped correctly, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool Detach();
|
bool Stop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Run the debug loop (does not return until the debuggee is detached or terminated).
|
\brief Detaches the debuggee.
|
||||||
*/
|
\return true if the debuggee was detached correctly, false otherwise.
|
||||||
void Start();
|
*/
|
||||||
|
bool Detach();
|
||||||
|
|
||||||
protected: //debug event callbacks
|
/**
|
||||||
/**
|
\brief Run the debug loop (does not return until the debuggee is detached or terminated).
|
||||||
\brief Process creation debug event callback. Provide an implementation to use this callback.
|
*/
|
||||||
\param createProcess Information about the process created.
|
void Start();
|
||||||
*/
|
|
||||||
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) {};
|
|
||||||
|
|
||||||
/**
|
protected: //debug event callbacks
|
||||||
\brief Process termination debug event callback. Provide an implementation to use this callback.
|
/**
|
||||||
\param exitProcess Information about the process terminated.
|
\brief Process creation debug event callback. Provide an implementation to use this callback.
|
||||||
*/
|
\param createProcess Information about the process created.
|
||||||
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) {};
|
*/
|
||||||
|
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Thread creation debug event callback. Provide an implementation to use this callback.
|
\brief Process termination debug event callback. Provide an implementation to use this callback.
|
||||||
\param createThread Information about the thread created.
|
\param exitProcess Information about the process terminated.
|
||||||
*/
|
*/
|
||||||
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) {};
|
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Thread termination debug event callback. Provide an implementation to use this callback.
|
\brief Thread creation debug event callback. Provide an implementation to use this callback.
|
||||||
\param exitThread Information about the thread terminated.
|
\param createThread Information about the thread created.
|
||||||
*/
|
*/
|
||||||
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) {};
|
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief DLL load debug event callback. Provide an implementation to use this callback.
|
\brief Thread termination debug event callback. Provide an implementation to use this callback.
|
||||||
\param loadDll Information about the DLL loaded.
|
\param exitThread Information about the thread terminated.
|
||||||
*/
|
*/
|
||||||
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) {};
|
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief DLL unload debug event callback. Provide an implementation to use this callback.
|
\brief DLL load debug event callback. Provide an implementation to use this callback.
|
||||||
\param unloadDll Information about the DLL unloaded.
|
\param loadDll Information about the DLL loaded.
|
||||||
*/
|
*/
|
||||||
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) {};
|
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Exception debug event callback. Provide an implementation to use this callback.
|
\brief DLL unload debug event callback. Provide an implementation to use this callback.
|
||||||
\param exceptionInfo Information about the exception.
|
\param unloadDll Information about the DLL unloaded.
|
||||||
*/
|
*/
|
||||||
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) {};
|
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Debug string debug event callback. Provide an implementation to use this callback.
|
\brief Exception debug event callback. Provide an implementation to use this callback.
|
||||||
\param debugString Information about the debug string.
|
\param exceptionInfo Information about the exception.
|
||||||
*/
|
*/
|
||||||
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) {};
|
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief RIP debug event callback. Provide an implementation to use this callback.
|
\brief Debug string debug event callback. Provide an implementation to use this callback.
|
||||||
\param rip Information about the RIP event.
|
\param debugString Information about the debug string.
|
||||||
*/
|
*/
|
||||||
virtual void cbRipEvent(const RIP_INFO & rip) {};
|
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) {};
|
||||||
|
|
||||||
protected: //other callbacks
|
/**
|
||||||
/**
|
\brief RIP debug event callback. Provide an implementation to use this callback.
|
||||||
\brief Internal error callback. Provide an implementation to use this callback.
|
\param rip Information about the RIP event.
|
||||||
\param error The error message.
|
*/
|
||||||
*/
|
virtual void cbRipEvent(const RIP_INFO & rip) {};
|
||||||
virtual void cbInternalError(const std::string & error) {};
|
|
||||||
|
|
||||||
/**
|
protected: //other callbacks
|
||||||
\brief Unhandled exception callback. Provide an implementation to use this callback.
|
/**
|
||||||
\param exceptionRecord The exception record.
|
\brief Internal error callback. Provide an implementation to use this callback.
|
||||||
\param firstChance True if the exception is a first chance exception, false otherwise.
|
\param error The error message.
|
||||||
*/
|
*/
|
||||||
virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) {};
|
virtual void cbInternalError(const std::string & error) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief System breakpoint callback. Provide an implementation to use this callback.
|
\brief Unhandled exception callback. Provide an implementation to use this callback.
|
||||||
*/
|
\param exceptionRecord The exception record.
|
||||||
virtual void cbSystemBreakpoint() {};
|
\param firstChance True if the exception is a first chance exception, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Step callback. Provide an implementation to use this callback.
|
\brief System breakpoint callback. Provide an implementation to use this callback.
|
||||||
*/
|
*/
|
||||||
virtual void cbStep() {};
|
virtual void cbSystemBreakpoint() {};
|
||||||
|
|
||||||
protected: //core debug event handlers
|
/**
|
||||||
/**
|
\brief Step callback. Provide an implementation to use this callback.
|
||||||
\brief Process creation debug event. Do not override this unless you know what you are doing!
|
*/
|
||||||
\param createProcess Information about the process created.
|
virtual void cbStep() {};
|
||||||
*/
|
|
||||||
virtual void createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess);
|
|
||||||
|
|
||||||
/**
|
protected: //core debug event handlers
|
||||||
\brief Process termination debug event. Do not override this unless you know what you are doing!
|
/**
|
||||||
\param exitProcess Information about the process terminated.
|
\brief Process creation debug event. Do not override this unless you know what you are doing!
|
||||||
*/
|
\param createProcess Information about the process created.
|
||||||
virtual void exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess);
|
*/
|
||||||
|
virtual void createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Thread creation debug event. Do not override this unless you know what you are doing!
|
\brief Process termination debug event. Do not override this unless you know what you are doing!
|
||||||
\param createThread Information about the thread created.
|
\param exitProcess Information about the process terminated.
|
||||||
*/
|
*/
|
||||||
virtual void createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread);
|
virtual void exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Thread termination debug event. Do not override this unless you know what you are doing!
|
\brief Thread creation debug event. Do not override this unless you know what you are doing!
|
||||||
\param exitThread Information about the thread terminated.
|
\param createThread Information about the thread created.
|
||||||
*/
|
*/
|
||||||
virtual void exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread);
|
virtual void createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief DLL load debug event. Do not override this unless you know what you are doing!
|
\brief Thread termination debug event. Do not override this unless you know what you are doing!
|
||||||
\param loadDll Information about the DLL loaded.
|
\param exitThread Information about the thread terminated.
|
||||||
*/
|
*/
|
||||||
virtual void loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll);
|
virtual void exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief DLL unload debug event. Do not override this unless you know what you are doing!
|
\brief DLL load debug event. Do not override this unless you know what you are doing!
|
||||||
\param unloadDll Information about the DLL unloaded.
|
\param loadDll Information about the DLL loaded.
|
||||||
*/
|
*/
|
||||||
virtual void unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll);
|
virtual void loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Exception debug event. Do not override this unless you know what you are doing!
|
\brief DLL unload debug event. Do not override this unless you know what you are doing!
|
||||||
\param exceptionInfo Information about the exception.
|
\param unloadDll Information about the DLL unloaded.
|
||||||
*/
|
*/
|
||||||
virtual void exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo);
|
virtual void unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Debug string debug event. Do not override this unless you know what you are doing!
|
\brief Exception debug event. Do not override this unless you know what you are doing!
|
||||||
\param debugString Information about the debug string.
|
\param exceptionInfo Information about the exception.
|
||||||
*/
|
*/
|
||||||
virtual void debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString);
|
virtual void exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief RIP debug event. Do not override this unless you know what you are doing!
|
\brief Debug string debug event. Do not override this unless you know what you are doing!
|
||||||
\param rip Information about the RIP event.
|
\param debugString Information about the debug string.
|
||||||
*/
|
*/
|
||||||
virtual void ripEvent(const RIP_INFO & rip);
|
virtual void debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString);
|
||||||
|
|
||||||
protected: //core exception handlers
|
/**
|
||||||
/**
|
\brief RIP debug event. Do not override this unless you know what you are doing!
|
||||||
\brief Breakpoint exception handler. Do not override this unless you know what you are doing!
|
\param rip Information about the RIP event.
|
||||||
\param exceptionRecord The exception record.
|
*/
|
||||||
\param firstChance True if the exception is a first chance exception, false otherwise.
|
virtual void ripEvent(const RIP_INFO & rip);
|
||||||
*/
|
|
||||||
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
|
|
||||||
|
|
||||||
/**
|
protected: //core exception handlers
|
||||||
\brief Single step exception handler. Do not override this unless you know what you are doing!
|
/**
|
||||||
\param exceptionRecord The exception record.
|
\brief Breakpoint exception handler. Do not override this unless you know what you are doing!
|
||||||
\param firstChance True if the exception is a first chance exception, false otherwise.
|
\param exceptionRecord The exception record.
|
||||||
*/
|
\param firstChance True if the exception is a first chance exception, false otherwise.
|
||||||
virtual void exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
|
*/
|
||||||
|
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
|
||||||
|
|
||||||
protected: //variables
|
/**
|
||||||
PROCESS_INFORMATION _mainProcess;
|
\brief Single step exception handler. Do not override this unless you know what you are doing!
|
||||||
DWORD _continueStatus;
|
\param exceptionRecord The exception record.
|
||||||
bool _breakDebugger;
|
\param firstChance True if the exception is a first chance exception, false otherwise.
|
||||||
DEBUG_EVENT _debugEvent;
|
*/
|
||||||
ProcessMap _processes;
|
virtual void exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
|
||||||
bool _isRunning;
|
|
||||||
|
|
||||||
/**
|
protected: //variables
|
||||||
\brief The current process (can be null in some cases).
|
PROCESS_INFORMATION _mainProcess;
|
||||||
*/
|
DWORD _continueStatus;
|
||||||
ProcessInfo* _process;
|
bool _breakDebugger;
|
||||||
|
DEBUG_EVENT _debugEvent;
|
||||||
|
ProcessMap _processes;
|
||||||
|
bool _isRunning;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief The current thread (can be null in some cases). Should be a copy of _process->thread.
|
\brief The current process (can be null in some cases).
|
||||||
*/
|
*/
|
||||||
ThreadInfo* _thread;
|
ProcessInfo* _process;
|
||||||
};
|
|
||||||
|
/**
|
||||||
|
\brief The current thread (can be null in some cases). Should be a copy of _process->thread.
|
||||||
|
*/
|
||||||
|
ThreadInfo* _thread;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_DEBUGGER_H
|
#endif //_DEBUGGER_H
|
||||||
|
|
@ -9,10 +9,6 @@
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Debugger.cpp">
|
<ClCompile Include="Debugger.cpp">
|
||||||
|
|
|
||||||
|
|
@ -8,85 +8,89 @@ using namespace GleeBug;
|
||||||
class MyDebugger : public Debugger
|
class MyDebugger : public Debugger
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process)
|
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) override
|
||||||
{
|
{
|
||||||
printf("Process %d created with entry 0x%p\n",
|
printf("Process %d created with entry 0x%p\n",
|
||||||
_debugEvent.dwProcessId,
|
_debugEvent.dwProcessId,
|
||||||
createProcess.lpStartAddress);
|
createProcess.lpStartAddress);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process)
|
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override
|
||||||
{
|
{
|
||||||
printf("Process %d terminated with exit code 0x%08X\n",
|
printf("Process %u terminated with exit code 0x%08X\n",
|
||||||
_debugEvent.dwProcessId,
|
_debugEvent.dwProcessId,
|
||||||
exitProcess.dwExitCode);
|
exitProcess.dwExitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread)
|
void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) override
|
||||||
{
|
{
|
||||||
printf("Thread %d created with entry 0x%p\n",
|
printf("Thread %u created with entry 0x%p\n",
|
||||||
_debugEvent.dwThreadId,
|
_debugEvent.dwThreadId,
|
||||||
createThread.lpStartAddress);
|
createThread.lpStartAddress);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread)
|
void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) override
|
||||||
{
|
{
|
||||||
printf("Thread %d terminated with exit code 0x%08X\n",
|
printf("Thread %u terminated with exit code 0x%08X\n",
|
||||||
_debugEvent.dwThreadId,
|
_debugEvent.dwThreadId,
|
||||||
exitThread.dwExitCode);
|
exitThread.dwExitCode);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll)
|
void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) override
|
||||||
{
|
{
|
||||||
printf("DLL loaded at 0x%p\n",
|
printf("DLL loaded at 0x%p\n",
|
||||||
loadDll.lpBaseOfDll);
|
loadDll.lpBaseOfDll);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll)
|
void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) override
|
||||||
{
|
{
|
||||||
printf("DLL 0x%p unloaded\n",
|
printf("DLL 0x%p unloaded\n",
|
||||||
unloadDll.lpBaseOfDll);
|
unloadDll.lpBaseOfDll);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) override
|
||||||
{
|
{
|
||||||
printf("Exception with code 0x%08X at 0x%p\n",
|
printf("Exception with code 0x%08X at 0x%p\n",
|
||||||
exceptionInfo.ExceptionRecord.ExceptionCode,
|
exceptionInfo.ExceptionRecord.ExceptionCode,
|
||||||
exceptionInfo.ExceptionRecord.ExceptionAddress);
|
exceptionInfo.ExceptionRecord.ExceptionAddress);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
|
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);
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void cbRipEvent(const RIP_INFO & rip)
|
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 boobs()
|
void boobs()
|
||||||
{
|
{
|
||||||
printf("(.)Y(.) 0x%p\n",
|
printf("(.)Y(.) 0x%p\n",
|
||||||
_thread->registers.Rip);
|
#ifdef _WIN64
|
||||||
}
|
_thread->registers.Rip);
|
||||||
|
#else //x32
|
||||||
|
_thread->registers.Eip);
|
||||||
|
#endif //_WIN64
|
||||||
|
}
|
||||||
|
|
||||||
virtual void cbSystemBreakpoint()
|
void cbSystemBreakpoint() override
|
||||||
{
|
{
|
||||||
printf("System breakpoint reached, CIP: 0x%p\n",
|
printf("System breakpoint reached, CIP: 0x%p\n",
|
||||||
_thread->registers.Rip);
|
_thread->registers.Rip);
|
||||||
_thread->StepInto(BIND(this, MyDebugger::boobs));
|
_thread->StepInto(BIND(this, MyDebugger::boobs));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void cbInternalError(const std::string & error)
|
void cbInternalError(const std::string & error) override
|
||||||
{
|
{
|
||||||
printf("Internal Error: %s\n",
|
printf("Internal Error: %s\n",
|
||||||
error.c_str());
|
error.c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_MYDEBUGGER_H
|
#endif //_MYDEBUGGER_H
|
||||||
|
|
@ -4,23 +4,23 @@
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
wchar_t szFilePath[256] = L"c:\\test64.exe";
|
wchar_t szFilePath[256] = L"c:\\test64.exe";
|
||||||
#else //x86
|
#else //x86
|
||||||
wchar_t szFilePath[256] = L"c:\\test32.exe";
|
wchar_t szFilePath[256] = L"c:\\test32.exe";
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
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();
|
||||||
puts("Debugger::Start finished!");
|
puts("Debugger::Start finished!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
puts("Debugger::Init failed!");
|
puts("Debugger::Init failed!");
|
||||||
}
|
}
|
||||||
system("pause");
|
system("pause");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue