massive cleanup + fixed various code problems

This commit is contained in:
Mr. eXoDia 2015-07-15 02:48:11 +02:00
parent 3ce2a318ca
commit 2481e33abd
22 changed files with 928 additions and 914 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ Release/
*.suo
*.sdf
*.opensdf
*.orig

View File

@ -2,14 +2,14 @@
namespace GleeBug
{
DllInfo::DllInfo()
{
}
DllInfo::DllInfo()
{
}
DllInfo::DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint)
{
this->lpBaseOfDll = (ULONG_PTR)lpBaseOfDll;
this->sizeOfImage = sizeOfImage;
this->entryPoint = (ULONG_PTR)entryPoint;
}
DllInfo::DllInfo(LPVOID lpBaseOfDll, ULONG_PTR sizeOfImage, LPVOID entryPoint)
{
this->lpBaseOfDll = reinterpret_cast<ULONG_PTR>(lpBaseOfDll);
this->sizeOfImage = sizeOfImage;
this->entryPoint = reinterpret_cast<ULONG_PTR>(entryPoint);
}
};

View File

@ -5,29 +5,29 @@
namespace GleeBug
{
/**
\brief DLL information structure.
*/
class DllInfo
{
public:
ULONG_PTR lpBaseOfDll;
DWORD sizeOfImage;
ULONG_PTR entryPoint;
/**
\brief DLL information structure.
*/
class DllInfo
{
public:
ULONG_PTR lpBaseOfDll;
ULONG_PTR sizeOfImage;
ULONG_PTR entryPoint;
/**
\brief Default constructor.
*/
DllInfo();
/**
\brief Default constructor.
*/
DllInfo();
/**
\brief Constructor.
\param lpBaseOfDll The base of DLL.
\param sizeOfImage Size of the image.
\param entryPoint The entry point.
*/
DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint);
};
/**
\brief Constructor.
\param lpBaseOfDll The base of DLL.
\param sizeOfImage Size of the image.
\param entryPoint The entry point.
*/
DllInfo(LPVOID lpBaseOfDll, ULONG_PTR sizeOfImage, LPVOID entryPoint);
};
};
#endif //_DEBUGGER_DLL_H

View File

@ -14,35 +14,35 @@
namespace GleeBug
{
typedef std::pair<ULONG_PTR, ULONG_PTR> Range;
typedef std::pair<ULONG_PTR, ULONG_PTR> Range;
struct RangeCompare
{
inline bool operator()(const Range & a, const Range & b) const //a before b?
{
return a.second < b.first;
}
};
struct RangeCompare
{
inline bool operator()(const Range & a, const Range & b) const //a before b?
{
return a.second < b.first;
}
};
//forward declarations
class Debugger;
class ProcessInfo;
class DllInfo;
class ThreadInfo;
//forward declarations
class Debugger;
class ProcessInfo;
class DllInfo;
class ThreadInfo;
//map typedefs
typedef std::map<DWORD, ProcessInfo> ProcessMap;
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
typedef std::map<DWORD, ThreadInfo> ThreadMap;
//map typedefs
typedef std::map<DWORD, ProcessInfo> ProcessMap;
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
typedef std::map<DWORD, ThreadInfo> ThreadMap;
//callback function typedefs
typedef std::function<void()> StepCallback;
//callback function typedefs
typedef std::function<void()> StepCallback;
//vector typedefs
typedef std::vector<StepCallback> StepCallbackVector;
//vector typedefs
typedef std::vector<StepCallback> StepCallbackVector;
//macros
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
//macros
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
};
#endif //_DEBUGGER_GLOBAL_H

View File

@ -2,12 +2,12 @@
namespace GleeBug
{
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
{
//prevent anti-debug trick (debug string events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
{
//prevent anti-debug trick (debug string events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//call the debug event callback
cbDebugStringEvent(debugString);
}
//call the debug event callback
cbDebugStringEvent(debugString);
}
};

View File

@ -2,37 +2,37 @@
namespace GleeBug
{
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
{
//DLL housekeeping
MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_process->hProcess,
(HMODULE)loadDll.lpBaseOfDll,
&modinfo,
sizeof(MODULEINFO));
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
_process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
{
//DLL housekeeping
MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_process->hProcess,
reinterpret_cast<HMODULE>(loadDll.lpBaseOfDll),
&modinfo,
sizeof(MODULEINFO));
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
_process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
//call the debug event callback
cbLoadDllEvent(loadDll, dll);
//call the debug event callback
cbLoadDllEvent(loadDll, dll);
//close the file handle
CloseHandle(loadDll.hFile);
}
//close the file handle
CloseHandle(loadDll.hFile);
}
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
{
//call the debug event callback
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll;
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _process->dlls.end())
cbUnloadDllEvent(unloadDll, dll->second);
else
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0));
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
{
//call the debug event callback
ULONG_PTR lpBaseOfDll = reinterpret_cast<ULONG_PTR>(unloadDll.lpBaseOfDll);
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _process->dlls.end())
cbUnloadDllEvent(unloadDll, dll->second);
else
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, nullptr));
//DLL housekeeping
if (dll != _process->dlls.end())
_process->dlls.erase(dll);
}
//DLL housekeeping
if (dll != _process->dlls.end())
_process->dlls.erase(dll);
}
};

View File

@ -2,64 +2,61 @@
namespace GleeBug
{
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (!_process->systemBreakpoint) //handle system breakpoint
{
_process->systemBreakpoint = true;
_continueStatus = DBG_CONTINUE;
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (!_process->systemBreakpoint) //handle system breakpoint
{
_process->systemBreakpoint = true;
_continueStatus = DBG_CONTINUE;
//call the callback
cbSystemBreakpoint();
}
else //handle other breakpoint exceptions
{
}
}
//call the callback
cbSystemBreakpoint();
}
}
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (_thread->isSingleStepping) //handle single step
{
_thread->isSingleStepping = false;
_continueStatus = DBG_CONTINUE;
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (_thread->isSingleStepping) //handle single step
{
_thread->isSingleStepping = false;
_continueStatus = DBG_CONTINUE;
//call the callbacks
StepCallbackVector cbStepCopy = _thread->stepCallbacks;
_thread->stepCallbacks.clear();
for (auto cbStep : cbStepCopy)
cbStep();
cbStep();
}
else //handle other single step exceptions
{
}
}
//call the callbacks
StepCallbackVector cbStepCopy = _thread->stepCallbacks;
_thread->stepCallbacks.clear();
for (auto cbStep : cbStepCopy)
cbStep();
cbStep();
}
else //handle other single step exceptions
{
}
}
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{
//let the debuggee handle exceptions per default
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{
//let the debuggee handle exceptions per default
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord;
const bool firstChance = exceptionInfo.dwFirstChance == 1;
const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord;
const bool firstChance = exceptionInfo.dwFirstChance == 1;
//dispatch the exception
switch (exceptionInfo.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
exceptionBreakpoint(exceptionRecord, firstChance);
break;
case STATUS_SINGLE_STEP:
exceptionSingleStep(exceptionRecord, firstChance);
break;
}
//dispatch the exception
switch (exceptionInfo.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
exceptionBreakpoint(exceptionRecord, firstChance);
break;
case STATUS_SINGLE_STEP:
exceptionSingleStep(exceptionRecord, firstChance);
break;
}
//call the unhandled exception callback
if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED)
cbUnhandledException(exceptionRecord, firstChance);
//call the unhandled exception callback
if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED)
cbUnhandledException(exceptionRecord, firstChance);
//call the debug event callback
cbExceptionEvent(exceptionInfo);
}
//call the debug event callback
cbExceptionEvent(exceptionInfo);
}
};

View File

@ -2,47 +2,47 @@
namespace GleeBug
{
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
{
//process housekeeping
ProcessInfo process(_debugEvent.dwProcessId,
createProcess.hProcess,
_debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process });
_process = &_processes.find(process.dwProcessId)->second;
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
{
//process housekeeping
ProcessInfo process(_debugEvent.dwProcessId,
createProcess.hProcess,
_debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process });
_process = &_processes.find(process.dwProcessId)->second;
//thread housekeeping (main thread is created implicitly)
ThreadInfo thread(_debugEvent.dwThreadId,
createProcess.hThread,
createProcess.lpThreadLocalBase,
createProcess.lpStartAddress);
_process->threads.insert({ thread.dwThreadId, thread });
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
//thread housekeeping (main thread is created implicitly)
ThreadInfo thread(_debugEvent.dwThreadId,
createProcess.hThread,
createProcess.lpThreadLocalBase,
createProcess.lpStartAddress);
_process->threads.insert({ thread.dwThreadId, thread });
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
//read thread context from main thread
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
//read thread context from main thread
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
//call the debug event callback
cbCreateProcessEvent(createProcess, *_process);
//call the debug event callback
cbCreateProcessEvent(createProcess, *_process);
//close the file handle
CloseHandle(createProcess.hFile);
}
//close the file handle
CloseHandle(createProcess.hFile);
}
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
{
//check if the terminated process is the main debuggee
if (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
_breakDebugger = true;
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
{
//check if the terminated process is the main debuggee
if (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
_breakDebugger = true;
//call the debug event callback
cbExitProcessEvent(exitProcess, *_process);
//call the debug event callback
cbExitProcessEvent(exitProcess, *_process);
//process housekeeping
_processes.erase(_debugEvent.dwProcessId);
//process housekeeping
_processes.erase(_debugEvent.dwProcessId);
//set the current process
_process = nullptr;
}
//set the current process
_process = nullptr;
}
};

View File

@ -2,12 +2,12 @@
namespace GleeBug
{
void Debugger::ripEvent(const RIP_INFO & rip)
{
//prevent anti-debug trick (RIP events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
void Debugger::ripEvent(const RIP_INFO & rip)
{
//prevent anti-debug trick (RIP events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//call the debug event callback
cbRipEvent(rip);
}
//call the debug event callback
cbRipEvent(rip);
}
};

View File

@ -2,30 +2,30 @@
namespace GleeBug
{
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
{
//thread housekeeping
_process->threads.insert({ _debugEvent.dwThreadId,
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
{
//thread housekeeping
_process->threads.insert({ _debugEvent.dwThreadId,
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
//set the current thread
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
//set the current thread
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
//call the debug event callback
cbCreateThreadEvent(createThread, *_thread);
}
//call the debug event callback
cbCreateThreadEvent(createThread, *_thread);
}
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
{
//call the debug event callback
cbExitThreadEvent(exitThread, *_thread);
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
{
//call the debug event callback
cbExitThreadEvent(exitThread, *_thread);
//thread housekeeping
_process->threads.erase(_debugEvent.dwThreadId);
//thread housekeeping
_process->threads.erase(_debugEvent.dwThreadId);
//set the current thread
_thread = _process->thread = nullptr;
}
//set the current thread
_thread = _process->thread = nullptr;
}
};

View File

@ -2,84 +2,84 @@
namespace GleeBug
{
void Debugger::Start()
{
//initialize loop variables
_breakDebugger = false;
void Debugger::Start()
{
//initialize loop variables
_breakDebugger = false;
while (!_breakDebugger)
{
//wait for a debug event
_isRunning = true;
if (!WaitForDebugEvent(&_debugEvent, INFINITE))
break;
_isRunning = false;
while (!_breakDebugger)
{
//wait for a debug event
_isRunning = true;
if (!WaitForDebugEvent(&_debugEvent, INFINITE))
break;
_isRunning = false;
//set default continue status
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//set default continue status
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//set the current process and thread
if (_processes.count(_debugEvent.dwProcessId))
{
_process = &_processes[_debugEvent.dwProcessId];
if (_process->threads.count(_debugEvent.dwThreadId))
{
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
}
else
_thread = _process->thread = nullptr;
}
else
_process = nullptr;
//set the current process and thread
if (_processes.count(_debugEvent.dwProcessId))
{
_process = &_processes[_debugEvent.dwProcessId];
if (_process->threads.count(_debugEvent.dwThreadId))
{
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
}
else
_thread = _process->thread = nullptr;
}
else
_process = nullptr;
//dispatch the debug event
switch (_debugEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
createProcessEvent(_debugEvent.u.CreateProcessInfo);
break;
case EXIT_PROCESS_DEBUG_EVENT:
exitProcessEvent(_debugEvent.u.ExitProcess);
break;
case CREATE_THREAD_DEBUG_EVENT:
createThreadEvent(_debugEvent.u.CreateThread);
break;
case EXIT_THREAD_DEBUG_EVENT:
exitThreadEvent(_debugEvent.u.ExitThread);
break;
case LOAD_DLL_DEBUG_EVENT:
loadDllEvent(_debugEvent.u.LoadDll);
break;
case UNLOAD_DLL_DEBUG_EVENT:
unloadDllEvent(_debugEvent.u.UnloadDll);
break;
case EXCEPTION_DEBUG_EVENT:
exceptionEvent(_debugEvent.u.Exception);
break;
case OUTPUT_DEBUG_STRING_EVENT:
debugStringEvent(_debugEvent.u.DebugString);
break;
case RIP_EVENT:
ripEvent(_debugEvent.u.RipInfo);
break;
}
//dispatch the debug event
switch (_debugEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
createProcessEvent(_debugEvent.u.CreateProcessInfo);
break;
case EXIT_PROCESS_DEBUG_EVENT:
exitProcessEvent(_debugEvent.u.ExitProcess);
break;
case CREATE_THREAD_DEBUG_EVENT:
createThreadEvent(_debugEvent.u.CreateThread);
break;
case EXIT_THREAD_DEBUG_EVENT:
exitThreadEvent(_debugEvent.u.ExitThread);
break;
case LOAD_DLL_DEBUG_EVENT:
loadDllEvent(_debugEvent.u.LoadDll);
break;
case UNLOAD_DLL_DEBUG_EVENT:
unloadDllEvent(_debugEvent.u.UnloadDll);
break;
case EXCEPTION_DEBUG_EVENT:
exceptionEvent(_debugEvent.u.Exception);
break;
case OUTPUT_DEBUG_STRING_EVENT:
debugStringEvent(_debugEvent.u.DebugString);
break;
case RIP_EVENT:
ripEvent(_debugEvent.u.RipInfo);
break;
}
//write the register context
if (_thread)
{
if (!_thread->RegWriteContext())
cbInternalError("ThreadInfo::RegWriteContext() failed!");
}
//write the register context
if (_thread)
{
if (!_thread->RegWriteContext())
cbInternalError("ThreadInfo::RegWriteContext() failed!");
}
//continue the debug event
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
break;
}
//continue the debug event
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
break;
}
//cleanup
_processes.clear();
_process = nullptr;
}
//cleanup
_processes.clear();
_process = nullptr;
}
};

View File

@ -2,28 +2,28 @@
namespace GleeBug
{
ProcessInfo::ProcessInfo()
{
this->thread = nullptr;
this->systemBreakpoint = false;
this->hProcess = INVALID_HANDLE_VALUE;
}
ProcessInfo::ProcessInfo()
{
this->thread = nullptr;
this->systemBreakpoint = false;
this->hProcess = INVALID_HANDLE_VALUE;
}
ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId)
{
this->systemBreakpoint = false;
this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
this->dwProcessId = dwProcessId;
this->dwMainThreadId = dwMainThreadId;
}
ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId)
{
this->systemBreakpoint = false;
this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
this->dwProcessId = dwProcessId;
this->dwMainThreadId = dwMainThreadId;
}
bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
{
return !!ReadProcessMemory(this->hProcess, (const void*)address, buffer, size, NULL);
}
bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
{
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)
{
return !!WriteProcessMemory(this->hProcess, (void*)address, buffer, size, NULL);
}
bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer)
{
return !!WriteProcessMemory(this->hProcess, reinterpret_cast<void*>(address), buffer, size, nullptr);
}
};

View File

@ -7,52 +7,52 @@
namespace GleeBug
{
/**
\brief Process information structure.
*/
class ProcessInfo
{
public:
HANDLE hProcess;
DWORD dwProcessId;
DWORD dwMainThreadId;
/**
\brief Process information structure.
*/
class ProcessInfo
{
public:
HANDLE hProcess;
DWORD dwProcessId;
DWORD dwMainThreadId;
ThreadInfo* thread;
bool systemBreakpoint;
ThreadInfo* thread;
bool systemBreakpoint;
ThreadMap threads;
DllMap dlls;
ThreadMap threads;
DllMap dlls;
/**
\brief Default constructor.
*/
ProcessInfo();
/**
\brief Default constructor.
*/
ProcessInfo();
/**
\brief Constructor.
\param dwProcessId Identifier for the process.
\param dwMainThreadId Identifier for the main thread.
*/
ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId);
/**
\brief Constructor.
\param dwProcessId Identifier for the process.
\param dwMainThreadId Identifier for the main thread.
*/
ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId);
/**
\brief Read memory from the process.
\param address The virtual address to read from.
\param size The size to read.
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
\return true if it succeeds, false if it fails.
*/
bool MemRead(ULONG_PTR address, const size_t size, void* buffer);
/**
\brief Read memory from the process.
\param address The virtual address to read from.
\param size The size to read.
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
\return true if it succeeds, false if it fails.
*/
bool MemRead(ULONG_PTR address, const size_t size, void* buffer);
/**
\brief Write memory to the process.
\param address The virtual address to write to.
\param size The size to write.
\param [in] buffer Source buffer. Cannot be null.
\return true if it succeeds, false if it fails.
*/
bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer);
};
/**
\brief Write memory to the process.
\param address The virtual address to write to.
\param size The size to write.
\param [in] buffer Source buffer. Cannot be null.
\return true if it succeeds, false if it fails.
*/
bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer);
};
};
#endif //_DEBUGGER_PROCESS_H

View File

@ -2,106 +2,106 @@
namespace GleeBug
{
RegistersInfo::RegistersInfo()
{
memset(&this->_context, 0, sizeof(CONTEXT));
}
RegistersInfo::RegistersInfo()
{
memset(&this->_context, 0, sizeof(CONTEXT));
}
const CONTEXT* RegistersInfo::GetContext()
{
const CONTEXT* RegistersInfo::GetContext()
{
#ifdef _WIN64
_context.Rax = this->Rax;
_context.Rbx = this->Rbx;
_context.Rcx = this->Rcx;
_context.Rdx = this->Rdx;
_context.Rsi = this->Rsi;
_context.Rdi = this->Rdi;
_context.Rbp = this->Rbp;
_context.Rsp = this->Rsp;
_context.Rip = this->Rip;
_context.R8 = this->R8;
_context.R9 = this->R9;
_context.R10 = this->R10;
_context.R11 = this->R11;
_context.R12 = this->R12;
_context.R13 = this->R13;
_context.R14 = this->R14;
_context.R15 = this->R15;
_context.EFlags = this->EFlags;
_context.Rax = this->Rax;
_context.Rbx = this->Rbx;
_context.Rcx = this->Rcx;
_context.Rdx = this->Rdx;
_context.Rsi = this->Rsi;
_context.Rdi = this->Rdi;
_context.Rbp = this->Rbp;
_context.Rsp = this->Rsp;
_context.Rip = this->Rip;
_context.R8 = this->R8;
_context.R9 = this->R9;
_context.R10 = this->R10;
_context.R11 = this->R11;
_context.R12 = this->R12;
_context.R13 = this->R13;
_context.R14 = this->R14;
_context.R15 = this->R15;
_context.EFlags = this->EFlags;
#else //x86
_context.Eax = this->Eax;
_context.Ebx = this->Ebx;
_context.Ecx = this->Ecx;
_context.Edx = this->Edx;
_context.Esi = this->Esi;
_context.Edi = this->Edi;
_context.Ebp = this->Ebp;
_context.Esp = this->Esp;
_context.Eip = this->Eip;
_context.EFlags = this->EFlags;
_context.Eax = this->Eax;
_context.Ebx = this->Ebx;
_context.Ecx = this->Ecx;
_context.Edx = this->Edx;
_context.Esi = this->Esi;
_context.Edi = this->Edi;
_context.Ebp = this->Ebp;
_context.Esp = this->Esp;
_context.Eip = this->Eip;
_context.EFlags = this->EFlags;
#endif //_WIN64
return &_context;
}
return &_context;
}
void RegistersInfo::SetContext(const CONTEXT & context)
{
void RegistersInfo::SetContext(const CONTEXT & context)
{
#ifdef _WIN64
this->Rax = context.Rax;
this->Rbx = context.Rbx;
this->Rcx = context.Rcx;
this->Rdx = context.Rdx;
this->Rsi = context.Rsi;
this->Rdi = context.Rdi;
this->Rbp = context.Rbp;
this->Rsp = context.Rsp;
this->Rip = context.Rip;
this->R8 = context.R8;
this->R9 = context.R9;
this->R10 = context.R10;
this->R11 = context.R11;
this->R12 = context.R12;
this->R13 = context.R13;
this->R14 = context.R14;
this->R15 = context.R15;
this->EFlags = context.EFlags;
this->Rax = context.Rax;
this->Rbx = context.Rbx;
this->Rcx = context.Rcx;
this->Rdx = context.Rdx;
this->Rsi = context.Rsi;
this->Rdi = context.Rdi;
this->Rbp = context.Rbp;
this->Rsp = context.Rsp;
this->Rip = context.Rip;
this->R8 = context.R8;
this->R9 = context.R9;
this->R10 = context.R10;
this->R11 = context.R11;
this->R12 = context.R12;
this->R13 = context.R13;
this->R14 = context.R14;
this->R15 = context.R15;
this->EFlags = context.EFlags;
#else //x86
this->Eax = context.Eax;
this->Ebx = context.Ebx;
this->Ecx = context.Ecx;
this->Edx = context.Edx;
this->Esi = context.Esi;
this->Edi = context.Edi;
this->Ebp = context.Ebp;
this->Esp = context.Esp;
this->Eip = context.Eip;
this->EFlags = context.EFlags;
this->Eax = context.Eax;
this->Ebx = context.Ebx;
this->Ecx = context.Ecx;
this->Edx = context.Edx;
this->Esi = context.Esi;
this->Edi = context.Edi;
this->Ebp = context.Ebp;
this->Esp = context.Esp;
this->Eip = context.Eip;
this->EFlags = context.EFlags;
#endif //_WIN64
this->_context = context;
}
this->_context = context;
}
void RegistersInfo::SetTrapFlag(bool set)
{
if (set)
this->EFlags |= TRAP_FLAG;
else
this->EFlags &= ~TRAP_FLAG;
}
void RegistersInfo::SetTrapFlag(bool set)
{
if (set)
this->EFlags |= TRAP_FLAG;
else
this->EFlags &= ~TRAP_FLAG;
}
bool RegistersInfo::GetTrapFlag()
{
return (this->EFlags & TRAP_FLAG) == TRAP_FLAG;
}
bool RegistersInfo::GetTrapFlag()
{
return (this->EFlags & TRAP_FLAG) == TRAP_FLAG;
}
void RegistersInfo::SetResumeFlag(bool set)
{
if (set)
this->EFlags |= RESUME_FLAG;
else
this->EFlags &= ~RESUME_FLAG;
}
void RegistersInfo::SetResumeFlag(bool set)
{
if (set)
this->EFlags |= RESUME_FLAG;
else
this->EFlags &= ~RESUME_FLAG;
}
bool RegistersInfo::GetResumeFlag()
{
return (this->EFlags & RESUME_FLAG) == RESUME_FLAG;
}
bool RegistersInfo::GetResumeFlag()
{
return (this->EFlags & RESUME_FLAG) == RESUME_FLAG;
}
};

View File

@ -5,91 +5,91 @@
namespace GleeBug
{
CONTEXT;
/**
\brief Thread register context.
*/
class RegistersInfo
{
public:
CONTEXT;
/**
\brief Thread register context.
*/
class RegistersInfo
{
public:
#ifdef _WIN64
DWORD64 Rax;
DWORD64 Rbx;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 Rbp;
DWORD64 Rsp;
DWORD64 Rip;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
DWORD EFlags;
DWORD64 Rax;
DWORD64 Rbx;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 Rbp;
DWORD64 Rsp;
DWORD64 Rip;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
DWORD EFlags;
#else //x86
DWORD Eax;
DWORD Ebx;
DWORD Ecx;
DWORD Edx;
DWORD Esi;
DWORD Edi;
DWORD Ebp;
DWORD Esp;
DWORD Eip;
DWORD EFlags;
DWORD Eax;
DWORD Ebx;
DWORD Ecx;
DWORD Edx;
DWORD Esi;
DWORD Edi;
DWORD Ebp;
DWORD Esp;
DWORD Eip;
DWORD EFlags;
#endif //_WIN64
/**
\brief Default constructor.
*/
RegistersInfo();
/**
\brief Default constructor.
*/
RegistersInfo();
/**
\brief Gets a pointer to the context object.
\return This function will never return a nullptr.
*/
const CONTEXT* GetContext();
/**
\brief Gets a pointer to the context object.
\return This function will never return a nullptr.
*/
const CONTEXT* GetContext();
/**
\brief Sets the CONTEXT.
\param context The context to set.
*/
void SetContext(const CONTEXT & context);
/**
\brief Sets the CONTEXT.
\param context The context to set.
*/
void SetContext(const CONTEXT & context);
/**
\brief Sets trap flag.
\param set (Optional) true to set, false to unset.
*/
void SetTrapFlag(bool set = true);
/**
\brief Sets trap flag.
\param set (Optional) true to set, false to unset.
*/
void SetTrapFlag(bool set = true);
/**
\brief Gets trap flag.
\return true if the flag is set, false otherwise.
*/
bool GetTrapFlag();
/**
\brief Gets trap flag.
\return true if the flag is set, false otherwise.
*/
bool GetTrapFlag();
/**
\brief Sets resume flag.
\param set (Optional) true to set, false to unset.
*/
void SetResumeFlag(bool set = true);
/**
\brief Sets resume flag.
\param set (Optional) true to set, false to unset.
*/
void SetResumeFlag(bool set = true);
/**
\brief Gets resume flag.
\return true if the flag is set, false otherwise.
*/
bool GetResumeFlag();
/**
\brief Gets resume flag.
\return true if the flag is set, false otherwise.
*/
bool GetResumeFlag();
private:
CONTEXT _context;
const int TRAP_FLAG = 0x100;
const int RESUME_FLAG = 0x10000;
};
private:
CONTEXT _context;
const int TRAP_FLAG = 0x100;
const int RESUME_FLAG = 0x10000;
};
};
#endif //_DEBUGGER_THREAD_REGISTERS_H

View File

@ -2,55 +2,55 @@
namespace GleeBug
{
ThreadInfo::ThreadInfo()
{
this->hThread = INVALID_HANDLE_VALUE;
}
ThreadInfo::ThreadInfo()
{
this->hThread = INVALID_HANDLE_VALUE;
}
ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
{
this->dwThreadId = dwThreadId;
this->hThread = hThread;
this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase;
this->lpStartAddress = (ULONG_PTR)lpStartAddress;
}
ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
{
this->dwThreadId = dwThreadId;
this->hThread = hThread;
this->lpThreadLocalBase = reinterpret_cast<ULONG_PTR>(lpThreadLocalBase);
this->lpStartAddress = reinterpret_cast<ULONG_PTR>(lpStartAddress);
}
bool ThreadInfo::RegReadContext()
{
SuspendThread(this->hThread);
memset(&this->_oldContext, 0, sizeof(CONTEXT));
this->_oldContext.ContextFlags = CONTEXT_ALL;
bool bReturn = false;
if (GetThreadContext(this->hThread, &this->_oldContext))
{
this->registers.SetContext(this->_oldContext);
bReturn = true;
}
ResumeThread(this->hThread);
return bReturn;
}
bool ThreadInfo::RegReadContext()
{
SuspendThread(this->hThread);
memset(&this->_oldContext, 0, sizeof(CONTEXT));
this->_oldContext.ContextFlags = CONTEXT_ALL;
bool bReturn = false;
if (GetThreadContext(this->hThread, &this->_oldContext))
{
this->registers.SetContext(this->_oldContext);
bReturn = true;
}
ResumeThread(this->hThread);
return bReturn;
}
bool ThreadInfo::RegWriteContext()
{
//check if something actually changed
if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
return true;
//update the context
SuspendThread(this->hThread);
bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext());
ResumeThread(this->hThread);
return bReturn;
}
bool ThreadInfo::RegWriteContext()
{
//check if something actually changed
if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
return true;
//update the context
SuspendThread(this->hThread);
bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext());
ResumeThread(this->hThread);
return bReturn;
}
void ThreadInfo::StepInto(StepCallback cbStep)
{
StepInto();
stepCallbacks.push_back(cbStep);
}
void ThreadInfo::StepInto(const StepCallback & cbStep)
{
StepInto();
stepCallbacks.push_back(cbStep);
}
void ThreadInfo::StepInto()
{
registers.SetTrapFlag();
isSingleStepping = true;
}
void ThreadInfo::StepInto()
{
registers.SetTrapFlag();
isSingleStepping = true;
}
};

View File

@ -6,73 +6,73 @@
namespace GleeBug
{
/**
\brief Thread information structure.
*/
class ThreadInfo
{
public:
DWORD dwThreadId;
HANDLE hThread;
ULONG_PTR lpThreadLocalBase;
ULONG_PTR lpStartAddress;
/**
\brief Thread information structure.
*/
class ThreadInfo
{
public:
DWORD dwThreadId;
HANDLE hThread;
ULONG_PTR lpThreadLocalBase;
ULONG_PTR lpStartAddress;
RegistersInfo registers;
StepCallbackVector stepCallbacks;
bool isSingleStepping;
RegistersInfo registers;
StepCallbackVector stepCallbacks;
bool isSingleStepping;
/**
\brief Default constructor.
*/
ThreadInfo();
/**
\brief Default constructor.
*/
ThreadInfo();
/**
\brief Constructor.
\param dwThreadId Identifier for the thread.
\param lpThreadLocalBase The thread local base.
\param lpStartAddress The start address.
*/
ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
/**
\brief Constructor.
\param dwThreadId Identifier for the thread.
\param lpThreadLocalBase The thread local base.
\param lpStartAddress The start address.
*/
ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
/**
\brief Read the register context from the thread. This fills the RegistersInfo member.
\return true if it succeeds, false if it fails.
*/
bool RegReadContext();
/**
\brief Read the register context from the thread. This fills the RegistersInfo member.
\return true if it succeeds, false if it fails.
*/
bool RegReadContext();
/**
\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.
*/
bool RegWriteContext();
/**
\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.
*/
bool RegWriteContext();
/**
\brief Step into.
*/
void StepInto();
/**
\brief Step into.
*/
void StepInto();
/**
\brief Step into.
\param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb).
*/
void StepInto(StepCallback cbStep);
/**
\brief Step into.
\param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb).
*/
void StepInto(const StepCallback & cbStep);
/**
\brief Step into.
\tparam T Generic type parameter. Must be a subclass of Debugger.
\param debugger This pointer to a subclass of Debugger.
\param callback Pointer to the callback. Written like: &MyDebugger::cb
*/
template <typename T>
void StepInto(T* debugger, void(T::*callback)())
{
static_cast<void>(static_cast<Debugger *>(debugger));
StepInto(std::bind(callback, debugger));
}
/**
\brief Step into.
\tparam T Generic type parameter. Must be a subclass of Debugger.
\param debugger This pointer to a subclass of Debugger.
\param callback Pointer to the callback. Written like: &MyDebugger::cb
*/
template <typename T>
void StepInto(T* debugger, void(T::*callback)())
{
static_cast<void>(static_cast<Debugger *>(debugger));
StepInto(std::bind(callback, debugger));
}
private:
CONTEXT _oldContext;
};
private:
CONTEXT _oldContext;
};
};
#endif //_DEBUGGER_THREADS_H

View File

@ -2,51 +2,62 @@
namespace GleeBug
{
Debugger::Debugger()
{
_processes.clear();
}
Debugger::Debugger()
{
_processes.clear();
}
bool Debugger::Init(const wchar_t* szFilePath,
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;
}
Debugger::~Debugger()
{
}
return !!CreateProcessW(szFileNameCreateProcess,
szCommandLineCreateProcess,
NULL,
NULL,
FALSE,
DEBUG_PROCESS | CREATE_NEW_CONSOLE,
NULL,
szCurrentDirectory,
&si,
&_mainProcess);
}
bool Debugger::Init(const wchar_t* szFilePath,
const wchar_t* szCommandLine,
const wchar_t* szCurrentDirectory)
{
STARTUPINFOW si;
memset(&si, 0, sizeof(si));
const wchar_t* szFileNameCreateProcess;
wchar_t* szCommandLineCreateProcess = nullptr;
wchar_t* szCreateWithCmdLine = nullptr;
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()
{
return !!TerminateProcess(_mainProcess.hProcess, 0);
}
bool result = !!CreateProcessW(szFileNameCreateProcess,
szCommandLineCreateProcess,
nullptr,
nullptr,
FALSE,
DEBUG_PROCESS | CREATE_NEW_CONSOLE,
nullptr,
szCurrentDirectory,
&si,
&_mainProcess);
bool Debugger::Detach()
{
return !!DebugActiveProcessStop(_mainProcess.dwProcessId);
}
if (szCreateWithCmdLine)
delete[] szCreateWithCmdLine;
return result;
}
bool Debugger::Stop()
{
return !!TerminateProcess(_mainProcess.hProcess, 0);
}
bool Debugger::Detach()
{
return !!DebugActiveProcessStop(_mainProcess.dwProcessId);
}
};

View File

@ -6,212 +6,217 @@
namespace GleeBug
{
/**
\brief A debugger class.
*/
class Debugger
{
public: //public functionality
/**
\brief Constructs the Debugger instance.
*/
Debugger();
/**
\brief A debugger class.
*/
class Debugger
{
public: //public functionality
/**
\brief Constructs the Debugger instance.
*/
Debugger();
/**
\brief Start the debuggee.
\param szFilePath Full pathname of the file to debug.
\param szCommandLine The command line to pass to the debuggee.
\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 Destructs the Debugger instance.
*/
virtual ~Debugger();
/**
\brief Stops the debuggee (terminate the process)
\return true if the debuggee was stopped correctly, false otherwise.
*/
bool Stop();
/**
\brief Start the debuggee.
\param szFilePath Full pathname of the file to debug.
\param szCommandLine The command line to pass to the debuggee.
\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.
\return true if the debuggee was detached correctly, false otherwise.
*/
bool Detach();
/**
\brief Stops the debuggee (terminate the process)
\return true if the debuggee was stopped correctly, false otherwise.
*/
bool Stop();
/**
\brief Run the debug loop (does not return until the debuggee is detached or terminated).
*/
void Start();
/**
\brief Detaches the debuggee.
\return true if the debuggee was detached correctly, false otherwise.
*/
bool Detach();
protected: //debug event callbacks
/**
\brief Process creation debug event callback. Provide an implementation to use this callback.
\param createProcess Information about the process created.
*/
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) {};
/**
\brief Run the debug loop (does not return until the debuggee is detached or terminated).
*/
void Start();
/**
\brief Process termination debug event callback. Provide an implementation to use this callback.
\param exitProcess Information about the process terminated.
*/
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) {};
protected: //debug event callbacks
/**
\brief Process creation debug event callback. Provide an implementation to use this callback.
\param createProcess Information about the process created.
*/
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.
\param createThread Information about the thread created.
*/
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) {};
/**
\brief Process termination debug event callback. Provide an implementation to use this callback.
\param exitProcess Information about the process terminated.
*/
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.
\param exitThread Information about the thread terminated.
*/
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) {};
/**
\brief Thread creation debug event callback. Provide an implementation to use this callback.
\param createThread Information about the thread created.
*/
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.
\param loadDll Information about the DLL loaded.
*/
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) {};
/**
\brief Thread termination debug event callback. Provide an implementation to use this callback.
\param exitThread Information about the thread terminated.
*/
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.
\param unloadDll Information about the DLL unloaded.
*/
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) {};
/**
\brief DLL load debug event callback. Provide an implementation to use this callback.
\param loadDll Information about the DLL loaded.
*/
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) {};
/**
\brief Exception debug event callback. Provide an implementation to use this callback.
\param exceptionInfo Information about the exception.
*/
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) {};
/**
\brief DLL unload debug event callback. Provide an implementation to use this callback.
\param unloadDll Information about the DLL unloaded.
*/
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.
\param debugString Information about the debug string.
*/
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) {};
/**
\brief Exception debug event callback. Provide an implementation to use this callback.
\param exceptionInfo Information about the exception.
*/
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) {};
/**
\brief RIP debug event callback. Provide an implementation to use this callback.
\param rip Information about the RIP event.
*/
virtual void cbRipEvent(const RIP_INFO & rip) {};
/**
\brief Debug string debug event callback. Provide an implementation to use this callback.
\param debugString Information about the debug string.
*/
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) {};
protected: //other callbacks
/**
\brief Internal error callback. Provide an implementation to use this callback.
\param error The error message.
*/
virtual void cbInternalError(const std::string & error) {};
/**
\brief RIP debug event callback. Provide an implementation to use this callback.
\param rip Information about the RIP event.
*/
virtual void cbRipEvent(const RIP_INFO & rip) {};
/**
\brief Unhandled exception callback. Provide an implementation to use this callback.
\param exceptionRecord The exception record.
\param firstChance True if the exception is a first chance exception, false otherwise.
*/
virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) {};
protected: //other callbacks
/**
\brief Internal error callback. Provide an implementation to use this callback.
\param error The error message.
*/
virtual void cbInternalError(const std::string & error) {};
/**
\brief System breakpoint callback. Provide an implementation to use this callback.
*/
virtual void cbSystemBreakpoint() {};
/**
\brief Unhandled exception callback. Provide an implementation to use this callback.
\param exceptionRecord The exception record.
\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.
*/
virtual void cbStep() {};
/**
\brief System breakpoint callback. Provide an implementation to use this callback.
*/
virtual void cbSystemBreakpoint() {};
protected: //core debug event handlers
/**
\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 createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess);
/**
\brief Step callback. Provide an implementation to use this callback.
*/
virtual void cbStep() {};
/**
\brief Process termination debug event. Do not override this unless you know what you are doing!
\param exitProcess Information about the process terminated.
*/
virtual void exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess);
protected: //core debug event handlers
/**
\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 createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess);
/**
\brief Thread creation debug event. Do not override this unless you know what you are doing!
\param createThread Information about the thread created.
*/
virtual void createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread);
/**
\brief Process termination debug event. Do not override this unless you know what you are doing!
\param exitProcess Information about the process terminated.
*/
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!
\param exitThread Information about the thread terminated.
*/
virtual void exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread);
/**
\brief Thread creation debug event. Do not override this unless you know what you are doing!
\param createThread Information about the thread created.
*/
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!
\param loadDll Information about the DLL loaded.
*/
virtual void loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll);
/**
\brief Thread termination debug event. Do not override this unless you know what you are doing!
\param exitThread Information about the thread terminated.
*/
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!
\param unloadDll Information about the DLL unloaded.
*/
virtual void unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll);
/**
\brief DLL load debug event. Do not override this unless you know what you are doing!
\param loadDll Information about the DLL loaded.
*/
virtual void loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll);
/**
\brief Exception debug event. Do not override this unless you know what you are doing!
\param exceptionInfo Information about the exception.
*/
virtual void exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo);
/**
\brief DLL unload debug event. Do not override this unless you know what you are doing!
\param unloadDll Information about the DLL unloaded.
*/
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!
\param debugString Information about the debug string.
*/
virtual void debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString);
/**
\brief Exception debug event. Do not override this unless you know what you are doing!
\param exceptionInfo Information about the exception.
*/
virtual void exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo);
/**
\brief RIP debug event. Do not override this unless you know what you are doing!
\param rip Information about the RIP event.
*/
virtual void ripEvent(const RIP_INFO & rip);
/**
\brief Debug string debug event. Do not override this unless you know what you are doing!
\param debugString Information about the debug string.
*/
virtual void debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString);
protected: //core exception handlers
/**
\brief Breakpoint exception handler. Do not override this unless you know what you are doing!
\param exceptionRecord The exception record.
\param firstChance True if the exception is a first chance exception, false otherwise.
*/
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
/**
\brief RIP debug event. Do not override this unless you know what you are doing!
\param rip Information about the RIP event.
*/
virtual void ripEvent(const RIP_INFO & rip);
/**
\brief Single step exception handler. Do not override this unless you know what you are doing!
\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);
protected: //core exception handlers
/**
\brief Breakpoint exception handler. Do not override this unless you know what you are doing!
\param exceptionRecord The exception record.
\param firstChance True if the exception is a first chance exception, false otherwise.
*/
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
protected: //variables
PROCESS_INFORMATION _mainProcess;
DWORD _continueStatus;
bool _breakDebugger;
DEBUG_EVENT _debugEvent;
ProcessMap _processes;
bool _isRunning;
/**
\brief Single step exception handler. Do not override this unless you know what you are doing!
\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);
/**
\brief The current process (can be null in some cases).
*/
ProcessInfo* _process;
protected: //variables
PROCESS_INFORMATION _mainProcess;
DWORD _continueStatus;
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.
*/
ThreadInfo* _thread;
};
/**
\brief The current process (can be null in some cases).
*/
ProcessInfo* _process;
/**
\brief The current thread (can be null in some cases). Should be a copy of _process->thread.
*/
ThreadInfo* _thread;
};
};
#endif //_DEBUGGER_H

View File

@ -9,10 +9,6 @@
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</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>
<ClCompile Include="Debugger.cpp">

View File

@ -8,85 +8,89 @@ using namespace GleeBug;
class MyDebugger : public Debugger
{
protected:
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process)
{
printf("Process %d created with entry 0x%p\n",
_debugEvent.dwProcessId,
createProcess.lpStartAddress);
};
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) override
{
printf("Process %d created with entry 0x%p\n",
_debugEvent.dwProcessId,
createProcess.lpStartAddress);
}
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process)
{
printf("Process %d terminated with exit code 0x%08X\n",
_debugEvent.dwProcessId,
exitProcess.dwExitCode);
}
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override
{
printf("Process %u terminated with exit code 0x%08X\n",
_debugEvent.dwProcessId,
exitProcess.dwExitCode);
}
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread)
{
printf("Thread %d created with entry 0x%p\n",
_debugEvent.dwThreadId,
createThread.lpStartAddress);
};
void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) override
{
printf("Thread %u created with entry 0x%p\n",
_debugEvent.dwThreadId,
createThread.lpStartAddress);
}
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread)
{
printf("Thread %d terminated with exit code 0x%08X\n",
_debugEvent.dwThreadId,
exitThread.dwExitCode);
};
void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) override
{
printf("Thread %u terminated with exit code 0x%08X\n",
_debugEvent.dwThreadId,
exitThread.dwExitCode);
}
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll)
{
printf("DLL loaded at 0x%p\n",
loadDll.lpBaseOfDll);
};
void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) override
{
printf("DLL loaded at 0x%p\n",
loadDll.lpBaseOfDll);
}
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll)
{
printf("DLL 0x%p unloaded\n",
unloadDll.lpBaseOfDll);
};
void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) override
{
printf("DLL 0x%p unloaded\n",
unloadDll.lpBaseOfDll);
}
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{
printf("Exception with code 0x%08X at 0x%p\n",
exceptionInfo.ExceptionRecord.ExceptionCode,
exceptionInfo.ExceptionRecord.ExceptionAddress);
};
void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) override
{
printf("Exception with code 0x%08X at 0x%p\n",
exceptionInfo.ExceptionRecord.ExceptionCode,
exceptionInfo.ExceptionRecord.ExceptionAddress);
}
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
{
printf("Debug string at 0x%p with length %d\n",
debugString.lpDebugStringData,
debugString.nDebugStringLength);
};
void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
{
printf("Debug string at 0x%p with length %d\n",
debugString.lpDebugStringData,
debugString.nDebugStringLength);
}
virtual void cbRipEvent(const RIP_INFO & rip)
{
printf("RIP event type 0x%X, error 0x%X",
rip.dwType,
rip.dwError);
};
void cbRipEvent(const RIP_INFO & rip) override
{
printf("RIP event type 0x%X, error 0x%X",
rip.dwType,
rip.dwError);
}
void boobs()
{
printf("(.)Y(.) 0x%p\n",
_thread->registers.Rip);
}
void boobs()
{
printf("(.)Y(.) 0x%p\n",
#ifdef _WIN64
_thread->registers.Rip);
#else //x32
_thread->registers.Eip);
#endif //_WIN64
}
virtual void cbSystemBreakpoint()
{
printf("System breakpoint reached, CIP: 0x%p\n",
_thread->registers.Rip);
_thread->StepInto(BIND(this, MyDebugger::boobs));
}
void cbSystemBreakpoint() override
{
printf("System breakpoint reached, CIP: 0x%p\n",
_thread->registers.Rip);
_thread->StepInto(BIND(this, MyDebugger::boobs));
}
virtual void cbInternalError(const std::string & error)
{
printf("Internal Error: %s\n",
error.c_str());
}
void cbInternalError(const std::string & error) override
{
printf("Internal Error: %s\n",
error.c_str());
}
};
#endif //_MYDEBUGGER_H

View File

@ -4,23 +4,23 @@
int main()
{
#ifdef _WIN64
wchar_t szFilePath[256] = L"c:\\test64.exe";
wchar_t szFilePath[256] = L"c:\\test64.exe";
#else //x86
wchar_t szFilePath[256] = L"c:\\test32.exe";
wchar_t szFilePath[256] = L"c:\\test32.exe";
#endif //_WIN64
wchar_t szCommandLine[256] = L"";
wchar_t szCurrentDir[256] = L"c:\\";
MyDebugger dbg;
if (dbg.Init(szFilePath, szCommandLine, szCurrentDir))
{
puts("Debugger::Init success!");
dbg.Start();
puts("Debugger::Start finished!");
}
else
{
puts("Debugger::Init failed!");
}
system("pause");
return 0;
wchar_t szCommandLine[256] = L"";
wchar_t szCurrentDir[256] = L"c:\\";
MyDebugger dbg;
if (dbg.Init(szFilePath, szCommandLine, szCurrentDir))
{
puts("Debugger::Init success!");
dbg.Start();
puts("Debugger::Start finished!");
}
else
{
puts("Debugger::Init failed!");
}
system("pause");
return 0;
}